authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-10 12:04:27+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-07-10 12:04:27+02:00
log1a998886c863a1829d649f196093f1058cd9cf13
treedb1b3b0a043a113cfb6544e8103cb64f8e4e4d8f
parent5b4b033236a7bed19c90faf7fefbc1990911cfef
parent10d6db5d7d1fb62ee2915a7ad2c7feb771ea3bbb
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #24329 from ziglang/writergate

Deprecates all existing std.io readers and writers in favor of the newly provided std.io.Reader and std.io.Writer which are non-generic and have the buffer above the vtable - in other words the buffer is in the interface, not the implementation. This means that although Reader and Writer are no longer generic, they are still transparent to optimization; all of the interface functions have a concrete hot path operating on the buffer, and only make vtable calls when the buffer is full.

357 files changed, 16918 insertions(+), 15115 deletions(-)

CMakeLists.txt-1
......@@ -436,7 +436,6 @@ set(ZIG_STAGE2_SOURCES
436436 lib/std/elf.zig
437437 lib/std/fifo.zig
438438 lib/std/fmt.zig
439 lib/std/fmt/format_float.zig
440439 lib/std/fmt/parse_float.zig
441440 lib/std/fs.zig
442441 lib/std/fs/AtomicFile.zig
build.zig+3-3
......@@ -279,7 +279,7 @@ pub fn build(b: *std.Build) !void {
279279
280280 const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor);
281281 if (zig_version.order(ancestor_ver) != .gt) {
282 std.debug.print("Zig version '{}' must be greater than tagged ancestor '{}'\n", .{ zig_version, ancestor_ver });
282 std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver });
283283 std.process.exit(1);
284284 }
285285
......@@ -1449,7 +1449,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
14491449 }
14501450
14511451 var dir = b.build_root.handle.openDir("doc/langref", .{ .iterate = true }) catch |err| {
1452 std.debug.panic("unable to open '{}doc/langref' directory: {s}", .{
1452 std.debug.panic("unable to open '{f}doc/langref' directory: {s}", .{
14531453 b.build_root, @errorName(err),
14541454 });
14551455 };
......@@ -1470,7 +1470,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath {
14701470 // in a temporary directory
14711471 "--cache-root", b.cache_root.path orelse ".",
14721472 });
1473 cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) });
1473 cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) });
14741474 cmd.addArgs(&.{"-i"});
14751475 cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name})));
14761476
doc/langref.html.in+2-1
......@@ -374,7 +374,8 @@
374374 <p>
375375 Most of the time, it is more appropriate to write to stderr rather than stdout, and
376376 whether or not the message is successfully written to the stream is irrelevant.
377 For this common case, there is a simpler API:
377 Also, formatted printing often comes in handy. For this common case,
378 there is a simpler API:
378379 </p>
379380 {#code|hello_again.zig#}
380381
doc/langref/bad_default_value.zig+1-1
......@@ -17,7 +17,7 @@ pub fn main() !void {
1717 .maximum = 0.20,
1818 };
1919 const category = threshold.categorize(0.90);
20 try std.io.getStdOut().writeAll(@tagName(category));
20 try std.fs.File.stdout().writeAll(@tagName(category));
2121}
2222
2323const std = @import("std");
doc/langref/hello.zig+1-2
......@@ -1,8 +1,7 @@
11const std = @import("std");
22
33pub fn main() !void {
4 const stdout = std.io.getStdOut().writer();
5 try stdout.print("Hello, {s}!\n", .{"world"});
4 try std.fs.File.stdout().writeAll("Hello, World!\n");
65}
76
87// exe=succeed
doc/langref/hello_again.zig+1-1
......@@ -1,7 +1,7 @@
11const std = @import("std");
22
33pub fn main() void {
4 std.debug.print("Hello, world!\n", .{});
4 std.debug.print("Hello, {s}!\n", .{"World"});
55}
66
77// exe=succeed
lib/compiler/aro/aro/Compilation.zig+1-1
......@@ -1432,7 +1432,7 @@ fn getFileContents(comp: *Compilation, path: []const u8, limit: ?u32) ![]const u
14321432 defer buf.deinit();
14331433
14341434 const max = limit orelse std.math.maxInt(u32);
1435 file.reader().readAllArrayList(&buf, max) catch |e| switch (e) {
1435 file.deprecatedReader().readAllArrayList(&buf, max) catch |e| switch (e) {
14361436 error.StreamTooLong => if (limit == null) return e,
14371437 else => return e,
14381438 };
lib/compiler/aro/aro/Diagnostics.zig+19-29
......@@ -1,4 +1,5 @@
11const std = @import("std");
2const assert = std.debug.assert;
23const Allocator = mem.Allocator;
34const mem = std.mem;
45const Source = @import("Source.zig");
......@@ -323,12 +324,13 @@ pub fn addExtra(
323324
324325pub fn render(comp: *Compilation, config: std.io.tty.Config) void {
325326 if (comp.diagnostics.list.items.len == 0) return;
326 var m = defaultMsgWriter(config);
327 var buffer: [1000]u8 = undefined;
328 var m = defaultMsgWriter(config, &buffer);
327329 defer m.deinit();
328330 renderMessages(comp, &m);
329331}
330pub fn defaultMsgWriter(config: std.io.tty.Config) MsgWriter {
331 return MsgWriter.init(config);
332pub fn defaultMsgWriter(config: std.io.tty.Config, buffer: []u8) MsgWriter {
333 return MsgWriter.init(config, buffer);
332334}
333335
334336pub fn renderMessages(comp: *Compilation, m: anytype) void {
......@@ -443,18 +445,13 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void {
443445 printRt(m, prop.msg, .{"{s}"}, .{&str});
444446 } else {
445447 var buf: [3]u8 = undefined;
446 const str = std.fmt.bufPrint(&buf, "x{x}", .{std.fmt.fmtSliceHexLower(&.{msg.extra.invalid_escape.char})}) catch unreachable;
448 const str = std.fmt.bufPrint(&buf, "x{x}", .{msg.extra.invalid_escape.char}) catch unreachable;
447449 printRt(m, prop.msg, .{"{s}"}, .{str});
448450 }
449451 },
450452 .normalized => {
451453 const f = struct {
452 pub fn f(
453 bytes: []const u8,
454 comptime _: []const u8,
455 _: std.fmt.FormatOptions,
456 writer: anytype,
457 ) !void {
454 pub fn f(bytes: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void {
458455 var it: std.unicode.Utf8Iterator = .{
459456 .bytes = bytes,
460457 .i = 0,
......@@ -464,22 +461,16 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void {
464461 try writer.writeByte(@intCast(codepoint));
465462 } else if (codepoint < 0xFFFF) {
466463 try writer.writeAll("\\u");
467 try std.fmt.formatInt(codepoint, 16, .upper, .{
468 .fill = '0',
469 .width = 4,
470 }, writer);
464 try writer.printInt(codepoint, 16, .upper, .{ .fill = '0', .width = 4 });
471465 } else {
472466 try writer.writeAll("\\U");
473 try std.fmt.formatInt(codepoint, 16, .upper, .{
474 .fill = '0',
475 .width = 8,
476 }, writer);
467 try writer.printInt(codepoint, 16, .upper, .{ .fill = '0', .width = 8 });
477468 }
478469 }
479470 }
480471 }.f;
481 printRt(m, prop.msg, .{"{s}"}, .{
482 std.fmt.Formatter(f){ .data = msg.extra.normalized },
472 printRt(m, prop.msg, .{"{f}"}, .{
473 std.fmt.Formatter([]const u8, f){ .data = msg.extra.normalized },
483474 });
484475 },
485476 .none, .offset => m.write(prop.msg),
......@@ -535,32 +526,31 @@ fn tagKind(d: *Diagnostics, tag: Tag, langopts: LangOpts) Kind {
535526}
536527
537528const MsgWriter = struct {
538 w: std.io.BufferedWriter(4096, std.fs.File.Writer),
529 writer: *std.io.Writer,
539530 config: std.io.tty.Config,
540531
541 fn init(config: std.io.tty.Config) MsgWriter {
542 std.debug.lockStdErr();
532 fn init(config: std.io.tty.Config, buffer: []u8) MsgWriter {
543533 return .{
544 .w = std.io.bufferedWriter(std.io.getStdErr().writer()),
534 .writer = std.debug.lockStderrWriter(buffer),
545535 .config = config,
546536 };
547537 }
548538
549539 pub fn deinit(m: *MsgWriter) void {
550 m.w.flush() catch {};
551 std.debug.unlockStdErr();
540 std.debug.unlockStderrWriter();
541 m.* = undefined;
552542 }
553543
554544 pub fn print(m: *MsgWriter, comptime fmt: []const u8, args: anytype) void {
555 m.w.writer().print(fmt, args) catch {};
545 m.writer.print(fmt, args) catch {};
556546 }
557547
558548 fn write(m: *MsgWriter, msg: []const u8) void {
559 m.w.writer().writeAll(msg) catch {};
549 m.writer.writeAll(msg) catch {};
560550 }
561551
562552 fn setColor(m: *MsgWriter, color: std.io.tty.Color) void {
563 m.config.setColor(m.w.writer(), color) catch {};
553 m.config.setColor(m.writer, color) catch {};
564554 }
565555
566556 fn location(m: *MsgWriter, path: []const u8, line: u32, col: u32) void {
lib/compiler/aro/aro/Driver.zig+11-11
......@@ -519,7 +519,7 @@ fn option(arg: []const u8, name: []const u8) ?[]const u8 {
519519
520520fn addSource(d: *Driver, path: []const u8) !Source {
521521 if (mem.eql(u8, "-", path)) {
522 const stdin = std.io.getStdIn().reader();
522 const stdin = std.fs.File.stdin().deprecatedReader();
523523 const input = try stdin.readAllAlloc(d.comp.gpa, std.math.maxInt(u32));
524524 defer d.comp.gpa.free(input);
525525 return d.comp.addSourceFromBuffer("<stdin>", input);
......@@ -541,7 +541,7 @@ pub fn fatal(d: *Driver, comptime fmt: []const u8, args: anytype) error{ FatalEr
541541}
542542
543543pub fn renderErrors(d: *Driver) void {
544 Diagnostics.render(d.comp, d.detectConfig(std.io.getStdErr()));
544 Diagnostics.render(d.comp, d.detectConfig(std.fs.File.stderr()));
545545}
546546
547547pub fn detectConfig(d: *Driver, file: std.fs.File) std.io.tty.Config {
......@@ -591,7 +591,7 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_
591591 var macro_buf = std.ArrayList(u8).init(d.comp.gpa);
592592 defer macro_buf.deinit();
593593
594 const std_out = std.io.getStdOut().writer();
594 const std_out = std.fs.File.stdout().deprecatedWriter();
595595 if (try parseArgs(d, std_out, macro_buf.writer(), args)) return;
596596
597597 const linking = !(d.only_preprocess or d.only_syntax or d.only_compile or d.only_preprocess_and_compile);
......@@ -686,10 +686,10 @@ fn processSource(
686686 std.fs.cwd().createFile(some, .{}) catch |er|
687687 return d.fatal("unable to create output file '{s}': {s}", .{ some, errorDescription(er) })
688688 else
689 std.io.getStdOut();
689 std.fs.File.stdout();
690690 defer if (d.output_name != null) file.close();
691691
692 var buf_w = std.io.bufferedWriter(file.writer());
692 var buf_w = std.io.bufferedWriter(file.deprecatedWriter());
693693
694694 pp.prettyPrintTokens(buf_w.writer(), dump_mode) catch |er|
695695 return d.fatal("unable to write result: {s}", .{errorDescription(er)});
......@@ -704,8 +704,8 @@ fn processSource(
704704 defer tree.deinit();
705705
706706 if (d.verbose_ast) {
707 const stdout = std.io.getStdOut();
708 var buf_writer = std.io.bufferedWriter(stdout.writer());
707 const stdout = std.fs.File.stdout();
708 var buf_writer = std.io.bufferedWriter(stdout.deprecatedWriter());
709709 tree.dump(d.detectConfig(stdout), buf_writer.writer()) catch {};
710710 buf_writer.flush() catch {};
711711 }
......@@ -734,8 +734,8 @@ fn processSource(
734734 defer ir.deinit(d.comp.gpa);
735735
736736 if (d.verbose_ir) {
737 const stdout = std.io.getStdOut();
738 var buf_writer = std.io.bufferedWriter(stdout.writer());
737 const stdout = std.fs.File.stdout();
738 var buf_writer = std.io.bufferedWriter(stdout.deprecatedWriter());
739739 ir.dump(d.comp.gpa, d.detectConfig(stdout), buf_writer.writer()) catch {};
740740 buf_writer.flush() catch {};
741741 }
......@@ -806,10 +806,10 @@ fn processSource(
806806}
807807
808808fn dumpLinkerArgs(items: []const []const u8) !void {
809 const stdout = std.io.getStdOut().writer();
809 const stdout = std.fs.File.stdout().deprecatedWriter();
810810 for (items, 0..) |item, i| {
811811 if (i > 0) try stdout.writeByte(' ');
812 try stdout.print("\"{}\"", .{std.zig.fmtEscapes(item)});
812 try stdout.print("\"{f}\"", .{std.zig.fmtString(item)});
813813 }
814814 try stdout.writeByte('\n');
815815}
lib/compiler/aro/aro/Parser.zig+5-5
......@@ -500,8 +500,8 @@ fn checkDeprecatedUnavailable(p: *Parser, ty: Type, usage_tok: TokenIndex, decl_
500500
501501 const w = p.strings.writer();
502502 const msg_str = p.comp.interner.get(@"error".msg.ref()).bytes;
503 try w.print("call to '{s}' declared with attribute error: {}", .{
504 p.tokSlice(@"error".__name_tok), std.zig.fmtEscapes(msg_str),
503 try w.print("call to '{s}' declared with attribute error: {f}", .{
504 p.tokSlice(@"error".__name_tok), std.zig.fmtString(msg_str),
505505 });
506506 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
507507 try p.errStr(.error_attribute, usage_tok, str);
......@@ -512,8 +512,8 @@ fn checkDeprecatedUnavailable(p: *Parser, ty: Type, usage_tok: TokenIndex, decl_
512512
513513 const w = p.strings.writer();
514514 const msg_str = p.comp.interner.get(warning.msg.ref()).bytes;
515 try w.print("call to '{s}' declared with attribute warning: {}", .{
516 p.tokSlice(warning.__name_tok), std.zig.fmtEscapes(msg_str),
515 try w.print("call to '{s}' declared with attribute warning: {f}", .{
516 p.tokSlice(warning.__name_tok), std.zig.fmtString(msg_str),
517517 });
518518 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
519519 try p.errStr(.warning_attribute, usage_tok, str);
......@@ -542,7 +542,7 @@ fn errDeprecated(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex, msg: ?Valu
542542 try w.writeAll(reason);
543543 if (msg) |m| {
544544 const str = p.comp.interner.get(m.ref()).bytes;
545 try w.print(": {}", .{std.zig.fmtEscapes(str)});
545 try w.print(": {f}", .{std.zig.fmtString(str)});
546546 }
547547 const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]);
548548 return p.errStr(tag, tok_i, str);
lib/compiler/aro/aro/Preprocessor.zig+3-2
......@@ -811,7 +811,7 @@ fn verboseLog(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args:
811811 const source = pp.comp.getSource(raw.source);
812812 const line_col = source.lineCol(.{ .id = raw.source, .line = raw.line, .byte_offset = raw.start });
813813
814 const stderr = std.io.getStdErr().writer();
814 const stderr = std.fs.File.stderr().deprecatedWriter();
815815 var buf_writer = std.io.bufferedWriter(stderr);
816816 const writer = buf_writer.writer();
817817 defer buf_writer.flush() catch {};
......@@ -3262,7 +3262,8 @@ fn printLinemarker(
32623262 // containing the same bytes as the input regardless of encoding.
32633263 else => {
32643264 try w.writeAll("\\x");
3265 try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, w);
3265 // TODO try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' });
3266 try w.print("{x:0>2}", .{byte});
32663267 },
32673268 };
32683269 try w.writeByte('"');
lib/compiler/aro/aro/Value.zig+2-2
......@@ -961,7 +961,7 @@ pub fn print(v: Value, ty: Type, comp: *const Compilation, w: anytype) @TypeOf(w
961961 switch (key) {
962962 .null => return w.writeAll("nullptr_t"),
963963 .int => |repr| switch (repr) {
964 inline else => |x| return w.print("{d}", .{x}),
964 inline .u64, .i64, .big_int => |x| return w.print("{d}", .{x}),
965965 },
966966 .float => |repr| switch (repr) {
967967 .f16 => |x| return w.print("{d}", .{@round(@as(f64, @floatCast(x)) * 1000) / 1000}),
......@@ -982,7 +982,7 @@ pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: any
982982 const without_null = bytes[0 .. bytes.len - @intFromEnum(size)];
983983 try w.writeByte('"');
984984 switch (size) {
985 .@"1" => try w.print("{}", .{std.zig.fmtEscapes(without_null)}),
985 .@"1" => try w.print("{f}", .{std.zig.fmtString(without_null)}),
986986 .@"2" => {
987987 var items: [2]u16 = undefined;
988988 var i: usize = 0;
lib/compiler/aro/backend/Object/Elf.zig+1-1
......@@ -171,7 +171,7 @@ pub fn addRelocation(elf: *Elf, name: []const u8, section_kind: Object.Section,
171171/// strtab
172172/// section headers
173173pub fn finish(elf: *Elf, file: std.fs.File) !void {
174 var buf_writer = std.io.bufferedWriter(file.writer());
174 var buf_writer = std.io.bufferedWriter(file.deprecatedWriter());
175175 const w = buf_writer.writer();
176176
177177 var num_sections: std.elf.Elf64_Half = additional_sections;
lib/compiler/aro_translate_c.zig+3-2
......@@ -1781,7 +1781,8 @@ test "Macro matching" {
17811781fn renderErrorsAndExit(comp: *aro.Compilation) noreturn {
17821782 defer std.process.exit(1);
17831783
1784 var writer = aro.Diagnostics.defaultMsgWriter(std.io.tty.detectConfig(std.io.getStdErr()));
1784 var buffer: [1000]u8 = undefined;
1785 var writer = aro.Diagnostics.defaultMsgWriter(std.io.tty.detectConfig(std.fs.File.stderr()), &buffer);
17851786 defer writer.deinit(); // writer deinit must run *before* exit so that stderr is flushed
17861787
17871788 var saw_error = false;
......@@ -1824,6 +1825,6 @@ pub fn main() !void {
18241825 defer tree.deinit(gpa);
18251826
18261827 const formatted = try tree.render(arena);
1827 try std.io.getStdOut().writeAll(formatted);
1828 try std.fs.File.stdout().writeAll(formatted);
18281829 return std.process.cleanExit();
18291830}
lib/compiler/aro_translate_c/ast.zig+6-6
......@@ -849,7 +849,7 @@ const Context = struct {
849849 fn addIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex {
850850 if (std.zig.primitives.isPrimitive(bytes))
851851 return c.addTokenFmt(.identifier, "@\"{s}\"", .{bytes});
852 return c.addTokenFmt(.identifier, "{p}", .{std.zig.fmtId(bytes)});
852 return c.addTokenFmt(.identifier, "{f}", .{std.zig.fmtIdFlags(bytes, .{ .allow_primitive = true })});
853853 }
854854
855855 fn listToSpan(c: *Context, list: []const NodeIndex) Allocator.Error!NodeSubRange {
......@@ -1201,7 +1201,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
12011201
12021202 const compile_error_tok = try c.addToken(.builtin, "@compileError");
12031203 _ = try c.addToken(.l_paren, "(");
1204 const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(payload.mangled)});
1204 const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{f}\"", .{std.zig.fmtString(payload.mangled)});
12051205 const err_msg = try c.addNode(.{
12061206 .tag = .string_literal,
12071207 .main_token = err_msg_tok,
......@@ -2116,7 +2116,7 @@ fn renderRecord(c: *Context, node: Node) !NodeIndex {
21162116 defer c.gpa.free(members);
21172117
21182118 for (payload.fields, 0..) |field, i| {
2119 const name_tok = try c.addTokenFmt(.identifier, "{p}", .{std.zig.fmtId(field.name)});
2119 const name_tok = try c.addTokenFmt(.identifier, "{f}", .{std.zig.fmtIdFlags(field.name, .{ .allow_primitive = true })});
21202120 _ = try c.addToken(.colon, ":");
21212121 const type_expr = try renderNode(c, field.type);
21222122
......@@ -2205,7 +2205,7 @@ fn renderFieldAccess(c: *Context, lhs: NodeIndex, field_name: []const u8) !NodeI
22052205 .main_token = try c.addToken(.period, "."),
22062206 .data = .{ .node_and_token = .{
22072207 lhs,
2208 try c.addTokenFmt(.identifier, "{p}", .{std.zig.fmtId(field_name)}),
2208 try c.addTokenFmt(.identifier, "{f}", .{std.zig.fmtIdFlags(field_name, .{ .allow_primitive = true })}),
22092209 } },
22102210 });
22112211}
......@@ -2681,7 +2681,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {
26812681 _ = try c.addToken(.l_paren, "(");
26822682 const res = try c.addNode(.{
26832683 .tag = .string_literal,
2684 .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}),
2684 .main_token = try c.addTokenFmt(.string_literal, "\"{f}\"", .{std.zig.fmtString(some)}),
26852685 .data = undefined,
26862686 });
26872687 _ = try c.addToken(.r_paren, ")");
......@@ -2765,7 +2765,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
27652765 _ = try c.addToken(.l_paren, "(");
27662766 const res = try c.addNode(.{
27672767 .tag = .string_literal,
2768 .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}),
2768 .main_token = try c.addTokenFmt(.string_literal, "\"{f}\"", .{std.zig.fmtString(some)}),
27692769 .data = undefined,
27702770 });
27712771 _ = try c.addToken(.r_paren, ")");
lib/compiler/build_runner.zig+82-67
......@@ -12,6 +12,7 @@ const Watch = std.Build.Watch;
1212const Fuzz = std.Build.Fuzz;
1313const Allocator = std.mem.Allocator;
1414const fatal = std.process.fatal;
15const Writer = std.io.Writer;
1516const runner = @This();
1617
1718pub const root = @import("@build");
......@@ -330,7 +331,7 @@ pub fn main() !void {
330331 }
331332 }
332333
333 const stderr = std.io.getStdErr();
334 const stderr: std.fs.File = .stderr();
334335 const ttyconf = get_tty_conf(color, stderr);
335336 switch (ttyconf) {
336337 .no_color => try graph.env_map.put("NO_COLOR", "1"),
......@@ -365,7 +366,7 @@ pub fn main() !void {
365366 .data = buffer.items,
366367 .flags = .{ .exclusive = true },
367368 }) catch |err| {
368 fatal("unable to write configuration results to '{}{s}': {s}", .{
369 fatal("unable to write configuration results to '{f}{s}': {s}", .{
369370 local_cache_directory, tmp_sub_path, @errorName(err),
370371 });
371372 };
......@@ -378,13 +379,19 @@ pub fn main() !void {
378379
379380 validateSystemLibraryOptions(builder);
380381
381 const stdout_writer = io.getStdOut().writer();
382
383 if (help_menu)
384 return usage(builder, stdout_writer);
382 if (help_menu) {
383 var w = initStdoutWriter();
384 printUsage(builder, w) catch return stdout_writer_allocation.err.?;
385 w.flush() catch return stdout_writer_allocation.err.?;
386 return;
387 }
385388
386 if (steps_menu)
387 return steps(builder, stdout_writer);
389 if (steps_menu) {
390 var w = initStdoutWriter();
391 printSteps(builder, w) catch return stdout_writer_allocation.err.?;
392 w.flush() catch return stdout_writer_allocation.err.?;
393 return;
394 }
388395
389396 var run: Run = .{
390397 .max_rss = max_rss,
......@@ -696,24 +703,23 @@ fn runStepNames(
696703 const ttyconf = run.ttyconf;
697704
698705 if (run.summary != .none) {
699 std.debug.lockStdErr();
700 defer std.debug.unlockStdErr();
701 const stderr = run.stderr;
706 const w = std.debug.lockStderrWriter(&stdio_buffer_allocation);
707 defer std.debug.unlockStderrWriter();
702708
703709 const total_count = success_count + failure_count + pending_count + skipped_count;
704 ttyconf.setColor(stderr, .cyan) catch {};
705 stderr.writeAll("Build Summary:") catch {};
706 ttyconf.setColor(stderr, .reset) catch {};
707 stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
708 if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};
709 if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {};
710 ttyconf.setColor(w, .cyan) catch {};
711 w.writeAll("Build Summary:") catch {};
712 ttyconf.setColor(w, .reset) catch {};
713 w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
714 if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {};
715 if (failure_count > 0) w.print("; {d} failed", .{failure_count}) catch {};
710716
711 if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
712 if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {};
713 if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {};
714 if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {};
717 if (test_count > 0) w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
718 if (test_skip_count > 0) w.print("; {d} skipped", .{test_skip_count}) catch {};
719 if (test_fail_count > 0) w.print("; {d} failed", .{test_fail_count}) catch {};
720 if (test_leak_count > 0) w.print("; {d} leaked", .{test_leak_count}) catch {};
715721
716 stderr.writeAll("\n") catch {};
722 w.writeAll("\n") catch {};
717723
718724 // Print a fancy tree with build results.
719725 var step_stack_copy = try step_stack.clone(gpa);
......@@ -722,7 +728,7 @@ fn runStepNames(
722728 var print_node: PrintNode = .{ .parent = null };
723729 if (step_names.len == 0) {
724730 print_node.last = true;
725 printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {};
731 printTreeStep(b, b.default_step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
726732 } else {
727733 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
728734 var i: usize = step_names.len;
......@@ -741,9 +747,10 @@ fn runStepNames(
741747 for (step_names, 0..) |step_name, i| {
742748 const tls = b.top_level_steps.get(step_name).?;
743749 print_node.last = i + 1 == last_index;
744 printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {};
750 printTreeStep(b, &tls.step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
745751 }
746752 }
753 w.writeByte('\n') catch {};
747754 }
748755
749756 if (failure_count == 0) {
......@@ -775,7 +782,7 @@ const PrintNode = struct {
775782 last: bool = false,
776783};
777784
778fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void {
785fn printPrefix(node: *PrintNode, stderr: *Writer, ttyconf: std.io.tty.Config) !void {
779786 const parent = node.parent orelse return;
780787 if (parent.parent == null) return;
781788 try printPrefix(parent, stderr, ttyconf);
......@@ -789,7 +796,7 @@ fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void
789796 }
790797}
791798
792fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
799fn printChildNodePrefix(stderr: *Writer, ttyconf: std.io.tty.Config) !void {
793800 try stderr.writeAll(switch (ttyconf) {
794801 .no_color, .windows_api => "+- ",
795802 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
......@@ -798,7 +805,7 @@ fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
798805
799806fn printStepStatus(
800807 s: *Step,
801 stderr: File,
808 stderr: *Writer,
802809 ttyconf: std.io.tty.Config,
803810 run: *const Run,
804811) !void {
......@@ -820,10 +827,10 @@ fn printStepStatus(
820827 try stderr.writeAll(" cached");
821828 } else if (s.test_results.test_count > 0) {
822829 const pass_count = s.test_results.passCount();
823 try stderr.writer().print(" {d} passed", .{pass_count});
830 try stderr.print(" {d} passed", .{pass_count});
824831 if (s.test_results.skip_count > 0) {
825832 try ttyconf.setColor(stderr, .yellow);
826 try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count});
833 try stderr.print(" {d} skipped", .{s.test_results.skip_count});
827834 }
828835 } else {
829836 try stderr.writeAll(" success");
......@@ -832,15 +839,15 @@ fn printStepStatus(
832839 if (s.result_duration_ns) |ns| {
833840 try ttyconf.setColor(stderr, .dim);
834841 if (ns >= std.time.ns_per_min) {
835 try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min});
842 try stderr.print(" {d}m", .{ns / std.time.ns_per_min});
836843 } else if (ns >= std.time.ns_per_s) {
837 try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s});
844 try stderr.print(" {d}s", .{ns / std.time.ns_per_s});
838845 } else if (ns >= std.time.ns_per_ms) {
839 try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms});
846 try stderr.print(" {d}ms", .{ns / std.time.ns_per_ms});
840847 } else if (ns >= std.time.ns_per_us) {
841 try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us});
848 try stderr.print(" {d}us", .{ns / std.time.ns_per_us});
842849 } else {
843 try stderr.writer().print(" {d}ns", .{ns});
850 try stderr.print(" {d}ns", .{ns});
844851 }
845852 try ttyconf.setColor(stderr, .reset);
846853 }
......@@ -848,13 +855,13 @@ fn printStepStatus(
848855 const rss = s.result_peak_rss;
849856 try ttyconf.setColor(stderr, .dim);
850857 if (rss >= 1000_000_000) {
851 try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
858 try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
852859 } else if (rss >= 1000_000) {
853 try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000});
860 try stderr.print(" MaxRSS:{d}M", .{rss / 1000_000});
854861 } else if (rss >= 1000) {
855 try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000});
862 try stderr.print(" MaxRSS:{d}K", .{rss / 1000});
856863 } else {
857 try stderr.writer().print(" MaxRSS:{d}B", .{rss});
864 try stderr.print(" MaxRSS:{d}B", .{rss});
858865 }
859866 try ttyconf.setColor(stderr, .reset);
860867 }
......@@ -866,7 +873,7 @@ fn printStepStatus(
866873 if (skip == .skipped_oom) {
867874 try stderr.writeAll(" (not enough memory)");
868875 try ttyconf.setColor(stderr, .dim);
869 try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
876 try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
870877 try ttyconf.setColor(stderr, .yellow);
871878 }
872879 try stderr.writeAll("\n");
......@@ -878,23 +885,23 @@ fn printStepStatus(
878885
879886fn printStepFailure(
880887 s: *Step,
881 stderr: File,
888 stderr: *Writer,
882889 ttyconf: std.io.tty.Config,
883890) !void {
884891 if (s.result_error_bundle.errorMessageCount() > 0) {
885892 try ttyconf.setColor(stderr, .red);
886 try stderr.writer().print(" {d} errors\n", .{
893 try stderr.print(" {d} errors\n", .{
887894 s.result_error_bundle.errorMessageCount(),
888895 });
889896 try ttyconf.setColor(stderr, .reset);
890897 } else if (!s.test_results.isSuccess()) {
891 try stderr.writer().print(" {d}/{d} passed", .{
898 try stderr.print(" {d}/{d} passed", .{
892899 s.test_results.passCount(), s.test_results.test_count,
893900 });
894901 if (s.test_results.fail_count > 0) {
895902 try stderr.writeAll(", ");
896903 try ttyconf.setColor(stderr, .red);
897 try stderr.writer().print("{d} failed", .{
904 try stderr.print("{d} failed", .{
898905 s.test_results.fail_count,
899906 });
900907 try ttyconf.setColor(stderr, .reset);
......@@ -902,7 +909,7 @@ fn printStepFailure(
902909 if (s.test_results.skip_count > 0) {
903910 try stderr.writeAll(", ");
904911 try ttyconf.setColor(stderr, .yellow);
905 try stderr.writer().print("{d} skipped", .{
912 try stderr.print("{d} skipped", .{
906913 s.test_results.skip_count,
907914 });
908915 try ttyconf.setColor(stderr, .reset);
......@@ -910,7 +917,7 @@ fn printStepFailure(
910917 if (s.test_results.leak_count > 0) {
911918 try stderr.writeAll(", ");
912919 try ttyconf.setColor(stderr, .red);
913 try stderr.writer().print("{d} leaked", .{
920 try stderr.print("{d} leaked", .{
914921 s.test_results.leak_count,
915922 });
916923 try ttyconf.setColor(stderr, .reset);
......@@ -932,7 +939,7 @@ fn printTreeStep(
932939 b: *std.Build,
933940 s: *Step,
934941 run: *const Run,
935 stderr: File,
942 stderr: *Writer,
936943 ttyconf: std.io.tty.Config,
937944 parent_node: *PrintNode,
938945 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
......@@ -992,7 +999,7 @@ fn printTreeStep(
992999 if (s.dependencies.items.len == 0) {
9931000 try stderr.writeAll(" (reused)\n");
9941001 } else {
995 try stderr.writer().print(" (+{d} more reused dependencies)\n", .{
1002 try stderr.print(" (+{d} more reused dependencies)\n", .{
9961003 s.dependencies.items.len,
9971004 });
9981005 }
......@@ -1129,11 +1136,11 @@ fn workerMakeOneStep(
11291136 const show_stderr = s.result_stderr.len > 0;
11301137
11311138 if (show_error_msgs or show_compile_errors or show_stderr) {
1132 std.debug.lockStdErr();
1133 defer std.debug.unlockStdErr();
1139 const bw = std.debug.lockStderrWriter(&stdio_buffer_allocation);
1140 defer std.debug.unlockStderrWriter();
11341141
11351142 const gpa = b.allocator;
1136 printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, run.stderr, run.prominent_compile_errors) catch {};
1143 printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, bw, run.prominent_compile_errors) catch {};
11371144 }
11381145
11391146 handle_result: {
......@@ -1190,7 +1197,7 @@ pub fn printErrorMessages(
11901197 gpa: Allocator,
11911198 failing_step: *Step,
11921199 options: std.zig.ErrorBundle.RenderOptions,
1193 stderr: File,
1200 stderr: *Writer,
11941201 prominent_compile_errors: bool,
11951202) !void {
11961203 // Provide context for where these error messages are coming from by
......@@ -1209,7 +1216,7 @@ pub fn printErrorMessages(
12091216 var indent: usize = 0;
12101217 while (step_stack.pop()) |s| : (indent += 1) {
12111218 if (indent > 0) {
1212 try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3);
1219 try stderr.splatByteAll(' ', (indent - 1) * 3);
12131220 try printChildNodePrefix(stderr, ttyconf);
12141221 }
12151222
......@@ -1231,7 +1238,7 @@ pub fn printErrorMessages(
12311238 }
12321239
12331240 if (!prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) {
1234 try failing_step.result_error_bundle.renderToWriter(options, stderr.writer());
1241 try failing_step.result_error_bundle.renderToWriter(options, stderr);
12351242 }
12361243
12371244 for (failing_step.result_error_msgs.items) |msg| {
......@@ -1243,27 +1250,27 @@ pub fn printErrorMessages(
12431250 }
12441251}
12451252
1246fn steps(builder: *std.Build, out_stream: anytype) !void {
1253fn printSteps(builder: *std.Build, w: *Writer) !void {
12471254 const allocator = builder.allocator;
12481255 for (builder.top_level_steps.values()) |top_level_step| {
12491256 const name = if (&top_level_step.step == builder.default_step)
12501257 try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
12511258 else
12521259 top_level_step.step.name;
1253 try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
1260 try w.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
12541261 }
12551262}
12561263
1257fn usage(b: *std.Build, out_stream: anytype) !void {
1258 try out_stream.print(
1264fn printUsage(b: *std.Build, w: *Writer) !void {
1265 try w.print(
12591266 \\Usage: {s} build [steps] [options]
12601267 \\
12611268 \\Steps:
12621269 \\
12631270 , .{b.graph.zig_exe});
1264 try steps(b, out_stream);
1271 try printSteps(b, w);
12651272
1266 try out_stream.writeAll(
1273 try w.writeAll(
12671274 \\
12681275 \\General Options:
12691276 \\ -p, --prefix [path] Where to install files (default: zig-out)
......@@ -1319,25 +1326,25 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13191326
13201327 const arena = b.allocator;
13211328 if (b.available_options_list.items.len == 0) {
1322 try out_stream.print(" (none)\n", .{});
1329 try w.print(" (none)\n", .{});
13231330 } else {
13241331 for (b.available_options_list.items) |option| {
13251332 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
13261333 option.name,
13271334 @tagName(option.type_id),
13281335 });
1329 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
1336 try w.print("{s:<30} {s}\n", .{ name, option.description });
13301337 if (option.enum_options) |enum_options| {
13311338 const padding = " " ** 33;
1332 try out_stream.writeAll(padding ++ "Supported Values:\n");
1339 try w.writeAll(padding ++ "Supported Values:\n");
13331340 for (enum_options) |enum_option| {
1334 try out_stream.print(padding ++ " {s}\n", .{enum_option});
1341 try w.print(padding ++ " {s}\n", .{enum_option});
13351342 }
13361343 }
13371344 }
13381345 }
13391346
1340 try out_stream.writeAll(
1347 try w.writeAll(
13411348 \\
13421349 \\System Integration Options:
13431350 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
......@@ -1352,7 +1359,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13521359 \\
13531360 );
13541361 if (b.graph.system_library_options.entries.len == 0) {
1355 try out_stream.writeAll(" (none) -\n");
1362 try w.writeAll(" (none) -\n");
13561363 } else {
13571364 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
13581365 const status = switch (v) {
......@@ -1360,11 +1367,11 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
13601367 .declared_disabled => "no",
13611368 .user_enabled, .user_disabled => unreachable, // already emitted error
13621369 };
1363 try out_stream.print(" {s:<43} {s}\n", .{ k, status });
1370 try w.print(" {s:<43} {s}\n", .{ k, status });
13641371 }
13651372 }
13661373
1367 try out_stream.writeAll(
1374 try w.writeAll(
13681375 \\
13691376 \\Advanced Options:
13701377 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
......@@ -1544,3 +1551,11 @@ fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {
15441551 };
15451552 }
15461553}
1554
1555var stdio_buffer_allocation: [256]u8 = undefined;
1556var stdout_writer_allocation: std.fs.File.Writer = undefined;
1557
1558fn initStdoutWriter() *Writer {
1559 stdout_writer_allocation = std.fs.File.stdout().writerStreaming(&stdio_buffer_allocation);
1560 return &stdout_writer_allocation.interface;
1561}
lib/compiler/libc.zig+3-3
......@@ -40,7 +40,7 @@ pub fn main() !void {
4040 const arg = args[i];
4141 if (mem.startsWith(u8, arg, "-")) {
4242 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
43 const stdout = std.io.getStdOut().writer();
43 const stdout = std.fs.File.stdout().deprecatedWriter();
4444 try stdout.writeAll(usage_libc);
4545 return std.process.cleanExit();
4646 } else if (mem.eql(u8, arg, "-target")) {
......@@ -97,7 +97,7 @@ pub fn main() !void {
9797 fatal("no include dirs detected for target {s}", .{zig_target});
9898 }
9999
100 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
100 var bw = std.io.bufferedWriter(std.fs.File.stdout().deprecatedWriter());
101101 var writer = bw.writer();
102102 for (libc_dirs.libc_include_dir_list) |include_dir| {
103103 try writer.writeAll(include_dir);
......@@ -125,7 +125,7 @@ pub fn main() !void {
125125 };
126126 defer libc.deinit(gpa);
127127
128 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
128 var bw = std.io.bufferedWriter(std.fs.File.stdout().deprecatedWriter());
129129 try libc.render(bw.writer());
130130 try bw.flush();
131131 }
lib/compiler/objcopy.zig+6-6
......@@ -54,7 +54,7 @@ fn cmdObjCopy(
5454 fatal("unexpected positional argument: '{s}'", .{arg});
5555 }
5656 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
57 return std.io.getStdOut().writeAll(usage);
57 return std.fs.File.stdout().writeAll(usage);
5858 } else if (mem.eql(u8, arg, "-O") or mem.eql(u8, arg, "--output-target")) {
5959 i += 1;
6060 if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
......@@ -227,8 +227,8 @@ fn cmdObjCopy(
227227 if (listen) {
228228 var server = try Server.init(.{
229229 .gpa = gpa,
230 .in = std.io.getStdIn(),
231 .out = std.io.getStdOut(),
230 .in = .stdin(),
231 .out = .stdout(),
232232 .zig_version = builtin.zig_version_string,
233233 });
234234 defer server.deinit();
......@@ -635,11 +635,11 @@ const HexWriter = struct {
635635 const payload_bytes = self.getPayloadBytes();
636636 assert(payload_bytes.len <= MAX_PAYLOAD_LEN);
637637
638 const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3s}{4X:0>2}" ++ linesep, .{
638 const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3X}{4X:0>2}" ++ linesep, .{
639639 @as(u8, @intCast(payload_bytes.len)),
640640 self.address,
641641 @intFromEnum(self.payload),
642 std.fmt.fmtSliceHexUpper(payload_bytes),
642 payload_bytes,
643643 self.checksum(),
644644 });
645645 try file.writeAll(line);
......@@ -1495,7 +1495,7 @@ const ElfFileHelper = struct {
14951495 if (size < prefix.len) return null;
14961496
14971497 try in_file.seekTo(offset);
1498 var section_reader = std.io.limitedReader(in_file.reader(), size);
1498 var section_reader = std.io.limitedReader(in_file.deprecatedReader(), size);
14991499
15001500 // allocate as large as decompressed data. if the compression doesn't fit, keep the data uncompressed.
15011501 const compressed_data = try allocator.alignedAlloc(u8, .@"8", @intCast(size));
lib/compiler/reduce.zig+1-1
......@@ -68,7 +68,7 @@ pub fn main() !void {
6868 const arg = args[i];
6969 if (mem.startsWith(u8, arg, "-")) {
7070 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
71 const stdout = std.io.getStdOut().writer();
71 const stdout = std.fs.File.stdout().deprecatedWriter();
7272 try stdout.writeAll(usage);
7373 return std.process.cleanExit();
7474 } else if (mem.eql(u8, arg, "--")) {
lib/compiler/resinator/cli.zig+13-14
......@@ -125,13 +125,12 @@ pub const Diagnostics = struct {
125125 }
126126
127127 pub fn renderToStdErr(self: *Diagnostics, args: []const []const u8, config: std.io.tty.Config) void {
128 std.debug.lockStdErr();
129 defer std.debug.unlockStdErr();
130 const stderr = std.io.getStdErr().writer();
128 const stderr = std.debug.lockStderrWriter(&.{});
129 defer std.debug.unlockStderrWriter();
131130 self.renderToWriter(args, stderr, config) catch return;
132131 }
133132
134 pub fn renderToWriter(self: *Diagnostics, args: []const []const u8, writer: anytype, config: std.io.tty.Config) !void {
133 pub fn renderToWriter(self: *Diagnostics, args: []const []const u8, writer: *std.io.Writer, config: std.io.tty.Config) !void {
135134 for (self.errors.items) |err_details| {
136135 try renderErrorMessage(writer, config, err_details, args);
137136 }
......@@ -1403,7 +1402,7 @@ test parsePercent {
14031402 try std.testing.expectError(error.InvalidFormat, parsePercent("~1"));
14041403}
14051404
1406pub fn renderErrorMessage(writer: anytype, config: std.io.tty.Config, err_details: Diagnostics.ErrorDetails, args: []const []const u8) !void {
1405pub fn renderErrorMessage(writer: *std.io.Writer, config: std.io.tty.Config, err_details: Diagnostics.ErrorDetails, args: []const []const u8) !void {
14071406 try config.setColor(writer, .dim);
14081407 try writer.writeAll("<cli>");
14091408 try config.setColor(writer, .reset);
......@@ -1481,27 +1480,27 @@ pub fn renderErrorMessage(writer: anytype, config: std.io.tty.Config, err_detail
14811480 try writer.writeByte('\n');
14821481
14831482 try config.setColor(writer, .green);
1484 try writer.writeByteNTimes(' ', prefix.len);
1483 try writer.splatByteAll(' ', prefix.len);
14851484 // Special case for when the option is *only* a prefix (e.g. invalid option: -)
14861485 if (err_details.arg_span.prefix_len == arg_with_name.len) {
1487 try writer.writeByteNTimes('^', err_details.arg_span.prefix_len);
1486 try writer.splatByteAll('^', err_details.arg_span.prefix_len);
14881487 } else {
1489 try writer.writeByteNTimes('~', err_details.arg_span.prefix_len);
1490 try writer.writeByteNTimes(' ', err_details.arg_span.name_offset - err_details.arg_span.prefix_len);
1488 try writer.splatByteAll('~', err_details.arg_span.prefix_len);
1489 try writer.splatByteAll(' ', err_details.arg_span.name_offset - err_details.arg_span.prefix_len);
14911490 if (!err_details.arg_span.point_at_next_arg and err_details.arg_span.value_offset == 0) {
14921491 try writer.writeByte('^');
1493 try writer.writeByteNTimes('~', name_slice.len - 1);
1492 try writer.splatByteAll('~', name_slice.len - 1);
14941493 } else if (err_details.arg_span.value_offset > 0) {
1495 try writer.writeByteNTimes('~', err_details.arg_span.value_offset - err_details.arg_span.name_offset);
1494 try writer.splatByteAll('~', err_details.arg_span.value_offset - err_details.arg_span.name_offset);
14961495 try writer.writeByte('^');
14971496 if (err_details.arg_span.value_offset < arg_with_name.len) {
1498 try writer.writeByteNTimes('~', arg_with_name.len - err_details.arg_span.value_offset - 1);
1497 try writer.splatByteAll('~', arg_with_name.len - err_details.arg_span.value_offset - 1);
14991498 }
15001499 } else if (err_details.arg_span.point_at_next_arg) {
1501 try writer.writeByteNTimes('~', arg_with_name.len - err_details.arg_span.name_offset + 1);
1500 try writer.splatByteAll('~', arg_with_name.len - err_details.arg_span.name_offset + 1);
15021501 try writer.writeByte('^');
15031502 if (next_arg_len > 0) {
1504 try writer.writeByteNTimes('~', next_arg_len - 1);
1503 try writer.splatByteAll('~', next_arg_len - 1);
15051504 }
15061505 }
15071506 }
lib/compiler/resinator/compile.zig+11-11
......@@ -570,7 +570,7 @@ pub const Compiler = struct {
570570 switch (predefined_type) {
571571 .GROUP_ICON, .GROUP_CURSOR => {
572572 // Check for animated icon first
573 if (ani.isAnimatedIcon(file.reader())) {
573 if (ani.isAnimatedIcon(file.deprecatedReader())) {
574574 // Animated icons are just put into the resource unmodified,
575575 // and the resource type changes to ANIICON/ANICURSOR
576576
......@@ -586,14 +586,14 @@ pub const Compiler = struct {
586586
587587 try header.write(writer, self.errContext(node.id));
588588 try file.seekTo(0);
589 try writeResourceData(writer, file.reader(), header.data_size);
589 try writeResourceData(writer, file.deprecatedReader(), header.data_size);
590590 return;
591591 }
592592
593593 // isAnimatedIcon moved the file cursor so reset to the start
594594 try file.seekTo(0);
595595
596 const icon_dir = ico.read(self.allocator, file.reader(), try file.getEndPos()) catch |err| switch (err) {
596 const icon_dir = ico.read(self.allocator, file.deprecatedReader(), try file.getEndPos()) catch |err| switch (err) {
597597 error.OutOfMemory => |e| return e,
598598 else => |e| {
599599 return self.iconReadError(
......@@ -672,7 +672,7 @@ pub const Compiler = struct {
672672 }
673673
674674 try file.seekTo(entry.data_offset_from_start_of_file);
675 var header_bytes = file.reader().readBytesNoEof(16) catch {
675 var header_bytes = file.deprecatedReader().readBytesNoEof(16) catch {
676676 return self.iconReadError(
677677 error.UnexpectedEOF,
678678 filename_utf8,
......@@ -803,7 +803,7 @@ pub const Compiler = struct {
803803 }
804804
805805 try file.seekTo(entry.data_offset_from_start_of_file);
806 try writeResourceDataNoPadding(writer, file.reader(), entry.data_size_in_bytes);
806 try writeResourceDataNoPadding(writer, file.deprecatedReader(), entry.data_size_in_bytes);
807807 try writeDataPadding(writer, full_data_size);
808808
809809 if (self.state.icon_id == std.math.maxInt(u16)) {
......@@ -859,7 +859,7 @@ pub const Compiler = struct {
859859 header.applyMemoryFlags(node.common_resource_attributes, self.source);
860860 const file_size = try file.getEndPos();
861861
862 const bitmap_info = bmp.read(file.reader(), file_size) catch |err| {
862 const bitmap_info = bmp.read(file.deprecatedReader(), file_size) catch |err| {
863863 const filename_string_index = try self.diagnostics.putString(filename_utf8);
864864 return self.addErrorDetailsAndFail(.{
865865 .err = .bmp_read_error,
......@@ -922,7 +922,7 @@ pub const Compiler = struct {
922922 header.data_size = bmp_bytes_to_write;
923923 try header.write(writer, self.errContext(node.id));
924924 try file.seekTo(bmp.file_header_len);
925 const file_reader = file.reader();
925 const file_reader = file.deprecatedReader();
926926 try writeResourceDataNoPadding(writer, file_reader, bitmap_info.dib_header_size);
927927 if (bitmap_info.getBitmasksByteLen() > 0) {
928928 try writeResourceDataNoPadding(writer, file_reader, bitmap_info.getBitmasksByteLen());
......@@ -968,7 +968,7 @@ pub const Compiler = struct {
968968 header.data_size = @intCast(file_size);
969969 try header.write(writer, self.errContext(node.id));
970970
971 var header_slurping_reader = headerSlurpingReader(148, file.reader());
971 var header_slurping_reader = headerSlurpingReader(148, file.deprecatedReader());
972972 try writeResourceData(writer, header_slurping_reader.reader(), header.data_size);
973973
974974 try self.state.font_dir.add(self.arena, FontDir.Font{
......@@ -1002,7 +1002,7 @@ pub const Compiler = struct {
10021002 // We now know that the data size will fit in a u32
10031003 header.data_size = @intCast(data_size);
10041004 try header.write(writer, self.errContext(node.id));
1005 try writeResourceData(writer, file.reader(), header.data_size);
1005 try writeResourceData(writer, file.deprecatedReader(), header.data_size);
10061006 }
10071007
10081008 fn iconReadError(
......@@ -2949,7 +2949,7 @@ pub fn HeaderSlurpingReader(comptime size: usize, comptime ReaderType: anytype)
29492949 slurped_header: [size]u8 = [_]u8{0x00} ** size,
29502950
29512951 pub const Error = ReaderType.Error;
2952 pub const Reader = std.io.Reader(*@This(), Error, read);
2952 pub const Reader = std.io.GenericReader(*@This(), Error, read);
29532953
29542954 pub fn read(self: *@This(), buf: []u8) Error!usize {
29552955 const amt = try self.child_reader.read(buf);
......@@ -2983,7 +2983,7 @@ pub fn LimitedWriter(comptime WriterType: type) type {
29832983 bytes_left: u64,
29842984
29852985 pub const Error = error{NoSpaceLeft} || WriterType.Error;
2986 pub const Writer = std.io.Writer(*Self, Error, write);
2986 pub const Writer = std.io.GenericWriter(*Self, Error, write);
29872987
29882988 const Self = @This();
29892989
lib/compiler/resinator/errors.zig+29-33
......@@ -1,4 +1,5 @@
11const std = @import("std");
2const assert = std.debug.assert;
23const Token = @import("lex.zig").Token;
34const SourceMappings = @import("source_mapping.zig").SourceMappings;
45const utils = @import("utils.zig");
......@@ -61,16 +62,15 @@ pub const Diagnostics = struct {
6162 }
6263
6364 pub fn renderToStdErr(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, tty_config: std.io.tty.Config, source_mappings: ?SourceMappings) void {
64 std.debug.lockStdErr();
65 defer std.debug.unlockStdErr();
66 const stderr = std.io.getStdErr().writer();
65 const stderr = std.debug.lockStderrWriter(&.{});
66 defer std.debug.unlockStderrWriter();
6767 for (self.errors.items) |err_details| {
6868 renderErrorMessage(stderr, tty_config, cwd, err_details, source, self.strings.items, source_mappings) catch return;
6969 }
7070 }
7171
7272 pub fn renderToStdErrDetectTTY(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, source_mappings: ?SourceMappings) void {
73 const tty_config = std.io.tty.detectConfig(std.io.getStdErr());
73 const tty_config = std.io.tty.detectConfig(std.fs.File.stderr());
7474 return self.renderToStdErr(cwd, source, tty_config, source_mappings);
7575 }
7676
......@@ -409,15 +409,7 @@ pub const ErrorDetails = struct {
409409 failed_to_open_cwd,
410410 };
411411
412 fn formatToken(
413 ctx: TokenFormatContext,
414 comptime fmt: []const u8,
415 options: std.fmt.FormatOptions,
416 writer: anytype,
417 ) !void {
418 _ = fmt;
419 _ = options;
420
412 fn formatToken(ctx: TokenFormatContext, writer: *std.io.Writer) std.io.Writer.Error!void {
421413 switch (ctx.token.id) {
422414 .eof => return writer.writeAll(ctx.token.id.nameForErrorDisplay()),
423415 else => {},
......@@ -441,7 +433,7 @@ pub const ErrorDetails = struct {
441433 code_page: SupportedCodePage,
442434 };
443435
444 fn fmtToken(self: ErrorDetails, source: []const u8) std.fmt.Formatter(formatToken) {
436 fn fmtToken(self: ErrorDetails, source: []const u8) std.fmt.Formatter(TokenFormatContext, formatToken) {
445437 return .{ .data = .{
446438 .token = self.token,
447439 .code_page = self.code_page,
......@@ -452,7 +444,7 @@ pub const ErrorDetails = struct {
452444 pub fn render(self: ErrorDetails, writer: anytype, source: []const u8, strings: []const []const u8) !void {
453445 switch (self.err) {
454446 .unfinished_string_literal => {
455 return writer.print("unfinished string literal at '{s}', expected closing '\"'", .{self.fmtToken(source)});
447 return writer.print("unfinished string literal at '{f}', expected closing '\"'", .{self.fmtToken(source)});
456448 },
457449 .string_literal_too_long => {
458450 return writer.print("string literal too long (max is currently {} characters)", .{self.extra.number});
......@@ -466,10 +458,14 @@ pub const ErrorDetails = struct {
466458 .hint => return,
467459 },
468460 .illegal_byte => {
469 return writer.print("character '{s}' is not allowed", .{std.fmt.fmtSliceEscapeUpper(self.token.slice(source))});
461 return writer.print("character '{f}' is not allowed", .{
462 std.ascii.hexEscape(self.token.slice(source), .upper),
463 });
470464 },
471465 .illegal_byte_outside_string_literals => {
472 return writer.print("character '{s}' is not allowed outside of string literals", .{std.fmt.fmtSliceEscapeUpper(self.token.slice(source))});
466 return writer.print("character '{f}' is not allowed outside of string literals", .{
467 std.ascii.hexEscape(self.token.slice(source), .upper),
468 });
473469 },
474470 .illegal_codepoint_outside_string_literals => {
475471 // This is somewhat hacky, but we know that:
......@@ -527,26 +523,26 @@ pub const ErrorDetails = struct {
527523 return writer.print("unsupported code page '{s} (id={})' in #pragma code_page", .{ @tagName(code_page), number });
528524 },
529525 .unfinished_raw_data_block => {
530 return writer.print("unfinished raw data block at '{s}', expected closing '}}' or 'END'", .{self.fmtToken(source)});
526 return writer.print("unfinished raw data block at '{f}', expected closing '}}' or 'END'", .{self.fmtToken(source)});
531527 },
532528 .unfinished_string_table_block => {
533 return writer.print("unfinished STRINGTABLE block at '{s}', expected closing '}}' or 'END'", .{self.fmtToken(source)});
529 return writer.print("unfinished STRINGTABLE block at '{f}', expected closing '}}' or 'END'", .{self.fmtToken(source)});
534530 },
535531 .expected_token => {
536 return writer.print("expected '{s}', got '{s}'", .{ self.extra.expected.nameForErrorDisplay(), self.fmtToken(source) });
532 return writer.print("expected '{s}', got '{f}'", .{ self.extra.expected.nameForErrorDisplay(), self.fmtToken(source) });
537533 },
538534 .expected_something_else => {
539535 try writer.writeAll("expected ");
540536 try self.extra.expected_types.writeCommaSeparated(writer);
541 return writer.print("; got '{s}'", .{self.fmtToken(source)});
537 return writer.print("; got '{f}'", .{self.fmtToken(source)});
542538 },
543539 .resource_type_cant_use_raw_data => switch (self.type) {
544 .err, .warning => try writer.print("expected '<filename>', found '{s}' (resource type '{s}' can't use raw data)", .{ self.fmtToken(source), self.extra.resource.nameForErrorDisplay() }),
545 .note => try writer.print("if '{s}' is intended to be a filename, it must be specified as a quoted string literal", .{self.fmtToken(source)}),
540 .err, .warning => try writer.print("expected '<filename>', found '{f}' (resource type '{s}' can't use raw data)", .{ self.fmtToken(source), self.extra.resource.nameForErrorDisplay() }),
541 .note => try writer.print("if '{f}' is intended to be a filename, it must be specified as a quoted string literal", .{self.fmtToken(source)}),
546542 .hint => return,
547543 },
548544 .id_must_be_ordinal => {
549 try writer.print("id of resource type '{s}' must be an ordinal (u16), got '{s}'", .{ self.extra.resource.nameForErrorDisplay(), self.fmtToken(source) });
545 try writer.print("id of resource type '{s}' must be an ordinal (u16), got '{f}'", .{ self.extra.resource.nameForErrorDisplay(), self.fmtToken(source) });
550546 },
551547 .name_or_id_not_allowed => {
552548 try writer.print("name or id is not allowed for resource type '{s}'", .{self.extra.resource.nameForErrorDisplay()});
......@@ -562,7 +558,7 @@ pub const ErrorDetails = struct {
562558 try writer.writeAll("ASCII character not equivalent to virtual key code");
563559 },
564560 .empty_menu_not_allowed => {
565 try writer.print("empty menu of type '{s}' not allowed", .{self.fmtToken(source)});
561 try writer.print("empty menu of type '{f}' not allowed", .{self.fmtToken(source)});
566562 },
567563 .rc_would_miscompile_version_value_padding => switch (self.type) {
568564 .err, .warning => return writer.print("the padding before this quoted string value would be miscompiled by the Win32 RC compiler", .{}),
......@@ -627,7 +623,7 @@ pub const ErrorDetails = struct {
627623 .string_already_defined => switch (self.type) {
628624 .err, .warning => {
629625 const language = self.extra.string_and_language.language;
630 return writer.print("string with id {d} (0x{X}) already defined for language {}", .{ self.extra.string_and_language.id, self.extra.string_and_language.id, language });
626 return writer.print("string with id {d} (0x{X}) already defined for language {f}", .{ self.extra.string_and_language.id, self.extra.string_and_language.id, language });
631627 },
632628 .note => return writer.print("previous definition of string with id {d} (0x{X}) here", .{ self.extra.string_and_language.id, self.extra.string_and_language.id }),
633629 .hint => return,
......@@ -642,7 +638,7 @@ pub const ErrorDetails = struct {
642638 try writer.print("unable to open file '{s}': {s}", .{ strings[self.extra.file_open_error.filename_string_index], @tagName(self.extra.file_open_error.err) });
643639 },
644640 .invalid_accelerator_key => {
645 try writer.print("invalid accelerator key '{s}': {s}", .{ self.fmtToken(source), @tagName(self.extra.accelerator_error.err) });
641 try writer.print("invalid accelerator key '{f}': {s}", .{ self.fmtToken(source), @tagName(self.extra.accelerator_error.err) });
646642 },
647643 .accelerator_type_required => {
648644 try writer.writeAll("accelerator type [ASCII or VIRTKEY] required when key is an integer");
......@@ -898,7 +894,7 @@ fn cellCount(code_page: SupportedCodePage, source: []const u8, start_index: usiz
898894
899895const truncated_str = "<...truncated...>";
900896
901pub fn renderErrorMessage(writer: anytype, tty_config: std.io.tty.Config, cwd: std.fs.Dir, err_details: ErrorDetails, source: []const u8, strings: []const []const u8, source_mappings: ?SourceMappings) !void {
897pub fn renderErrorMessage(writer: *std.io.Writer, tty_config: std.io.tty.Config, cwd: std.fs.Dir, err_details: ErrorDetails, source: []const u8, strings: []const []const u8, source_mappings: ?SourceMappings) !void {
902898 if (err_details.type == .hint) return;
903899
904900 const source_line_start = err_details.token.getLineStartForErrorDisplay(source);
......@@ -981,10 +977,10 @@ pub fn renderErrorMessage(writer: anytype, tty_config: std.io.tty.Config, cwd: s
981977
982978 try tty_config.setColor(writer, .green);
983979 const num_spaces = truncated_visual_info.point_offset - truncated_visual_info.before_len;
984 try writer.writeByteNTimes(' ', num_spaces);
985 try writer.writeByteNTimes('~', truncated_visual_info.before_len);
980 try writer.splatByteAll(' ', num_spaces);
981 try writer.splatByteAll('~', truncated_visual_info.before_len);
986982 try writer.writeByte('^');
987 try writer.writeByteNTimes('~', truncated_visual_info.after_len);
983 try writer.splatByteAll('~', truncated_visual_info.after_len);
988984 try writer.writeByte('\n');
989985 try tty_config.setColor(writer, .reset);
990986
......@@ -1085,7 +1081,7 @@ const CorrespondingLines = struct {
10851081 buffered_reader: BufferedReaderType,
10861082 code_page: SupportedCodePage,
10871083
1088 const BufferedReaderType = std.io.BufferedReader(512, std.fs.File.Reader);
1084 const BufferedReaderType = std.io.BufferedReader(512, std.fs.File.DeprecatedReader);
10891085
10901086 pub fn init(cwd: std.fs.Dir, err_details: ErrorDetails, line_for_comparison: []const u8, corresponding_span: SourceMappings.CorrespondingSpan, corresponding_file: []const u8) !CorrespondingLines {
10911087 // We don't do line comparison for this error, so don't print the note if the line
......@@ -1106,7 +1102,7 @@ const CorrespondingLines = struct {
11061102 .code_page = err_details.code_page,
11071103 };
11081104 corresponding_lines.buffered_reader = BufferedReaderType{
1109 .unbuffered_reader = corresponding_lines.file.reader(),
1105 .unbuffered_reader = corresponding_lines.file.deprecatedReader(),
11101106 };
11111107 errdefer corresponding_lines.deinit();
11121108
lib/compiler/resinator/lex.zig+3-1
......@@ -237,7 +237,9 @@ pub const Lexer = struct {
237237 }
238238
239239 pub fn dump(self: *Self, token: *const Token) void {
240 std.debug.print("{s}:{d}: {s}\n", .{ @tagName(token.id), token.line_number, std.fmt.fmtSliceEscapeLower(token.slice(self.buffer)) });
240 std.debug.print("{s}:{d}: {f}\n", .{
241 @tagName(token.id), token.line_number, std.ascii.hexEscape(token.slice(self.buffer), .lower),
242 });
241243 }
242244
243245 pub const LexMethod = enum {
lib/compiler/resinator/main.zig+17-13
......@@ -22,14 +22,14 @@ pub fn main() !void {
2222 defer arena_state.deinit();
2323 const arena = arena_state.allocator();
2424
25 const stderr = std.io.getStdErr();
25 const stderr = std.fs.File.stderr();
2626 const stderr_config = std.io.tty.detectConfig(stderr);
2727
2828 const args = try std.process.argsAlloc(allocator);
2929 defer std.process.argsFree(allocator, args);
3030
3131 if (args.len < 2) {
32 try renderErrorMessage(stderr.writer(), stderr_config, .err, "expected zig lib dir as first argument", .{});
32 try renderErrorMessage(std.debug.lockStderrWriter(&.{}), stderr_config, .err, "expected zig lib dir as first argument", .{});
3333 std.process.exit(1);
3434 }
3535 const zig_lib_dir = args[1];
......@@ -44,7 +44,7 @@ pub fn main() !void {
4444 var error_handler: ErrorHandler = switch (zig_integration) {
4545 true => .{
4646 .server = .{
47 .out = std.io.getStdOut(),
47 .out = std.fs.File.stdout(),
4848 .in = undefined, // won't be receiving messages
4949 .receive_fifo = undefined, // won't be receiving messages
5050 },
......@@ -81,15 +81,15 @@ pub fn main() !void {
8181 defer options.deinit();
8282
8383 if (options.print_help_and_exit) {
84 const stdout = std.io.getStdOut();
85 try cli.writeUsage(stdout.writer(), "zig rc");
84 const stdout = std.fs.File.stdout();
85 try cli.writeUsage(stdout.deprecatedWriter(), "zig rc");
8686 return;
8787 }
8888
8989 // Don't allow verbose when integrating with Zig via stdout
9090 options.verbose = false;
9191
92 const stdout_writer = std.io.getStdOut().writer();
92 const stdout_writer = std.fs.File.stdout().deprecatedWriter();
9393 if (options.verbose) {
9494 try options.dumpVerbose(stdout_writer);
9595 try stdout_writer.writeByte('\n');
......@@ -290,7 +290,7 @@ pub fn main() !void {
290290 };
291291 defer depfile.close();
292292
293 const depfile_writer = depfile.writer();
293 const depfile_writer = depfile.deprecatedWriter();
294294 var depfile_buffered_writer = std.io.bufferedWriter(depfile_writer);
295295 switch (options.depfile_fmt) {
296296 .json => {
......@@ -343,7 +343,7 @@ pub fn main() !void {
343343 switch (err) {
344344 error.DuplicateResource => {
345345 const duplicate_resource = resources.list.items[cvtres_diagnostics.duplicate_resource];
346 try error_handler.emitMessage(allocator, .err, "duplicate resource [id: {}, type: {}, language: {}]", .{
346 try error_handler.emitMessage(allocator, .err, "duplicate resource [id: {f}, type: {f}, language: {f}]", .{
347347 duplicate_resource.name_value,
348348 fmtResourceType(duplicate_resource.type_value),
349349 duplicate_resource.language,
......@@ -352,7 +352,7 @@ pub fn main() !void {
352352 error.ResourceDataTooLong => {
353353 const overflow_resource = resources.list.items[cvtres_diagnostics.duplicate_resource];
354354 try error_handler.emitMessage(allocator, .err, "resource has a data length that is too large to be written into a coff section", .{});
355 try error_handler.emitMessage(allocator, .note, "the resource with the invalid size is [id: {}, type: {}, language: {}]", .{
355 try error_handler.emitMessage(allocator, .note, "the resource with the invalid size is [id: {f}, type: {f}, language: {f}]", .{
356356 overflow_resource.name_value,
357357 fmtResourceType(overflow_resource.type_value),
358358 overflow_resource.language,
......@@ -361,7 +361,7 @@ pub fn main() !void {
361361 error.TotalResourceDataTooLong => {
362362 const overflow_resource = resources.list.items[cvtres_diagnostics.duplicate_resource];
363363 try error_handler.emitMessage(allocator, .err, "total resource data exceeds the maximum of the coff 'size of raw data' field", .{});
364 try error_handler.emitMessage(allocator, .note, "size overflow occurred when attempting to write this resource: [id: {}, type: {}, language: {}]", .{
364 try error_handler.emitMessage(allocator, .note, "size overflow occurred when attempting to write this resource: [id: {f}, type: {f}, language: {f}]", .{
365365 overflow_resource.name_value,
366366 fmtResourceType(overflow_resource.type_value),
367367 overflow_resource.language,
......@@ -471,7 +471,7 @@ const IoStream = struct {
471471 allocator: std.mem.Allocator,
472472 };
473473 pub const WriteError = std.mem.Allocator.Error || std.fs.File.WriteError;
474 pub const Writer = std.io.Writer(WriterContext, WriteError, write);
474 pub const Writer = std.io.GenericWriter(WriterContext, WriteError, write);
475475
476476 pub fn write(ctx: WriterContext, bytes: []const u8) WriteError!usize {
477477 switch (ctx.self.*) {
......@@ -645,7 +645,9 @@ const ErrorHandler = union(enum) {
645645 },
646646 .tty => {
647647 // extra newline to separate this line from the aro errors
648 try renderErrorMessage(std.io.getStdErr().writer(), self.tty, .err, "{s}\n", .{fail_msg});
648 const stderr = std.debug.lockStderrWriter(&.{});
649 defer std.debug.unlockStderrWriter();
650 try renderErrorMessage(stderr, self.tty, .err, "{s}\n", .{fail_msg});
649651 aro.Diagnostics.render(comp, self.tty);
650652 },
651653 }
......@@ -690,7 +692,9 @@ const ErrorHandler = union(enum) {
690692 try server.serveErrorBundle(error_bundle);
691693 },
692694 .tty => {
693 try renderErrorMessage(std.io.getStdErr().writer(), self.tty, msg_type, format, args);
695 const stderr = std.debug.lockStderrWriter(&.{});
696 defer std.debug.unlockStderrWriter();
697 try renderErrorMessage(stderr, self.tty, msg_type, format, args);
694698 },
695699 }
696700 }
lib/compiler/resinator/res.zig+11-31
......@@ -1,4 +1,5 @@
11const std = @import("std");
2const assert = std.debug.assert;
23const rc = @import("rc.zig");
34const ResourceType = rc.ResourceType;
45const CommonResourceAttributes = rc.CommonResourceAttributes;
......@@ -163,14 +164,7 @@ pub const Language = packed struct(u16) {
163164 return @bitCast(self);
164165 }
165166
166 pub fn format(
167 language: Language,
168 comptime fmt: []const u8,
169 options: std.fmt.FormatOptions,
170 out_stream: anytype,
171 ) !void {
172 _ = fmt;
173 _ = options;
167 pub fn format(language: Language, w: *std.io.Writer) std.io.Writer.Error!void {
174168 const language_id = language.asInt();
175169 const language_name = language_name: {
176170 if (std.enums.fromInt(lang.LanguageId, language_id)) |lang_enum_val| {
......@@ -181,7 +175,7 @@ pub const Language = packed struct(u16) {
181175 }
182176 break :language_name "<UNKNOWN>";
183177 };
184 try out_stream.print("{s} (0x{X})", .{ language_name, language_id });
178 try w.print("{s} (0x{X})", .{ language_name, language_id });
185179 }
186180};
187181
......@@ -445,47 +439,33 @@ pub const NameOrOrdinal = union(enum) {
445439 }
446440 }
447441
448 pub fn format(
449 self: NameOrOrdinal,
450 comptime fmt: []const u8,
451 options: std.fmt.FormatOptions,
452 out_stream: anytype,
453 ) !void {
454 _ = fmt;
455 _ = options;
442 pub fn format(self: NameOrOrdinal, w: *std.io.Writer) !void {
456443 switch (self) {
457444 .name => |name| {
458 try out_stream.print("{s}", .{std.unicode.fmtUtf16Le(name)});
445 try w.print("{f}", .{std.unicode.fmtUtf16Le(name)});
459446 },
460447 .ordinal => |ordinal| {
461 try out_stream.print("{d}", .{ordinal});
448 try w.print("{d}", .{ordinal});
462449 },
463450 }
464451 }
465452
466 fn formatResourceType(
467 self: NameOrOrdinal,
468 comptime fmt: []const u8,
469 options: std.fmt.FormatOptions,
470 out_stream: anytype,
471 ) !void {
472 _ = fmt;
473 _ = options;
453 fn formatResourceType(self: NameOrOrdinal, w: *std.io.Writer) std.io.Writer.Error!void {
474454 switch (self) {
475455 .name => |name| {
476 try out_stream.print("{s}", .{std.unicode.fmtUtf16Le(name)});
456 try w.print("{f}", .{std.unicode.fmtUtf16Le(name)});
477457 },
478458 .ordinal => |ordinal| {
479459 if (std.enums.tagName(RT, @enumFromInt(ordinal))) |predefined_type_name| {
480 try out_stream.print("{s}", .{predefined_type_name});
460 try w.print("{s}", .{predefined_type_name});
481461 } else {
482 try out_stream.print("{d}", .{ordinal});
462 try w.print("{d}", .{ordinal});
483463 }
484464 },
485465 }
486466 }
487467
488 pub fn fmtResourceType(type_value: NameOrOrdinal) std.fmt.Formatter(formatResourceType) {
468 pub fn fmtResourceType(type_value: NameOrOrdinal) std.fmt.Formatter(NameOrOrdinal, formatResourceType) {
489469 return .{ .data = type_value };
490470 }
491471};
lib/compiler/resinator/utils.zig+1-1
......@@ -86,7 +86,7 @@ pub const ErrorMessageType = enum { err, warning, note };
8686
8787/// Used for generic colored errors/warnings/notes, more context-specific error messages
8888/// are handled elsewhere.
89pub fn renderErrorMessage(writer: anytype, config: std.io.tty.Config, msg_type: ErrorMessageType, comptime format: []const u8, args: anytype) !void {
89pub fn renderErrorMessage(writer: *std.io.Writer, config: std.io.tty.Config, msg_type: ErrorMessageType, comptime format: []const u8, args: anytype) !void {
9090 switch (msg_type) {
9191 .err => {
9292 try config.setColor(writer, .bold);
lib/compiler/std-docs.zig+2-2
......@@ -7,7 +7,7 @@ const assert = std.debug.assert;
77const Cache = std.Build.Cache;
88
99fn usage() noreturn {
10 io.getStdOut().writeAll(
10 std.fs.File.stdout().writeAll(
1111 \\Usage: zig std [options]
1212 \\
1313 \\Options:
......@@ -63,7 +63,7 @@ pub fn main() !void {
6363 var http_server = try address.listen(.{});
6464 const port = http_server.listen_address.in.getPort();
6565 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});
66 std.io.getStdOut().writeAll(url_with_newline) catch {};
66 std.fs.File.stdout().writeAll(url_with_newline) catch {};
6767 if (should_open_browser) {
6868 openBrowserTab(gpa, url_with_newline[0 .. url_with_newline.len - 1 :'\n']) catch |err| {
6969 std.log.err("unable to open browser: {s}", .{@errorName(err)});
lib/compiler/test_runner.zig+5-5
......@@ -69,8 +69,8 @@ fn mainServer() !void {
6969 @disableInstrumentation();
7070 var server = try std.zig.Server.init(.{
7171 .gpa = fba.allocator(),
72 .in = std.io.getStdIn(),
73 .out = std.io.getStdOut(),
72 .in = .stdin(),
73 .out = .stdout(),
7474 .zig_version = builtin.zig_version_string,
7575 });
7676 defer server.deinit();
......@@ -191,7 +191,7 @@ fn mainTerminal() void {
191191 .root_name = "Test",
192192 .estimated_total_items = test_fn_list.len,
193193 });
194 const have_tty = std.io.getStdErr().isTty();
194 const have_tty = std.fs.File.stderr().isTty();
195195
196196 var async_frame_buffer: []align(builtin.target.stackAlignment()) u8 = undefined;
197197 // TODO this is on the next line (using `undefined` above) because otherwise zig incorrectly
......@@ -301,7 +301,7 @@ pub fn mainSimple() anyerror!void {
301301 var failed: u64 = 0;
302302
303303 // we don't want to bring in File and Writer if the backend doesn't support it
304 const stderr = if (comptime enable_print) std.io.getStdErr() else {};
304 const stderr = if (comptime enable_print) std.fs.File.stderr() else {};
305305
306306 for (builtin.test_functions) |test_fn| {
307307 if (test_fn.func()) |_| {
......@@ -328,7 +328,7 @@ pub fn mainSimple() anyerror!void {
328328 passed += 1;
329329 }
330330 if (enable_print and print_summary) {
331 stderr.writer().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
331 stderr.deprecatedWriter().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
332332 }
333333 if (failed != 0) std.process.exit(1);
334334}
lib/docs/wasm/Walk.zig+1-1
......@@ -440,7 +440,7 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast {
440440 const err_loc = std.zig.findLineColumn(ast.source, err_offset);
441441 rendered_err.clearRetainingCapacity();
442442 try ast.renderError(err, rendered_err.writer(gpa));
443 log.err("{s}:{}:{}: {s}", .{ file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.items });
443 log.err("{s}:{d}:{d}: {s}", .{ file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.items });
444444 }
445445 return Ast.parse(gpa, "", .zig);
446446 }
lib/docs/wasm/main.zig+2-2
......@@ -717,9 +717,9 @@ fn render_docs(
717717 try writer.writeAll("<a href=\"#");
718718 _ = missing_feature_url_escape;
719719 try writer.writeAll(g.link_buffer.items);
720 try writer.print("\">{}</a>", .{markdown.fmtHtml(content)});
720 try writer.print("\">{f}</a>", .{markdown.fmtHtml(content)});
721721 } else {
722 try writer.print("{}", .{markdown.fmtHtml(content)});
722 try writer.print("{f}", .{markdown.fmtHtml(content)});
723723 }
724724
725725 try writer.writeAll("</code>");
lib/docs/wasm/markdown.zig+2-2
......@@ -145,7 +145,7 @@ fn mainImpl() !void {
145145 var parser = try Parser.init(gpa);
146146 defer parser.deinit();
147147
148 var stdin_buf = std.io.bufferedReader(std.io.getStdIn().reader());
148 var stdin_buf = std.io.bufferedReader(std.fs.File.stdin().deprecatedReader());
149149 var line_buf = std.ArrayList(u8).init(gpa);
150150 defer line_buf.deinit();
151151 while (stdin_buf.reader().streamUntilDelimiter(line_buf.writer(), '\n', null)) {
......@@ -160,7 +160,7 @@ fn mainImpl() !void {
160160 var doc = try parser.endInput();
161161 defer doc.deinit(gpa);
162162
163 var stdout_buf = std.io.bufferedWriter(std.io.getStdOut().writer());
163 var stdout_buf = std.io.bufferedWriter(std.fs.File.stdout().deprecatedWriter());
164164 try doc.render(stdout_buf.writer());
165165 try stdout_buf.flush();
166166}
lib/docs/wasm/markdown/renderer.zig+13-19
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const Document = @import("Document.zig");
33const Node = Document.Node;
4const assert = std.debug.assert;
45
56/// A Markdown document renderer.
67///
......@@ -41,7 +42,7 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
4142 if (start == 1) {
4243 try writer.writeAll("<ol>\n");
4344 } else {
44 try writer.print("<ol start=\"{}\">\n", .{start});
45 try writer.print("<ol start=\"{d}\">\n", .{start});
4546 }
4647 } else {
4748 try writer.writeAll("<ul>\n");
......@@ -105,15 +106,15 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
105106 }
106107 },
107108 .heading => {
108 try writer.print("<h{}>", .{data.heading.level});
109 try writer.print("<h{d}>", .{data.heading.level});
109110 for (doc.extraChildren(data.heading.children)) |child| {
110111 try r.renderFn(r, doc, child, writer);
111112 }
112 try writer.print("</h{}>\n", .{data.heading.level});
113 try writer.print("</h{d}>\n", .{data.heading.level});
113114 },
114115 .code_block => {
115116 const content = doc.string(data.code_block.content);
116 try writer.print("<pre><code>{}</code></pre>\n", .{fmtHtml(content)});
117 try writer.print("<pre><code>{f}</code></pre>\n", .{fmtHtml(content)});
117118 },
118119 .blockquote => {
119120 try writer.writeAll("<blockquote>\n");
......@@ -134,7 +135,7 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
134135 },
135136 .link => {
136137 const target = doc.string(data.link.target);
137 try writer.print("<a href=\"{}\">", .{fmtHtml(target)});
138 try writer.print("<a href=\"{f}\">", .{fmtHtml(target)});
138139 for (doc.extraChildren(data.link.children)) |child| {
139140 try r.renderFn(r, doc, child, writer);
140141 }
......@@ -142,11 +143,11 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
142143 },
143144 .autolink => {
144145 const target = doc.string(data.text.content);
145 try writer.print("<a href=\"{0}\">{0}</a>", .{fmtHtml(target)});
146 try writer.print("<a href=\"{0f}\">{0f}</a>", .{fmtHtml(target)});
146147 },
147148 .image => {
148149 const target = doc.string(data.link.target);
149 try writer.print("<img src=\"{}\" alt=\"", .{fmtHtml(target)});
150 try writer.print("<img src=\"{f}\" alt=\"", .{fmtHtml(target)});
150151 for (doc.extraChildren(data.link.children)) |child| {
151152 try renderInlineNodeText(doc, child, writer);
152153 }
......@@ -168,11 +169,11 @@ pub fn Renderer(comptime Writer: type, comptime Context: type) type {
168169 },
169170 .code_span => {
170171 const content = doc.string(data.text.content);
171 try writer.print("<code>{}</code>", .{fmtHtml(content)});
172 try writer.print("<code>{f}</code>", .{fmtHtml(content)});
172173 },
173174 .text => {
174175 const content = doc.string(data.text.content);
175 try writer.print("{}", .{fmtHtml(content)});
176 try writer.print("{f}", .{fmtHtml(content)});
176177 },
177178 .line_break => {
178179 try writer.writeAll("<br />\n");
......@@ -221,7 +222,7 @@ pub fn renderInlineNodeText(
221222 },
222223 .autolink, .code_span, .text => {
223224 const content = doc.string(data.text.content);
224 try writer.print("{}", .{fmtHtml(content)});
225 try writer.print("{f}", .{fmtHtml(content)});
225226 },
226227 .line_break => {
227228 try writer.writeAll("\n");
......@@ -229,18 +230,11 @@ pub fn renderInlineNodeText(
229230 }
230231}
231232
232pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter(formatHtml) {
233pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter([]const u8, formatHtml) {
233234 return .{ .data = bytes };
234235}
235236
236fn formatHtml(
237 bytes: []const u8,
238 comptime fmt: []const u8,
239 options: std.fmt.FormatOptions,
240 writer: anytype,
241) !void {
242 _ = fmt;
243 _ = options;
237fn formatHtml(bytes: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void {
244238 for (bytes) |b| {
245239 switch (b) {
246240 '<' => try writer.writeAll("&lt;"),
lib/fuzzer.zig+12-9
......@@ -9,7 +9,8 @@ pub const std_options = std.Options{
99 .logFn = logOverride,
1010};
1111
12var log_file: ?std.fs.File = null;
12var log_file_buffer: [256]u8 = undefined;
13var log_file_writer: ?std.fs.File.Writer = null;
1314
1415fn logOverride(
1516 comptime level: std.log.Level,
......@@ -17,15 +18,17 @@ fn logOverride(
1718 comptime format: []const u8,
1819 args: anytype,
1920) void {
20 const f = if (log_file) |f| f else f: {
21 const fw = if (log_file_writer) |*f| f else f: {
2122 const f = fuzzer.cache_dir.createFile("tmp/libfuzzer.log", .{}) catch
2223 @panic("failed to open fuzzer log file");
23 log_file = f;
24 break :f f;
24 log_file_writer = f.writer(&log_file_buffer);
25 break :f &log_file_writer.?;
2526 };
2627 const prefix1 = comptime level.asText();
2728 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
28 f.writer().print(prefix1 ++ prefix2 ++ format ++ "\n", args) catch @panic("failed to write to fuzzer log");
29 fw.interface.print(prefix1 ++ prefix2 ++ format ++ "\n", args) catch
30 @panic("failed to write to fuzzer log");
31 fw.interface.flush() catch @panic("failed to flush fuzzer log");
2932}
3033
3134/// Helps determine run uniqueness in the face of recursion.
......@@ -226,18 +229,18 @@ const Fuzzer = struct {
226229 .read = true,
227230 }) catch |e| switch (e) {
228231 error.PathAlreadyExists => continue,
229 else => fatal("unable to create '{}{d}: {s}", .{ f.corpus_directory, i, @errorName(err) }),
232 else => fatal("unable to create '{f}{d}: {s}", .{ f.corpus_directory, i, @errorName(err) }),
230233 };
231234 errdefer input_file.close();
232235 // Initialize the mmap for the current input.
233236 f.input = MemoryMappedList.create(input_file, 0, std.heap.page_size_max) catch |e| {
234 fatal("unable to init memory map for input at '{}{d}': {s}", .{
237 fatal("unable to init memory map for input at '{f}{d}': {s}", .{
235238 f.corpus_directory, i, @errorName(e),
236239 });
237240 };
238241 break;
239242 },
240 else => fatal("unable to read '{}{d}': {s}", .{ f.corpus_directory, i, @errorName(err) }),
243 else => fatal("unable to read '{f}{d}': {s}", .{ f.corpus_directory, i, @errorName(err) }),
241244 };
242245 errdefer gpa.free(input);
243246 f.corpus.append(gpa, .{
......@@ -263,7 +266,7 @@ const Fuzzer = struct {
263266 const sub_path = try std.fmt.allocPrint(gpa, "f/{s}", .{f.unit_test_name});
264267 f.corpus_directory = .{
265268 .handle = f.cache_dir.makeOpenPath(sub_path, .{}) catch |err|
266 fatal("unable to open corpus directory 'f/{s}': {s}", .{ sub_path, @errorName(err) }),
269 fatal("unable to open corpus directory 'f/{s}': {t}", .{ sub_path, err }),
267270 .path = sub_path,
268271 };
269272 initNextInput(f);
lib/init/src/root.zig+1-1
......@@ -5,7 +5,7 @@ pub fn bufferedPrint() !void {
55 // Stdout is for the actual output of your application, for example if you
66 // are implementing gzip, then only the compressed bytes should be sent to
77 // stdout, not any debugging messages.
8 const stdout_file = std.io.getStdOut().writer();
8 const stdout_file = std.fs.File.stdout().deprecatedWriter();
99 // Buffering can improve performance significantly in print-heavy programs.
1010 var bw = std.io.bufferedWriter(stdout_file);
1111 const stdout = bw.writer();
lib/std/Build.zig+33-43
......@@ -284,7 +284,7 @@ pub fn create(
284284 .h_dir = undefined,
285285 .dest_dir = graph.env_map.get("DESTDIR"),
286286 .install_tls = .{
287 .step = Step.init(.{
287 .step = .init(.{
288288 .id = TopLevelStep.base_id,
289289 .name = "install",
290290 .owner = b,
......@@ -292,7 +292,7 @@ pub fn create(
292292 .description = "Copy build artifacts to prefix path",
293293 },
294294 .uninstall_tls = .{
295 .step = Step.init(.{
295 .step = .init(.{
296296 .id = TopLevelStep.base_id,
297297 .name = "uninstall",
298298 .owner = b,
......@@ -342,7 +342,7 @@ fn createChildOnly(
342342 .graph = parent.graph,
343343 .allocator = allocator,
344344 .install_tls = .{
345 .step = Step.init(.{
345 .step = .init(.{
346346 .id = TopLevelStep.base_id,
347347 .name = "install",
348348 .owner = child,
......@@ -350,7 +350,7 @@ fn createChildOnly(
350350 .description = "Copy build artifacts to prefix path",
351351 },
352352 .uninstall_tls = .{
353 .step = Step.init(.{
353 .step = .init(.{
354354 .id = TopLevelStep.base_id,
355355 .name = "uninstall",
356356 .owner = child,
......@@ -1525,7 +1525,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
15251525pub fn step(b: *Build, name: []const u8, description: []const u8) *Step {
15261526 const step_info = b.allocator.create(TopLevelStep) catch @panic("OOM");
15271527 step_info.* = .{
1528 .step = Step.init(.{
1528 .step = .init(.{
15291529 .id = TopLevelStep.base_id,
15301530 .name = name,
15311531 .owner = b,
......@@ -1745,7 +1745,7 @@ pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8
17451745 return true;
17461746 },
17471747 .lazy_path, .lazy_path_list => {
1748 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)) });
1748 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)) });
17491749 return true;
17501750 },
17511751 }
......@@ -1824,13 +1824,13 @@ pub fn validateUserInputDidItFail(b: *Build) bool {
18241824 return b.invalid_user_input;
18251825}
18261826
1827fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 {
1828 var buf = ArrayList(u8).init(ally);
1829 if (opt_cwd) |cwd| try buf.writer().print("cd {s} && ", .{cwd});
1827fn allocPrintCmd(gpa: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 {
1828 var buf: std.ArrayListUnmanaged(u8) = .empty;
1829 if (opt_cwd) |cwd| try buf.print(gpa, "cd {s} && ", .{cwd});
18301830 for (argv) |arg| {
1831 try buf.writer().print("{s} ", .{arg});
1831 try buf.print(gpa, "{s} ", .{arg});
18321832 }
1833 return buf.toOwnedSlice();
1833 return buf.toOwnedSlice(gpa);
18341834}
18351835
18361836fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void {
......@@ -2059,7 +2059,7 @@ pub fn runAllowFail(
20592059 try Step.handleVerbose2(b, null, child.env_map, argv);
20602060 try child.spawn();
20612061
2062 const stdout = child.stdout.?.reader().readAllAlloc(b.allocator, max_output_size) catch {
2062 const stdout = child.stdout.?.deprecatedReader().readAllAlloc(b.allocator, max_output_size) catch {
20632063 return error.ReadFailure;
20642064 };
20652065 errdefer b.allocator.free(stdout);
......@@ -2466,10 +2466,9 @@ pub const GeneratedFile = struct {
24662466
24672467 pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 {
24682468 return gen.path orelse {
2469 std.debug.lockStdErr();
2470 const stderr = std.io.getStdErr();
2471 dumpBadGetPathHelp(gen.step, stderr, src_builder, asking_step) catch {};
2472 std.debug.unlockStdErr();
2469 const w = debug.lockStderrWriter(&.{});
2470 dumpBadGetPathHelp(gen.step, w, .detect(.stderr()), src_builder, asking_step) catch {};
2471 debug.unlockStderrWriter();
24732472 @panic("misconfigured build script");
24742473 };
24752474 }
......@@ -2676,10 +2675,9 @@ pub const LazyPath = union(enum) {
26762675 var file_path: Cache.Path = .{
26772676 .root_dir = Cache.Directory.cwd(),
26782677 .sub_path = gen.file.path orelse {
2679 std.debug.lockStdErr();
2680 const stderr = std.io.getStdErr();
2681 dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {};
2682 std.debug.unlockStdErr();
2678 const w = debug.lockStderrWriter(&.{});
2679 dumpBadGetPathHelp(gen.file.step, w, .detect(.stderr()), src_builder, asking_step) catch {};
2680 debug.unlockStderrWriter();
26832681 @panic("misconfigured build script");
26842682 },
26852683 };
......@@ -2766,44 +2764,42 @@ fn dumpBadDirnameHelp(
27662764 comptime msg: []const u8,
27672765 args: anytype,
27682766) anyerror!void {
2769 debug.lockStdErr();
2770 defer debug.unlockStdErr();
2767 const w = debug.lockStderrWriter(&.{});
2768 defer debug.unlockStderrWriter();
27712769
2772 const stderr = io.getStdErr();
2773 const w = stderr.writer();
27742770 try w.print(msg, args);
27752771
2776 const tty_config = std.io.tty.detectConfig(stderr);
2772 const tty_config = std.io.tty.detectConfig(.stderr());
27772773
27782774 if (fail_step) |s| {
27792775 tty_config.setColor(w, .red) catch {};
2780 try stderr.writeAll(" The step was created by this stack trace:\n");
2776 try w.writeAll(" The step was created by this stack trace:\n");
27812777 tty_config.setColor(w, .reset) catch {};
27822778
2783 s.dump(stderr);
2779 s.dump(w, tty_config);
27842780 }
27852781
27862782 if (asking_step) |as| {
27872783 tty_config.setColor(w, .red) catch {};
2788 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});
2784 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
27892785 tty_config.setColor(w, .reset) catch {};
27902786
2791 as.dump(stderr);
2787 as.dump(w, tty_config);
27922788 }
27932789
27942790 tty_config.setColor(w, .red) catch {};
2795 try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
2791 try w.writeAll(" Hope that helps. Proceeding to panic.\n");
27962792 tty_config.setColor(w, .reset) catch {};
27972793}
27982794
27992795/// In this function the stderr mutex has already been locked.
28002796pub fn dumpBadGetPathHelp(
28012797 s: *Step,
2802 stderr: fs.File,
2798 w: *std.io.Writer,
2799 tty_config: std.io.tty.Config,
28032800 src_builder: *Build,
28042801 asking_step: ?*Step,
28052802) anyerror!void {
2806 const w = stderr.writer();
28072803 try w.print(
28082804 \\getPath() was called on a GeneratedFile that wasn't built yet.
28092805 \\ source package path: {s}
......@@ -2814,21 +2810,20 @@ pub fn dumpBadGetPathHelp(
28142810 s.name,
28152811 });
28162812
2817 const tty_config = std.io.tty.detectConfig(stderr);
28182813 tty_config.setColor(w, .red) catch {};
2819 try stderr.writeAll(" The step was created by this stack trace:\n");
2814 try w.writeAll(" The step was created by this stack trace:\n");
28202815 tty_config.setColor(w, .reset) catch {};
28212816
2822 s.dump(stderr);
2817 s.dump(w, tty_config);
28232818 if (asking_step) |as| {
28242819 tty_config.setColor(w, .red) catch {};
2825 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});
2820 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
28262821 tty_config.setColor(w, .reset) catch {};
28272822
2828 as.dump(stderr);
2823 as.dump(w, tty_config);
28292824 }
28302825 tty_config.setColor(w, .red) catch {};
2831 try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
2826 try w.writeAll(" Hope that helps. Proceeding to panic.\n");
28322827 tty_config.setColor(w, .reset) catch {};
28332828}
28342829
......@@ -2866,11 +2861,6 @@ pub fn makeTempPath(b: *Build) []const u8 {
28662861 return result_path;
28672862}
28682863
2869/// Deprecated; use `std.fmt.hex` instead.
2870pub fn hex64(x: u64) [16]u8 {
2871 return std.fmt.hex(x);
2872}
2873
28742864/// A pair of target query and fully resolved target.
28752865/// This type is generally required by build system API that need to be given a
28762866/// target. The query is kept because the Zig toolchain needs to know which parts
lib/std/Build/Cache.zig+55-61
......@@ -2,6 +2,18 @@
22//! This is not a general-purpose cache. It is designed to be fast and simple,
33//! not to withstand attacks using specially-crafted input.
44
5const Cache = @This();
6const std = @import("std");
7const builtin = @import("builtin");
8const crypto = std.crypto;
9const fs = std.fs;
10const assert = std.debug.assert;
11const testing = std.testing;
12const mem = std.mem;
13const fmt = std.fmt;
14const Allocator = std.mem.Allocator;
15const log = std.log.scoped(.cache);
16
517gpa: Allocator,
618manifest_dir: fs.Dir,
719hash: HashHelper = .{},
......@@ -21,18 +33,6 @@ pub const Path = @import("Cache/Path.zig");
2133pub const Directory = @import("Cache/Directory.zig");
2234pub const DepTokenizer = @import("Cache/DepTokenizer.zig");
2335
24const Cache = @This();
25const std = @import("std");
26const builtin = @import("builtin");
27const crypto = std.crypto;
28const fs = std.fs;
29const assert = std.debug.assert;
30const testing = std.testing;
31const mem = std.mem;
32const fmt = std.fmt;
33const Allocator = std.mem.Allocator;
34const log = std.log.scoped(.cache);
35
3636pub fn addPrefix(cache: *Cache, directory: Directory) void {
3737 cache.prefixes_buffer[cache.prefixes_len] = directory;
3838 cache.prefixes_len += 1;
......@@ -68,7 +68,7 @@ const PrefixedPath = struct {
6868
6969fn findPrefix(cache: *const Cache, file_path: []const u8) !PrefixedPath {
7070 const gpa = cache.gpa;
71 const resolved_path = try fs.path.resolve(gpa, &[_][]const u8{file_path});
71 const resolved_path = try fs.path.resolve(gpa, &.{file_path});
7272 errdefer gpa.free(resolved_path);
7373 return findPrefixResolved(cache, resolved_path);
7474}
......@@ -132,7 +132,7 @@ pub const Hasher = crypto.auth.siphash.SipHash128(1, 3);
132132/// Initial state with random bytes, that can be copied.
133133/// Refresh this with new random bytes when the manifest
134134/// format is modified in a non-backwards-compatible way.
135pub const hasher_init: Hasher = Hasher.init(&[_]u8{
135pub const hasher_init: Hasher = Hasher.init(&.{
136136 0x33, 0x52, 0xa2, 0x84,
137137 0xcf, 0x17, 0x56, 0x57,
138138 0x01, 0xbb, 0xcd, 0xe4,
......@@ -286,11 +286,8 @@ pub const HashHelper = struct {
286286
287287pub fn binToHex(bin_digest: BinDigest) HexDigest {
288288 var out_digest: HexDigest = undefined;
289 _ = fmt.bufPrint(
290 &out_digest,
291 "{s}",
292 .{fmt.fmtSliceHexLower(&bin_digest)},
293 ) catch unreachable;
289 var w: std.io.Writer = .fixed(&out_digest);
290 w.printHex(&bin_digest, .lower) catch unreachable;
294291 return out_digest;
295292}
296293
......@@ -337,7 +334,6 @@ pub const Manifest = struct {
337334 manifest_create: fs.File.OpenError,
338335 manifest_read: fs.File.ReadError,
339336 manifest_lock: fs.File.LockError,
340 manifest_seek: fs.File.SeekError,
341337 file_open: FileOp,
342338 file_stat: FileOp,
343339 file_read: FileOp,
......@@ -611,12 +607,6 @@ pub const Manifest = struct {
611607 var file = self.files.pop().?;
612608 file.key.deinit(self.cache.gpa);
613609 }
614 // Also, seek the file back to the start.
615 self.manifest_file.?.seekTo(0) catch |err| {
616 self.diagnostic = .{ .manifest_seek = err };
617 return error.CacheCheckFailed;
618 };
619
620610 switch (try self.hitWithCurrentLock()) {
621611 .hit => break :hit,
622612 .miss => |m| break :digests m.file_digests_populated,
......@@ -661,9 +651,8 @@ pub const Manifest = struct {
661651 return true;
662652 }
663653
664 /// Assumes that `self.hash.hasher` has been updated only with the original digest, that
665 /// `self.files` contains only the original input files, and that `self.manifest_file.?` is
666 /// seeked to the start of the file.
654 /// Assumes that `self.hash.hasher` has been updated only with the original digest and that
655 /// `self.files` contains only the original input files.
667656 fn hitWithCurrentLock(self: *Manifest) HitError!union(enum) {
668657 hit,
669658 miss: struct {
......@@ -672,12 +661,13 @@ pub const Manifest = struct {
672661 } {
673662 const gpa = self.cache.gpa;
674663 const input_file_count = self.files.entries.len;
675
676 const file_contents = self.manifest_file.?.reader().readAllAlloc(gpa, manifest_file_size_max) catch |err| switch (err) {
664 var manifest_reader = self.manifest_file.?.reader(&.{}); // Reads positionally from zero.
665 const limit: std.io.Limit = .limited(manifest_file_size_max);
666 const file_contents = manifest_reader.interface.allocRemaining(gpa, limit) catch |err| switch (err) {
677667 error.OutOfMemory => return error.OutOfMemory,
678668 error.StreamTooLong => return error.OutOfMemory,
679 else => |e| {
680 self.diagnostic = .{ .manifest_read = e };
669 error.ReadFailed => {
670 self.diagnostic = .{ .manifest_read = manifest_reader.err.? };
681671 return error.CacheCheckFailed;
682672 },
683673 };
......@@ -1063,14 +1053,17 @@ pub const Manifest = struct {
10631053 }
10641054
10651055 fn addDepFileMaybePost(self: *Manifest, dir: fs.Dir, dep_file_basename: []const u8) !void {
1066 const dep_file_contents = try dir.readFileAlloc(self.cache.gpa, dep_file_basename, manifest_file_size_max);
1067 defer self.cache.gpa.free(dep_file_contents);
1056 const gpa = self.cache.gpa;
1057 const dep_file_contents = try dir.readFileAlloc(gpa, dep_file_basename, manifest_file_size_max);
1058 defer gpa.free(dep_file_contents);
10681059
1069 var error_buf = std.ArrayList(u8).init(self.cache.gpa);
1070 defer error_buf.deinit();
1060 var error_buf: std.ArrayListUnmanaged(u8) = .empty;
1061 defer error_buf.deinit(gpa);
10711062
1072 var it: DepTokenizer = .{ .bytes = dep_file_contents };
1063 var resolve_buf: std.ArrayListUnmanaged(u8) = .empty;
1064 defer resolve_buf.deinit(gpa);
10731065
1066 var it: DepTokenizer = .{ .bytes = dep_file_contents };
10741067 while (it.next()) |token| {
10751068 switch (token) {
10761069 // We don't care about targets, we only want the prereqs
......@@ -1080,16 +1073,14 @@ pub const Manifest = struct {
10801073 _ = try self.addFile(file_path, null);
10811074 } else try self.addFilePost(file_path),
10821075 .prereq_must_resolve => {
1083 var resolve_buf = std.ArrayList(u8).init(self.cache.gpa);
1084 defer resolve_buf.deinit();
1085
1086 try token.resolve(resolve_buf.writer());
1076 resolve_buf.clearRetainingCapacity();
1077 try token.resolve(gpa, &resolve_buf);
10871078 if (self.manifest_file == null) {
10881079 _ = try self.addFile(resolve_buf.items, null);
10891080 } else try self.addFilePost(resolve_buf.items);
10901081 },
10911082 else => |err| {
1092 try err.printError(error_buf.writer());
1083 try err.printError(gpa, &error_buf);
10931084 log.err("failed parsing {s}: {s}", .{ dep_file_basename, error_buf.items });
10941085 return error.InvalidDepFile;
10951086 },
......@@ -1127,24 +1118,12 @@ pub const Manifest = struct {
11271118 if (self.manifest_dirty) {
11281119 self.manifest_dirty = false;
11291120
1130 var contents = std.ArrayList(u8).init(self.cache.gpa);
1131 defer contents.deinit();
1132
1133 const writer = contents.writer();
1134 try writer.writeAll(manifest_header ++ "\n");
1135 for (self.files.keys()) |file| {
1136 try writer.print("{d} {d} {d} {} {d} {s}\n", .{
1137 file.stat.size,
1138 file.stat.inode,
1139 file.stat.mtime,
1140 fmt.fmtSliceHexLower(&file.bin_digest),
1141 file.prefixed_path.prefix,
1142 file.prefixed_path.sub_path,
1143 });
1144 }
1145
1146 try manifest_file.setEndPos(contents.items.len);
1147 try manifest_file.pwriteAll(contents.items, 0);
1121 var buffer: [4000]u8 = undefined;
1122 var fw = manifest_file.writer(&buffer);
1123 writeDirtyManifestToStream(self, &fw) catch |err| switch (err) {
1124 error.WriteFailed => return fw.err.?,
1125 else => |e| return e,
1126 };
11481127 }
11491128
11501129 if (self.want_shared_lock) {
......@@ -1152,6 +1131,21 @@ pub const Manifest = struct {
11521131 }
11531132 }
11541133
1134 fn writeDirtyManifestToStream(self: *Manifest, fw: *fs.File.Writer) !void {
1135 try fw.interface.writeAll(manifest_header ++ "\n");
1136 for (self.files.keys()) |file| {
1137 try fw.interface.print("{d} {d} {d} {x} {d} {s}\n", .{
1138 file.stat.size,
1139 file.stat.inode,
1140 file.stat.mtime,
1141 &file.bin_digest,
1142 file.prefixed_path.prefix,
1143 file.prefixed_path.sub_path,
1144 });
1145 }
1146 try fw.end();
1147 }
1148
11551149 fn downgradeToSharedLock(self: *Manifest) !void {
11561150 if (!self.have_exclusive_lock) return;
11571151
lib/std/Build/Cache/DepTokenizer.zig+43-158
......@@ -7,6 +7,7 @@ state: State = .lhs,
77const std = @import("std");
88const testing = std.testing;
99const assert = std.debug.assert;
10const Allocator = std.mem.Allocator;
1011
1112pub fn next(self: *Tokenizer) ?Token {
1213 var start = self.index;
......@@ -362,7 +363,7 @@ pub const Token = union(enum) {
362363 };
363364
364365 /// Resolve escapes in target or prereq. Only valid with .target_must_resolve or .prereq_must_resolve.
365 pub fn resolve(self: Token, writer: anytype) @TypeOf(writer).Error!void {
366 pub fn resolve(self: Token, gpa: Allocator, list: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!void {
366367 switch (self) {
367368 .target_must_resolve => |bytes| {
368369 var state: enum { start, escape, dollar } = .start;
......@@ -372,27 +373,27 @@ pub const Token = union(enum) {
372373 switch (c) {
373374 '\\' => state = .escape,
374375 '$' => state = .dollar,
375 else => try writer.writeByte(c),
376 else => try list.append(gpa, c),
376377 }
377378 },
378379 .escape => {
379380 switch (c) {
380381 ' ', '#', '\\' => {},
381382 '$' => {
382 try writer.writeByte('\\');
383 try list.append(gpa, '\\');
383384 state = .dollar;
384385 continue;
385386 },
386 else => try writer.writeByte('\\'),
387 else => try list.append(gpa, '\\'),
387388 }
388 try writer.writeByte(c);
389 try list.append(gpa, c);
389390 state = .start;
390391 },
391392 .dollar => {
392 try writer.writeByte('$');
393 try list.append(gpa, '$');
393394 switch (c) {
394395 '$' => {},
395 else => try writer.writeByte(c),
396 else => try list.append(gpa, c),
396397 }
397398 state = .start;
398399 },
......@@ -406,19 +407,19 @@ pub const Token = union(enum) {
406407 .start => {
407408 switch (c) {
408409 '\\' => state = .escape,
409 else => try writer.writeByte(c),
410 else => try list.append(gpa, c),
410411 }
411412 },
412413 .escape => {
413414 switch (c) {
414415 ' ' => {},
415416 '\\' => {
416 try writer.writeByte(c);
417 try list.append(gpa, c);
417418 continue;
418419 },
419 else => try writer.writeByte('\\'),
420 else => try list.append(gpa, '\\'),
420421 }
421 try writer.writeByte(c);
422 try list.append(gpa, c);
422423 state = .start;
423424 },
424425 }
......@@ -428,20 +429,20 @@ pub const Token = union(enum) {
428429 }
429430 }
430431
431 pub fn printError(self: Token, writer: anytype) @TypeOf(writer).Error!void {
432 pub fn printError(self: Token, gpa: Allocator, list: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!void {
432433 switch (self) {
433434 .target, .target_must_resolve, .prereq, .prereq_must_resolve => unreachable, // not an error
434435 .incomplete_quoted_prerequisite,
435436 .incomplete_target,
436437 => |index_and_bytes| {
437 try writer.print("{s} '", .{self.errStr()});
438 try list.print(gpa, "{s} '", .{self.errStr()});
438439 if (self == .incomplete_target) {
439440 const tmp = Token{ .target_must_resolve = index_and_bytes.bytes };
440 try tmp.resolve(writer);
441 try tmp.resolve(gpa, list);
441442 } else {
442 try printCharValues(writer, index_and_bytes.bytes);
443 try printCharValues(gpa, list, index_and_bytes.bytes);
443444 }
444 try writer.print("' at position {d}", .{index_and_bytes.index});
445 try list.print(gpa, "' at position {d}", .{index_and_bytes.index});
445446 },
446447 .invalid_target,
447448 .bad_target_escape,
......@@ -450,9 +451,9 @@ pub const Token = union(enum) {
450451 .incomplete_escape,
451452 .expected_colon,
452453 => |index_and_char| {
453 try writer.writeAll("illegal char ");
454 try printUnderstandableChar(writer, index_and_char.char);
455 try writer.print(" at position {d}: {s}", .{ index_and_char.index, self.errStr() });
454 try list.appendSlice(gpa, "illegal char ");
455 try printUnderstandableChar(gpa, list, index_and_char.char);
456 try list.print(gpa, " at position {d}: {s}", .{ index_and_char.index, self.errStr() });
456457 },
457458 }
458459 }
......@@ -1026,41 +1027,41 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void {
10261027 defer arena_allocator.deinit();
10271028
10281029 var it: Tokenizer = .{ .bytes = input };
1029 var buffer = std.ArrayList(u8).init(arena);
1030 var resolve_buf = std.ArrayList(u8).init(arena);
1030 var buffer: std.ArrayListUnmanaged(u8) = .empty;
1031 var resolve_buf: std.ArrayListUnmanaged(u8) = .empty;
10311032 var i: usize = 0;
10321033 while (it.next()) |token| {
1033 if (i != 0) try buffer.appendSlice("\n");
1034 if (i != 0) try buffer.appendSlice(arena, "\n");
10341035 switch (token) {
10351036 .target, .prereq => |bytes| {
1036 try buffer.appendSlice(@tagName(token));
1037 try buffer.appendSlice(" = {");
1037 try buffer.appendSlice(arena, @tagName(token));
1038 try buffer.appendSlice(arena, " = {");
10381039 for (bytes) |b| {
1039 try buffer.append(printable_char_tab[b]);
1040 try buffer.append(arena, printable_char_tab[b]);
10401041 }
1041 try buffer.appendSlice("}");
1042 try buffer.appendSlice(arena, "}");
10421043 },
10431044 .target_must_resolve => {
1044 try buffer.appendSlice("target = {");
1045 try token.resolve(resolve_buf.writer());
1045 try buffer.appendSlice(arena, "target = {");
1046 try token.resolve(arena, &resolve_buf);
10461047 for (resolve_buf.items) |b| {
1047 try buffer.append(printable_char_tab[b]);
1048 try buffer.append(arena, printable_char_tab[b]);
10481049 }
10491050 resolve_buf.items.len = 0;
1050 try buffer.appendSlice("}");
1051 try buffer.appendSlice(arena, "}");
10511052 },
10521053 .prereq_must_resolve => {
1053 try buffer.appendSlice("prereq = {");
1054 try token.resolve(resolve_buf.writer());
1054 try buffer.appendSlice(arena, "prereq = {");
1055 try token.resolve(arena, &resolve_buf);
10551056 for (resolve_buf.items) |b| {
1056 try buffer.append(printable_char_tab[b]);
1057 try buffer.append(arena, printable_char_tab[b]);
10571058 }
10581059 resolve_buf.items.len = 0;
1059 try buffer.appendSlice("}");
1060 try buffer.appendSlice(arena, "}");
10601061 },
10611062 else => {
1062 try buffer.appendSlice("ERROR: ");
1063 try token.printError(buffer.writer());
1063 try buffer.appendSlice(arena, "ERROR: ");
1064 try token.printError(arena, &buffer);
10641065 break;
10651066 },
10661067 }
......@@ -1072,134 +1073,18 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void {
10721073 return;
10731074 }
10741075
1075 const out = std.io.getStdErr().writer();
1076
1077 try out.writeAll("\n");
1078 try printSection(out, "<<<< input", input);
1079 try printSection(out, "==== expect", expect);
1080 try printSection(out, ">>>> got", buffer.items);
1081 try printRuler(out);
1082
1083 try testing.expect(false);
1084}
1085
1086fn printSection(out: anytype, label: []const u8, bytes: []const u8) !void {
1087 try printLabel(out, label, bytes);
1088 try hexDump(out, bytes);
1089 try printRuler(out);
1090 try out.writeAll(bytes);
1091 try out.writeAll("\n");
1092}
1093
1094fn printLabel(out: anytype, label: []const u8, bytes: []const u8) !void {
1095 var buf: [80]u8 = undefined;
1096 const text = try std.fmt.bufPrint(buf[0..], "{s} {d} bytes ", .{ label, bytes.len });
1097 try out.writeAll(text);
1098 var i: usize = text.len;
1099 const end = 79;
1100 while (i < end) : (i += 1) {
1101 try out.writeAll(&[_]u8{label[0]});
1102 }
1103 try out.writeAll("\n");
1104}
1105
1106fn printRuler(out: anytype) !void {
1107 var i: usize = 0;
1108 const end = 79;
1109 while (i < end) : (i += 1) {
1110 try out.writeAll("-");
1111 }
1112 try out.writeAll("\n");
1113}
1114
1115fn hexDump(out: anytype, bytes: []const u8) !void {
1116 const n16 = bytes.len >> 4;
1117 var line: usize = 0;
1118 var offset: usize = 0;
1119 while (line < n16) : (line += 1) {
1120 try hexDump16(out, offset, bytes[offset..][0..16]);
1121 offset += 16;
1122 }
1123
1124 const n = bytes.len & 0x0f;
1125 if (n > 0) {
1126 try printDecValue(out, offset, 8);
1127 try out.writeAll(":");
1128 try out.writeAll(" ");
1129 const end1 = @min(offset + n, offset + 8);
1130 for (bytes[offset..end1]) |b| {
1131 try out.writeAll(" ");
1132 try printHexValue(out, b, 2);
1133 }
1134 const end2 = offset + n;
1135 if (end2 > end1) {
1136 try out.writeAll(" ");
1137 for (bytes[end1..end2]) |b| {
1138 try out.writeAll(" ");
1139 try printHexValue(out, b, 2);
1140 }
1141 }
1142 const short = 16 - n;
1143 var i: usize = 0;
1144 while (i < short) : (i += 1) {
1145 try out.writeAll(" ");
1146 }
1147 if (end2 > end1) {
1148 try out.writeAll(" |");
1149 } else {
1150 try out.writeAll(" |");
1151 }
1152 try printCharValues(out, bytes[offset..end2]);
1153 try out.writeAll("|\n");
1154 offset += n;
1155 }
1156
1157 try printDecValue(out, offset, 8);
1158 try out.writeAll(":");
1159 try out.writeAll("\n");
1076 try testing.expectEqualStrings(expect, buffer.items);
11601077}
11611078
1162fn hexDump16(out: anytype, offset: usize, bytes: []const u8) !void {
1163 try printDecValue(out, offset, 8);
1164 try out.writeAll(":");
1165 try out.writeAll(" ");
1166 for (bytes[0..8]) |b| {
1167 try out.writeAll(" ");
1168 try printHexValue(out, b, 2);
1169 }
1170 try out.writeAll(" ");
1171 for (bytes[8..16]) |b| {
1172 try out.writeAll(" ");
1173 try printHexValue(out, b, 2);
1174 }
1175 try out.writeAll(" |");
1176 try printCharValues(out, bytes);
1177 try out.writeAll("|\n");
1178}
1179
1180fn printDecValue(out: anytype, value: u64, width: u8) !void {
1181 var buffer: [20]u8 = undefined;
1182 const len = std.fmt.formatIntBuf(buffer[0..], value, 10, .lower, .{ .width = width, .fill = '0' });
1183 try out.writeAll(buffer[0..len]);
1184}
1185
1186fn printHexValue(out: anytype, value: u64, width: u8) !void {
1187 var buffer: [16]u8 = undefined;
1188 const len = std.fmt.formatIntBuf(buffer[0..], value, 16, .lower, .{ .width = width, .fill = '0' });
1189 try out.writeAll(buffer[0..len]);
1190}
1191
1192fn printCharValues(out: anytype, bytes: []const u8) !void {
1193 for (bytes) |b| {
1194 try out.writeAll(&[_]u8{printable_char_tab[b]});
1195 }
1079fn printCharValues(gpa: Allocator, list: *std.ArrayListUnmanaged(u8), bytes: []const u8) !void {
1080 for (bytes) |b| try list.append(gpa, printable_char_tab[b]);
11961081}
11971082
1198fn printUnderstandableChar(out: anytype, char: u8) !void {
1083fn printUnderstandableChar(gpa: Allocator, list: *std.ArrayListUnmanaged(u8), char: u8) !void {
11991084 if (std.ascii.isPrint(char)) {
1200 try out.print("'{c}'", .{char});
1085 try list.print(gpa, "'{c}'", .{char});
12011086 } else {
1202 try out.print("\\x{X:0>2}", .{char});
1087 try list.print(gpa, "\\x{X:0>2}", .{char});
12031088 }
12041089}
12051090
lib/std/Build/Cache/Directory.zig+2-8
......@@ -1,5 +1,6 @@
11const Directory = @This();
22const std = @import("../../std.zig");
3const assert = std.debug.assert;
34const fs = std.fs;
45const fmt = std.fmt;
56const Allocator = std.mem.Allocator;
......@@ -55,14 +56,7 @@ pub fn closeAndFree(self: *Directory, gpa: Allocator) void {
5556 self.* = undefined;
5657}
5758
58pub fn format(
59 self: Directory,
60 comptime fmt_string: []const u8,
61 options: fmt.FormatOptions,
62 writer: anytype,
63) !void {
64 _ = options;
65 if (fmt_string.len != 0) fmt.invalidFmtError(fmt_string, self);
59pub fn format(self: Directory, writer: *std.io.Writer) std.io.Writer.Error!void {
6660 if (self.path) |p| {
6761 try writer.writeAll(p);
6862 try writer.writeAll(fs.path.sep_str);
lib/std/Build/Cache/Path.zig+39-34
......@@ -1,3 +1,10 @@
1const Path = @This();
2const std = @import("../../std.zig");
3const assert = std.debug.assert;
4const fs = std.fs;
5const Allocator = std.mem.Allocator;
6const Cache = std.Build.Cache;
7
18root_dir: Cache.Directory,
29/// The path, relative to the root dir, that this `Path` represents.
310/// Empty string means the root_dir is the path.
......@@ -133,38 +140,42 @@ pub fn makePath(p: Path, sub_path: []const u8) !void {
133140}
134141
135142pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 {
136 return std.fmt.allocPrint(allocator, "{}", .{p});
143 return std.fmt.allocPrint(allocator, "{f}", .{p});
137144}
138145
139146pub fn toStringZ(p: Path, allocator: Allocator) Allocator.Error![:0]u8 {
140 return std.fmt.allocPrintZ(allocator, "{}", .{p});
141}
142
143pub fn format(
144 self: Path,
145 comptime fmt_string: []const u8,
146 options: std.fmt.FormatOptions,
147 writer: anytype,
148) !void {
149 if (fmt_string.len == 1) {
150 // Quote-escape the string.
151 const stringEscape = std.zig.stringEscape;
152 const f = switch (fmt_string[0]) {
153 'q' => "",
154 '\'' => "\'",
155 else => @compileError("unsupported format string: " ++ fmt_string),
156 };
157 if (self.root_dir.path) |p| {
158 try stringEscape(p, f, options, writer);
159 if (self.sub_path.len > 0) try stringEscape(fs.path.sep_str, f, options, writer);
160 }
161 if (self.sub_path.len > 0) {
162 try stringEscape(self.sub_path, f, options, writer);
163 }
164 return;
147 return std.fmt.allocPrintSentinel(allocator, "{f}", .{p}, 0);
148}
149
150pub fn fmtEscapeString(path: Path) std.fmt.Formatter(Path, formatEscapeString) {
151 return .{ .data = path };
152}
153
154pub fn formatEscapeString(path: Path, writer: *std.io.Writer) std.io.Writer.Error!void {
155 if (path.root_dir.path) |p| {
156 try std.zig.stringEscape(p, writer);
157 if (path.sub_path.len > 0) try std.zig.stringEscape(fs.path.sep_str, writer);
165158 }
166 if (fmt_string.len > 0)
167 std.fmt.invalidFmtError(fmt_string, self);
159 if (path.sub_path.len > 0) {
160 try std.zig.stringEscape(path.sub_path, writer);
161 }
162}
163
164pub fn fmtEscapeChar(path: Path) std.fmt.Formatter(Path, formatEscapeChar) {
165 return .{ .data = path };
166}
167
168pub fn formatEscapeChar(path: Path, writer: *std.io.Writer) std.io.Writer.Error!void {
169 if (path.root_dir.path) |p| {
170 try std.zig.charEscape(p, writer);
171 if (path.sub_path.len > 0) try std.zig.charEscape(fs.path.sep_str, writer);
172 }
173 if (path.sub_path.len > 0) {
174 try std.zig.charEscape(path.sub_path, writer);
175 }
176}
177
178pub fn format(self: Path, writer: *std.io.Writer) std.io.Writer.Error!void {
168179 if (std.fs.path.isAbsolute(self.sub_path)) {
169180 try writer.writeAll(self.sub_path);
170181 return;
......@@ -223,9 +234,3 @@ pub const TableAdapter = struct {
223234 return a.eql(b);
224235 }
225236};
226
227const Path = @This();
228const std = @import("../../std.zig");
229const fs = std.fs;
230const Allocator = std.mem.Allocator;
231const Cache = std.Build.Cache;
lib/std/Build/Fuzz.zig+8-8
......@@ -112,7 +112,6 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog
112112
113113fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {
114114 const gpa = run.step.owner.allocator;
115 const stderr = std.io.getStdErr();
116115
117116 const compile = run.producer.?;
118117 const prog_node = parent_prog_node.start(compile.step.name, 0);
......@@ -125,9 +124,10 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, par
125124 const show_stderr = compile.step.result_stderr.len > 0;
126125
127126 if (show_error_msgs or show_compile_errors or show_stderr) {
128 std.debug.lockStdErr();
129 defer std.debug.unlockStdErr();
130 build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, stderr, false) catch {};
127 var buf: [256]u8 = undefined;
128 const w = std.debug.lockStderrWriter(&buf);
129 defer std.debug.unlockStderrWriter();
130 build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, w, false) catch {};
131131 }
132132
133133 const rebuilt_bin_path = result catch |err| switch (err) {
......@@ -152,10 +152,10 @@ fn fuzzWorkerRun(
152152
153153 run.rerunInFuzzMode(web_server, unit_test_index, prog_node) catch |err| switch (err) {
154154 error.MakeFailed => {
155 const stderr = std.io.getStdErr();
156 std.debug.lockStdErr();
157 defer std.debug.unlockStdErr();
158 build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, stderr, false) catch {};
155 var buf: [256]u8 = undefined;
156 const w = std.debug.lockStderrWriter(&buf);
157 defer std.debug.unlockStderrWriter();
158 build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, w, false) catch {};
159159 return;
160160 },
161161 else => {
lib/std/Build/Fuzz/WebServer.zig+9-9
......@@ -170,7 +170,7 @@ fn serveFile(
170170 // We load the file with every request so that the user can make changes to the file
171171 // and refresh the HTML page without restarting this server.
172172 const file_contents = ws.zig_lib_directory.handle.readFileAlloc(gpa, name, 10 * 1024 * 1024) catch |err| {
173 log.err("failed to read '{}{s}': {s}", .{ ws.zig_lib_directory, name, @errorName(err) });
173 log.err("failed to read '{f}{s}': {s}", .{ ws.zig_lib_directory, name, @errorName(err) });
174174 return error.AlreadyReported;
175175 };
176176 defer gpa.free(file_contents);
......@@ -251,10 +251,10 @@ fn buildWasmBinary(
251251 "-fsingle-threaded", //
252252 "--dep", "Walk", //
253253 "--dep", "html_render", //
254 try std.fmt.allocPrint(arena, "-Mroot={}", .{main_src_path}), //
255 try std.fmt.allocPrint(arena, "-MWalk={}", .{walk_src_path}), //
254 try std.fmt.allocPrint(arena, "-Mroot={f}", .{main_src_path}), //
255 try std.fmt.allocPrint(arena, "-MWalk={f}", .{walk_src_path}), //
256256 "--dep", "Walk", //
257 try std.fmt.allocPrint(arena, "-Mhtml_render={}", .{html_render_src_path}), //
257 try std.fmt.allocPrint(arena, "-Mhtml_render={f}", .{html_render_src_path}), //
258258 "--listen=-",
259259 });
260260
......@@ -526,7 +526,7 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void {
526526
527527 for (deduped_paths) |joined_path| {
528528 var file = joined_path.root_dir.handle.openFile(joined_path.sub_path, .{}) catch |err| {
529 log.err("failed to open {}: {s}", .{ joined_path, @errorName(err) });
529 log.err("failed to open {f}: {s}", .{ joined_path, @errorName(err) });
530530 continue;
531531 };
532532 defer file.close();
......@@ -604,7 +604,7 @@ fn prepareTables(
604604
605605 const rebuilt_exe_path = run_step.rebuilt_executable.?;
606606 var debug_info = std.debug.Info.load(gpa, rebuilt_exe_path, &gop.value_ptr.coverage) catch |err| {
607 log.err("step '{s}': failed to load debug information for '{}': {s}", .{
607 log.err("step '{s}': failed to load debug information for '{f}': {s}", .{
608608 run_step.step.name, rebuilt_exe_path, @errorName(err),
609609 });
610610 return error.AlreadyReported;
......@@ -616,7 +616,7 @@ fn prepareTables(
616616 .sub_path = "v/" ++ std.fmt.hex(coverage_id),
617617 };
618618 var coverage_file = coverage_file_path.root_dir.handle.openFile(coverage_file_path.sub_path, .{}) catch |err| {
619 log.err("step '{s}': failed to load coverage file '{}': {s}", .{
619 log.err("step '{s}': failed to load coverage file '{f}': {s}", .{
620620 run_step.step.name, coverage_file_path, @errorName(err),
621621 });
622622 return error.AlreadyReported;
......@@ -624,7 +624,7 @@ fn prepareTables(
624624 defer coverage_file.close();
625625
626626 const file_size = coverage_file.getEndPos() catch |err| {
627 log.err("unable to check len of coverage file '{}': {s}", .{ coverage_file_path, @errorName(err) });
627 log.err("unable to check len of coverage file '{f}': {s}", .{ coverage_file_path, @errorName(err) });
628628 return error.AlreadyReported;
629629 };
630630
......@@ -636,7 +636,7 @@ fn prepareTables(
636636 coverage_file.handle,
637637 0,
638638 ) catch |err| {
639 log.err("failed to map coverage file '{}': {s}", .{ coverage_file_path, @errorName(err) });
639 log.err("failed to map coverage file '{f}': {s}", .{ coverage_file_path, @errorName(err) });
640640 return error.AlreadyReported;
641641 };
642642 gop.value_ptr.mapped_memory = mapped_memory;
lib/std/Build/Module.zig+1-1
......@@ -186,7 +186,7 @@ pub const IncludeDir = union(enum) {
186186 .embed_path => |lazy_path| {
187187 // Special case: this is a single arg.
188188 const resolved = lazy_path.getPath3(b, asking_step);
189 const arg = b.fmt("--embed-dir={}", .{resolved});
189 const arg = b.fmt("--embed-dir={f}", .{resolved});
190190 return zig_args.append(arg);
191191 },
192192 };
lib/std/Build/Step.zig+4-6
......@@ -286,9 +286,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
286286}
287287
288288/// For debugging purposes, prints identifying information about this Step.
289pub fn dump(step: *Step, file: std.fs.File) void {
290 const w = file.writer();
291 const tty_config = std.io.tty.detectConfig(file);
289pub fn dump(step: *Step, w: *std.io.Writer, tty_config: std.io.tty.Config) void {
292290 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
293291 w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
294292 @errorName(err),
......@@ -482,9 +480,9 @@ pub fn evalZigProcess(
482480pub fn installFile(s: *Step, src_lazy_path: Build.LazyPath, dest_path: []const u8) !std.fs.Dir.PrevStatus {
483481 const b = s.owner;
484482 const src_path = src_lazy_path.getPath3(b, s);
485 try handleVerbose(b, null, &.{ "install", "-C", b.fmt("{}", .{src_path}), dest_path });
483 try handleVerbose(b, null, &.{ "install", "-C", b.fmt("{f}", .{src_path}), dest_path });
486484 return src_path.root_dir.handle.updateFile(src_path.sub_path, std.fs.cwd(), dest_path, .{}) catch |err| {
487 return s.fail("unable to update file from '{}' to '{s}': {s}", .{
485 return s.fail("unable to update file from '{f}' to '{s}': {s}", .{
488486 src_path, dest_path, @errorName(err),
489487 });
490488 };
......@@ -821,7 +819,7 @@ fn failWithCacheError(s: *Step, man: *const Build.Cache.Manifest, err: Build.Cac
821819 switch (err) {
822820 error.CacheCheckFailed => switch (man.diagnostic) {
823821 .none => unreachable,
824 .manifest_create, .manifest_read, .manifest_lock, .manifest_seek => |e| return s.fail("failed to check cache: {s} {s}", .{
822 .manifest_create, .manifest_read, .manifest_lock => |e| return s.fail("failed to check cache: {s} {s}", .{
825823 @tagName(man.diagnostic), @errorName(e),
826824 }),
827825 .file_open, .file_stat, .file_read, .file_hash => |op| {
lib/std/Build/Step/CheckObject.zig+36-61
......@@ -6,6 +6,7 @@ const macho = std.macho;
66const math = std.math;
77const mem = std.mem;
88const testing = std.testing;
9const Writer = std.io.Writer;
910
1011const CheckObject = @This();
1112
......@@ -28,7 +29,7 @@ pub fn create(
2829 const gpa = owner.allocator;
2930 const check_object = gpa.create(CheckObject) catch @panic("OOM");
3031 check_object.* = .{
31 .step = Step.init(.{
32 .step = .init(.{
3233 .id = base_id,
3334 .name = "CheckObject",
3435 .owner = owner,
......@@ -80,7 +81,7 @@ const Action = struct {
8081 const hay = mem.trim(u8, haystack, " ");
8182 const phrase = mem.trim(u8, act.phrase.resolve(b, step), " ");
8283
83 var candidate_vars = std.ArrayList(struct { name: []const u8, value: u64 }).init(b.allocator);
84 var candidate_vars: std.ArrayList(struct { name: []const u8, value: u64 }) = .init(b.allocator);
8485 var hay_it = mem.tokenizeScalar(u8, hay, ' ');
8586 var needle_it = mem.tokenizeScalar(u8, phrase, ' ');
8687
......@@ -229,18 +230,11 @@ const ComputeCompareExpected = struct {
229230 literal: u64,
230231 },
231232
232 pub fn format(
233 value: @This(),
234 comptime fmt: []const u8,
235 options: std.fmt.FormatOptions,
236 writer: anytype,
237 ) !void {
238 if (fmt.len != 0) std.fmt.invalidFmtError(fmt, value);
239 _ = options;
240 try writer.print("{s} ", .{@tagName(value.op)});
233 pub fn format(value: ComputeCompareExpected, w: *Writer) Writer.Error!void {
234 try w.print("{t} ", .{value.op});
241235 switch (value.value) {
242 .variable => |name| try writer.writeAll(name),
243 .literal => |x| try writer.print("{x}", .{x}),
236 .variable => |name| try w.writeAll(name),
237 .literal => |x| try w.print("{x}", .{x}),
244238 }
245239 }
246240};
......@@ -565,9 +559,11 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
565559 null,
566560 .of(u64),
567561 null,
568 ) catch |err| return step.fail("unable to read '{'}': {s}", .{ src_path, @errorName(err) });
562 ) catch |err| return step.fail("unable to read '{f}': {s}", .{
563 std.fmt.alt(src_path, .formatEscapeChar), @errorName(err),
564 });
569565
570 var vars = std.StringHashMap(u64).init(gpa);
566 var vars: std.StringHashMap(u64) = .init(gpa);
571567 for (check_object.checks.items) |chk| {
572568 if (chk.kind == .compute_compare) {
573569 assert(chk.actions.items.len == 1);
......@@ -581,7 +577,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
581577 return step.fail(
582578 \\
583579 \\========= comparison failed for action: ===========
584 \\{s} {}
580 \\{s} {f}
585581 \\===================================================
586582 , .{ act.phrase.resolve(b, step), act.expected.? });
587583 }
......@@ -600,7 +596,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
600596 // we either format message string with escaped codes, or not to aid debugging
601597 // the failed test.
602598 const fmtMessageString = struct {
603 fn fmtMessageString(kind: Check.Kind, msg: []const u8) std.fmt.Formatter(formatMessageString) {
599 fn fmtMessageString(kind: Check.Kind, msg: []const u8) std.fmt.Formatter(Ctx, formatMessageString) {
604600 return .{ .data = .{
605601 .kind = kind,
606602 .msg = msg,
......@@ -612,17 +608,10 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
612608 msg: []const u8,
613609 };
614610
615 fn formatMessageString(
616 ctx: Ctx,
617 comptime unused_fmt_string: []const u8,
618 options: std.fmt.FormatOptions,
619 writer: anytype,
620 ) !void {
621 _ = unused_fmt_string;
622 _ = options;
611 fn formatMessageString(ctx: Ctx, w: *Writer) !void {
623612 switch (ctx.kind) {
624 .dump_section => try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ctx.msg)}),
625 else => try writer.writeAll(ctx.msg),
613 .dump_section => try w.print("{f}", .{std.ascii.hexEscape(ctx.msg, .lower)}),
614 else => try w.writeAll(ctx.msg),
626615 }
627616 }
628617 }.fmtMessageString;
......@@ -637,11 +626,11 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
637626 return step.fail(
638627 \\
639628 \\========= expected to find: ==========================
640 \\{s}
629 \\{f}
641630 \\========= but parsed file does not contain it: =======
642 \\{s}
631 \\{f}
643632 \\========= file path: =================================
644 \\{}
633 \\{f}
645634 , .{
646635 fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
647636 fmtMessageString(chk.kind, output),
......@@ -657,11 +646,11 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
657646 return step.fail(
658647 \\
659648 \\========= expected to find: ==========================
660 \\*{s}*
649 \\*{f}*
661650 \\========= but parsed file does not contain it: =======
662 \\{s}
651 \\{f}
663652 \\========= file path: =================================
664 \\{}
653 \\{f}
665654 , .{
666655 fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
667656 fmtMessageString(chk.kind, output),
......@@ -676,11 +665,11 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
676665 return step.fail(
677666 \\
678667 \\========= expected not to find: ===================
679 \\{s}
668 \\{f}
680669 \\========= but parsed file does contain it: ========
681 \\{s}
670 \\{f}
682671 \\========= file path: ==============================
683 \\{}
672 \\{f}
684673 , .{
685674 fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
686675 fmtMessageString(chk.kind, output),
......@@ -696,13 +685,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
696685 return step.fail(
697686 \\
698687 \\========= expected to find and extract: ==============
699 \\{s}
688 \\{f}
700689 \\========= but parsed file does not contain it: =======
701 \\{s}
690 \\{f}
702691 \\========= file path: ==============================
703 \\{}
692 \\{f}
704693 , .{
705 act.phrase.resolve(b, step),
694 fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
706695 fmtMessageString(chk.kind, output),
707696 src_path,
708697 });
......@@ -963,7 +952,7 @@ const MachODumper = struct {
963952 .UUID => {
964953 const uuid = lc.cast(macho.uuid_command).?;
965954 try writer.writeByte('\n');
966 try writer.print("uuid {x}", .{std.fmt.fmtSliceHexLower(&uuid.uuid)});
955 try writer.print("uuid {x}", .{&uuid.uuid});
967956 },
968957
969958 .DATA_IN_CODE,
......@@ -2012,7 +2001,7 @@ const ElfDumper = struct {
20122001
20132002 for (ctx.phdrs, 0..) |phdr, phndx| {
20142003 try writer.print("phdr {d}\n", .{phndx});
2015 try writer.print("type {s}\n", .{fmtPhType(phdr.p_type)});
2004 try writer.print("type {f}\n", .{fmtPhType(phdr.p_type)});
20162005 try writer.print("vaddr {x}\n", .{phdr.p_vaddr});
20172006 try writer.print("paddr {x}\n", .{phdr.p_paddr});
20182007 try writer.print("offset {x}\n", .{phdr.p_offset});
......@@ -2052,7 +2041,7 @@ const ElfDumper = struct {
20522041 for (ctx.shdrs, 0..) |shdr, shndx| {
20532042 try writer.print("shdr {d}\n", .{shndx});
20542043 try writer.print("name {s}\n", .{ctx.getSectionName(shndx)});
2055 try writer.print("type {s}\n", .{fmtShType(shdr.sh_type)});
2044 try writer.print("type {f}\n", .{fmtShType(shdr.sh_type)});
20562045 try writer.print("addr {x}\n", .{shdr.sh_addr});
20572046 try writer.print("offset {x}\n", .{shdr.sh_offset});
20582047 try writer.print("size {x}\n", .{shdr.sh_size});
......@@ -2325,18 +2314,11 @@ const ElfDumper = struct {
23252314 return mem.sliceTo(@as([*:0]const u8, @ptrCast(strtab.ptr + off)), 0);
23262315 }
23272316
2328 fn fmtShType(sh_type: u32) std.fmt.Formatter(formatShType) {
2317 fn fmtShType(sh_type: u32) std.fmt.Formatter(u32, formatShType) {
23292318 return .{ .data = sh_type };
23302319 }
23312320
2332 fn formatShType(
2333 sh_type: u32,
2334 comptime unused_fmt_string: []const u8,
2335 options: std.fmt.FormatOptions,
2336 writer: anytype,
2337 ) !void {
2338 _ = unused_fmt_string;
2339 _ = options;
2321 fn formatShType(sh_type: u32, writer: *Writer) Writer.Error!void {
23402322 const name = switch (sh_type) {
23412323 elf.SHT_NULL => "NULL",
23422324 elf.SHT_PROGBITS => "PROGBITS",
......@@ -2372,18 +2354,11 @@ const ElfDumper = struct {
23722354 try writer.writeAll(name);
23732355 }
23742356
2375 fn fmtPhType(ph_type: u32) std.fmt.Formatter(formatPhType) {
2357 fn fmtPhType(ph_type: u32) std.fmt.Formatter(u32, formatPhType) {
23762358 return .{ .data = ph_type };
23772359 }
23782360
2379 fn formatPhType(
2380 ph_type: u32,
2381 comptime unused_fmt_string: []const u8,
2382 options: std.fmt.FormatOptions,
2383 writer: anytype,
2384 ) !void {
2385 _ = unused_fmt_string;
2386 _ = options;
2361 fn formatPhType(ph_type: u32, writer: *Writer) Writer.Error!void {
23872362 const p_type = switch (ph_type) {
23882363 elf.PT_NULL => "NULL",
23892364 elf.PT_LOAD => "LOAD",
lib/std/Build/Step/Compile.zig+36-44
......@@ -409,7 +409,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
409409 .linkage = options.linkage,
410410 .kind = options.kind,
411411 .name = name,
412 .step = Step.init(.{
412 .step = .init(.{
413413 .id = base_id,
414414 .name = step_name,
415415 .owner = owner,
......@@ -1017,20 +1017,16 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
10171017 const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
10181018
10191019 const generated_file = maybe_path orelse {
1020 std.debug.lockStdErr();
1021 const stderr = std.io.getStdErr();
1022
1023 std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {};
1024
1020 const w = std.debug.lockStderrWriter(&.{});
1021 std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {};
1022 std.debug.unlockStderrWriter();
10251023 @panic("missing emit option for " ++ tag_name);
10261024 };
10271025
10281026 const path = generated_file.path orelse {
1029 std.debug.lockStdErr();
1030 const stderr = std.io.getStdErr();
1031
1032 std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {};
1033
1027 const w = std.debug.lockStderrWriter(&.{});
1028 std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {};
1029 std.debug.unlockStderrWriter();
10341030 @panic(tag_name ++ " is null. Is there a missing step dependency?");
10351031 };
10361032
......@@ -1542,7 +1538,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
15421538 if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic) {
15431539 if (compile.version) |version| {
15441540 try zig_args.append("--version");
1545 try zig_args.append(b.fmt("{}", .{version}));
1541 try zig_args.append(b.fmt("{f}", .{version}));
15461542 }
15471543
15481544 if (compile.rootModuleTarget().os.tag.isDarwin()) {
......@@ -1696,9 +1692,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
16961692
16971693 if (compile.build_id orelse b.build_id) |build_id| {
16981694 try zig_args.append(switch (build_id) {
1699 .hexstring => |hs| b.fmt("--build-id=0x{s}", .{
1700 std.fmt.fmtSliceHexLower(hs.toSlice()),
1701 }),
1695 .hexstring => |hs| b.fmt("--build-id=0x{x}", .{hs.toSlice()}),
17021696 .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}),
17031697 });
17041698 }
......@@ -1706,7 +1700,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
17061700 const opt_zig_lib_dir = if (compile.zig_lib_dir) |dir|
17071701 dir.getPath2(b, step)
17081702 else if (b.graph.zig_lib_directory.path) |_|
1709 b.fmt("{}", .{b.graph.zig_lib_directory})
1703 b.fmt("{f}", .{b.graph.zig_lib_directory})
17101704 else
17111705 null;
17121706
......@@ -1746,8 +1740,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
17461740 }
17471741
17481742 if (compile.error_limit) |err_limit| try zig_args.appendSlice(&.{
1749 "--error-limit",
1750 b.fmt("{}", .{err_limit}),
1743 "--error-limit", b.fmt("{d}", .{err_limit}),
17511744 });
17521745
17531746 try addFlag(&zig_args, "incremental", b.graph.incremental);
......@@ -1771,12 +1764,12 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
17711764 for (arg, 0..) |c, arg_idx| {
17721765 if (c == '\\' or c == '"') {
17731766 // Slow path for arguments that need to be escaped. We'll need to allocate and copy
1774 var escaped = try ArrayList(u8).initCapacity(arena, arg.len + 1);
1775 const writer = escaped.writer();
1776 try writer.writeAll(arg[0..arg_idx]);
1767 var escaped: std.ArrayListUnmanaged(u8) = .empty;
1768 try escaped.ensureTotalCapacityPrecise(arena, arg.len + 1);
1769 try escaped.appendSlice(arena, arg[0..arg_idx]);
17771770 for (arg[arg_idx..]) |to_escape| {
1778 if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\');
1779 try writer.writeByte(to_escape);
1771 if (to_escape == '\\' or to_escape == '"') try escaped.append(arena, '\\');
1772 try escaped.append(arena, to_escape);
17801773 }
17811774 escaped_args.appendAssumeCapacity(escaped.items);
17821775 continue :arg_blk;
......@@ -1793,11 +1786,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
17931786 var args_hash: [Sha256.digest_length]u8 = undefined;
17941787 Sha256.hash(args, &args_hash, .{});
17951788 var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined;
1796 _ = try std.fmt.bufPrint(
1797 &args_hex_hash,
1798 "{s}",
1799 .{std.fmt.fmtSliceHexLower(&args_hash)},
1800 );
1789 _ = try std.fmt.bufPrint(&args_hex_hash, "{x}", .{&args_hash});
18011790
18021791 const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash;
18031792 try b.cache_root.handle.writeFile(.{ .sub_path = args_file, .data = args });
......@@ -1836,7 +1825,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
18361825 // Update generated files
18371826 if (maybe_output_dir) |output_dir| {
18381827 if (compile.emit_directory) |lp| {
1839 lp.path = b.fmt("{}", .{output_dir});
1828 lp.path = b.fmt("{f}", .{output_dir});
18401829 }
18411830
18421831 // zig fmt: off
......@@ -1970,20 +1959,23 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool)
19701959fn checkCompileErrors(compile: *Compile) !void {
19711960 // Clear this field so that it does not get printed by the build runner.
19721961 const actual_eb = compile.step.result_error_bundle;
1973 compile.step.result_error_bundle = std.zig.ErrorBundle.empty;
1962 compile.step.result_error_bundle = .empty;
19741963
19751964 const arena = compile.step.owner.allocator;
19761965
1977 var actual_errors_list = std.ArrayList(u8).init(arena);
1978 try actual_eb.renderToWriter(.{
1979 .ttyconf = .no_color,
1980 .include_reference_trace = false,
1981 .include_source_line = false,
1982 }, actual_errors_list.writer());
1983 const actual_errors = try actual_errors_list.toOwnedSlice();
1966 const actual_errors = ae: {
1967 var aw: std.io.Writer.Allocating = .init(arena);
1968 defer aw.deinit();
1969 try actual_eb.renderToWriter(.{
1970 .ttyconf = .no_color,
1971 .include_reference_trace = false,
1972 .include_source_line = false,
1973 }, &aw.writer);
1974 break :ae try aw.toOwnedSlice();
1975 };
19841976
19851977 // Render the expected lines into a string that we can compare verbatim.
1986 var expected_generated = std.ArrayList(u8).init(arena);
1978 var expected_generated: std.ArrayListUnmanaged(u8) = .empty;
19871979 const expect_errors = compile.expect_errors.?;
19881980
19891981 var actual_line_it = mem.splitScalar(u8, actual_errors, '\n');
......@@ -2042,17 +2034,17 @@ fn checkCompileErrors(compile: *Compile) !void {
20422034 .exact => |expect_lines| {
20432035 for (expect_lines) |expect_line| {
20442036 const actual_line = actual_line_it.next() orelse {
2045 try expected_generated.appendSlice(expect_line);
2046 try expected_generated.append('\n');
2037 try expected_generated.appendSlice(arena, expect_line);
2038 try expected_generated.append(arena, '\n');
20472039 continue;
20482040 };
20492041 if (matchCompileError(actual_line, expect_line)) {
2050 try expected_generated.appendSlice(actual_line);
2051 try expected_generated.append('\n');
2042 try expected_generated.appendSlice(arena, actual_line);
2043 try expected_generated.append(arena, '\n');
20522044 continue;
20532045 }
2054 try expected_generated.appendSlice(expect_line);
2055 try expected_generated.append('\n');
2046 try expected_generated.appendSlice(arena, expect_line);
2047 try expected_generated.append(arena, '\n');
20562048 }
20572049
20582050 if (mem.eql(u8, expected_generated.items, actual_errors)) return;
lib/std/Build/Step/ConfigHeader.zig+92-140
......@@ -2,6 +2,7 @@ const std = @import("std");
22const ConfigHeader = @This();
33const Step = std.Build.Step;
44const Allocator = std.mem.Allocator;
5const Writer = std.io.Writer;
56
67pub const Style = union(enum) {
78 /// A configure format supported by autotools that uses `#undef foo` to
......@@ -87,7 +88,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader {
8788 owner.fmt("configure {s} header to {s}", .{ @tagName(options.style), include_path });
8889
8990 config_header.* = .{
90 .step = Step.init(.{
91 .step = .init(.{
9192 .id = base_id,
9293 .name = name,
9394 .owner = owner,
......@@ -95,7 +96,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader {
9596 .first_ret_addr = options.first_ret_addr orelse @returnAddress(),
9697 }),
9798 .style = options.style,
98 .values = std.StringArrayHashMap(Value).init(owner.allocator),
99 .values = .init(owner.allocator),
99100
100101 .max_bytes = options.max_bytes,
101102 .include_path = include_path,
......@@ -195,8 +196,9 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
195196 man.hash.addBytes(config_header.include_path);
196197 man.hash.addOptionalBytes(config_header.include_guard_override);
197198
198 var output = std.ArrayList(u8).init(gpa);
199 defer output.deinit();
199 var aw: std.io.Writer.Allocating = .init(gpa);
200 defer aw.deinit();
201 const bw = &aw.writer;
200202
201203 const header_text = "This file was generated by ConfigHeader using the Zig Build System.";
202204 const c_generated_line = "/* " ++ header_text ++ " */\n";
......@@ -204,7 +206,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
204206
205207 switch (config_header.style) {
206208 .autoconf_undef, .autoconf, .autoconf_at => |file_source| {
207 try output.appendSlice(c_generated_line);
209 try bw.writeAll(c_generated_line);
208210 const src_path = file_source.getPath2(b, step);
209211 const contents = std.fs.cwd().readFileAlloc(arena, src_path, config_header.max_bytes) catch |err| {
210212 return step.fail("unable to read autoconf input file '{s}': {s}", .{
......@@ -212,32 +214,33 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
212214 });
213215 };
214216 switch (config_header.style) {
215 .autoconf_undef, .autoconf => try render_autoconf_undef(step, contents, &output, config_header.values, src_path),
216 .autoconf_at => try render_autoconf_at(step, contents, &output, config_header.values, src_path),
217 .autoconf_undef, .autoconf => try render_autoconf_undef(step, contents, bw, config_header.values, src_path),
218 .autoconf_at => try render_autoconf_at(step, contents, &aw, config_header.values, src_path),
217219 else => unreachable,
218220 }
219221 },
220222 .cmake => |file_source| {
221 try output.appendSlice(c_generated_line);
223 try bw.writeAll(c_generated_line);
222224 const src_path = file_source.getPath2(b, step);
223225 const contents = std.fs.cwd().readFileAlloc(arena, src_path, config_header.max_bytes) catch |err| {
224226 return step.fail("unable to read cmake input file '{s}': {s}", .{
225227 src_path, @errorName(err),
226228 });
227229 };
228 try render_cmake(step, contents, &output, config_header.values, src_path);
230 try render_cmake(step, contents, bw, config_header.values, src_path);
229231 },
230232 .blank => {
231 try output.appendSlice(c_generated_line);
232 try render_blank(&output, config_header.values, config_header.include_path, config_header.include_guard_override);
233 try bw.writeAll(c_generated_line);
234 try render_blank(gpa, bw, config_header.values, config_header.include_path, config_header.include_guard_override);
233235 },
234236 .nasm => {
235 try output.appendSlice(asm_generated_line);
236 try render_nasm(&output, config_header.values);
237 try bw.writeAll(asm_generated_line);
238 try render_nasm(bw, config_header.values);
237239 },
238240 }
239241
240 man.hash.addBytes(output.items);
242 const output = aw.getWritten();
243 man.hash.addBytes(output);
241244
242245 if (try step.cacheHit(&man)) {
243246 const digest = man.final();
......@@ -256,13 +259,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
256259 const sub_path_dirname = std.fs.path.dirname(sub_path).?;
257260
258261 b.cache_root.handle.makePath(sub_path_dirname) catch |err| {
259 return step.fail("unable to make path '{}{s}': {s}", .{
262 return step.fail("unable to make path '{f}{s}': {s}", .{
260263 b.cache_root, sub_path_dirname, @errorName(err),
261264 });
262265 };
263266
264 b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = output.items }) catch |err| {
265 return step.fail("unable to write file '{}{s}': {s}", .{
267 b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = output }) catch |err| {
268 return step.fail("unable to write file '{f}{s}': {s}", .{
266269 b.cache_root, sub_path, @errorName(err),
267270 });
268271 };
......@@ -274,7 +277,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
274277fn render_autoconf_undef(
275278 step: *Step,
276279 contents: []const u8,
277 output: *std.ArrayList(u8),
280 bw: *Writer,
278281 values: std.StringArrayHashMap(Value),
279282 src_path: []const u8,
280283) !void {
......@@ -289,15 +292,15 @@ fn render_autoconf_undef(
289292 var line_it = std.mem.splitScalar(u8, contents, '\n');
290293 while (line_it.next()) |line| : (line_index += 1) {
291294 if (!std.mem.startsWith(u8, line, "#")) {
292 try output.appendSlice(line);
293 try output.appendSlice("\n");
295 try bw.writeAll(line);
296 try bw.writeByte('\n');
294297 continue;
295298 }
296299 var it = std.mem.tokenizeAny(u8, line[1..], " \t\r");
297300 const undef = it.next().?;
298301 if (!std.mem.eql(u8, undef, "undef")) {
299 try output.appendSlice(line);
300 try output.appendSlice("\n");
302 try bw.writeAll(line);
303 try bw.writeByte('\n');
301304 continue;
302305 }
303306 const name = it.next().?;
......@@ -309,7 +312,7 @@ fn render_autoconf_undef(
309312 continue;
310313 };
311314 is_used.set(index);
312 try renderValueC(output, name, values.values()[index]);
315 try renderValueC(bw, name, values.values()[index]);
313316 }
314317
315318 var unused_value_it = is_used.iterator(.{ .kind = .unset });
......@@ -326,12 +329,13 @@ fn render_autoconf_undef(
326329fn render_autoconf_at(
327330 step: *Step,
328331 contents: []const u8,
329 output: *std.ArrayList(u8),
332 aw: *std.io.Writer.Allocating,
330333 values: std.StringArrayHashMap(Value),
331334 src_path: []const u8,
332335) !void {
333336 const build = step.owner;
334337 const allocator = build.allocator;
338 const bw = &aw.writer;
335339
336340 const used = allocator.alloc(bool, values.count()) catch @panic("OOM");
337341 for (used) |*u| u.* = false;
......@@ -343,11 +347,11 @@ fn render_autoconf_at(
343347 while (line_it.next()) |line| : (line_index += 1) {
344348 const last_line = line_it.index == line_it.buffer.len;
345349
346 const old_len = output.items.len;
347 expand_variables_autoconf_at(output, line, values, used) catch |err| switch (err) {
350 const old_len = aw.getWritten().len;
351 expand_variables_autoconf_at(bw, line, values, used) catch |err| switch (err) {
348352 error.MissingValue => {
349 const name = output.items[old_len..];
350 defer output.shrinkRetainingCapacity(old_len);
353 const name = aw.getWritten()[old_len..];
354 defer aw.shrinkRetainingCapacity(old_len);
351355 try step.addError("{s}:{d}: error: unspecified config header value: '{s}'", .{
352356 src_path, line_index + 1, name,
353357 });
......@@ -362,9 +366,7 @@ fn render_autoconf_at(
362366 continue;
363367 },
364368 };
365 if (!last_line) {
366 try output.append('\n');
367 }
369 if (!last_line) try bw.writeByte('\n');
368370 }
369371
370372 for (values.unmanaged.entries.slice().items(.key), used) |name, u| {
......@@ -374,15 +376,13 @@ fn render_autoconf_at(
374376 }
375377 }
376378
377 if (any_errors) {
378 return error.MakeFailed;
379 }
379 if (any_errors) return error.MakeFailed;
380380}
381381
382382fn render_cmake(
383383 step: *Step,
384384 contents: []const u8,
385 output: *std.ArrayList(u8),
385 bw: *Writer,
386386 values: std.StringArrayHashMap(Value),
387387 src_path: []const u8,
388388) !void {
......@@ -417,10 +417,8 @@ fn render_cmake(
417417 defer allocator.free(line);
418418
419419 if (!std.mem.startsWith(u8, line, "#")) {
420 try output.appendSlice(line);
421 if (!last_line) {
422 try output.appendSlice("\n");
423 }
420 try bw.writeAll(line);
421 if (!last_line) try bw.writeByte('\n');
424422 continue;
425423 }
426424 var it = std.mem.tokenizeAny(u8, line[1..], " \t\r");
......@@ -428,10 +426,8 @@ fn render_cmake(
428426 if (!std.mem.eql(u8, cmakedefine, "cmakedefine") and
429427 !std.mem.eql(u8, cmakedefine, "cmakedefine01"))
430428 {
431 try output.appendSlice(line);
432 if (!last_line) {
433 try output.appendSlice("\n");
434 }
429 try bw.writeAll(line);
430 if (!last_line) try bw.writeByte('\n');
435431 continue;
436432 }
437433
......@@ -502,7 +498,7 @@ fn render_cmake(
502498 value = Value{ .ident = it.rest() };
503499 }
504500
505 try renderValueC(output, name, value);
501 try renderValueC(bw, name, value);
506502 }
507503
508504 if (any_errors) {
......@@ -511,13 +507,14 @@ fn render_cmake(
511507}
512508
513509fn render_blank(
514 output: *std.ArrayList(u8),
510 gpa: std.mem.Allocator,
511 bw: *Writer,
515512 defines: std.StringArrayHashMap(Value),
516513 include_path: []const u8,
517514 include_guard_override: ?[]const u8,
518515) !void {
519516 const include_guard_name = include_guard_override orelse blk: {
520 const name = try output.allocator.dupe(u8, include_path);
517 const name = try gpa.dupe(u8, include_path);
521518 for (name) |*byte| {
522519 switch (byte.*) {
523520 'a'...'z' => byte.* = byte.* - 'a' + 'A',
......@@ -527,92 +524,53 @@ fn render_blank(
527524 }
528525 break :blk name;
529526 };
527 defer if (include_guard_override == null) gpa.free(include_guard_name);
530528
531 try output.appendSlice("#ifndef ");
532 try output.appendSlice(include_guard_name);
533 try output.appendSlice("\n#define ");
534 try output.appendSlice(include_guard_name);
535 try output.appendSlice("\n");
529 try bw.print(
530 \\#ifndef {[0]s}
531 \\#define {[0]s}
532 \\
533 , .{include_guard_name});
536534
537535 const values = defines.values();
538 for (defines.keys(), 0..) |name, i| {
539 try renderValueC(output, name, values[i]);
540 }
536 for (defines.keys(), 0..) |name, i| try renderValueC(bw, name, values[i]);
541537
542 try output.appendSlice("#endif /* ");
543 try output.appendSlice(include_guard_name);
544 try output.appendSlice(" */\n");
538 try bw.print(
539 \\#endif /* {s} */
540 \\
541 , .{include_guard_name});
545542}
546543
547fn render_nasm(output: *std.ArrayList(u8), defines: std.StringArrayHashMap(Value)) !void {
548 const values = defines.values();
549 for (defines.keys(), 0..) |name, i| {
550 try renderValueNasm(output, name, values[i]);
551 }
544fn render_nasm(bw: *Writer, defines: std.StringArrayHashMap(Value)) !void {
545 for (defines.keys(), defines.values()) |name, value| try renderValueNasm(bw, name, value);
552546}
553547
554fn renderValueC(output: *std.ArrayList(u8), name: []const u8, value: Value) !void {
548fn renderValueC(bw: *Writer, name: []const u8, value: Value) !void {
555549 switch (value) {
556 .undef => {
557 try output.appendSlice("/* #undef ");
558 try output.appendSlice(name);
559 try output.appendSlice(" */\n");
560 },
561 .defined => {
562 try output.appendSlice("#define ");
563 try output.appendSlice(name);
564 try output.appendSlice("\n");
565 },
566 .boolean => |b| {
567 try output.appendSlice("#define ");
568 try output.appendSlice(name);
569 try output.appendSlice(if (b) " 1\n" else " 0\n");
570 },
571 .int => |i| {
572 try output.writer().print("#define {s} {d}\n", .{ name, i });
573 },
574 .ident => |ident| {
575 try output.writer().print("#define {s} {s}\n", .{ name, ident });
576 },
577 .string => |string| {
578 // TODO: use C-specific escaping instead of zig string literals
579 try output.writer().print("#define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) });
580 },
550 .undef => try bw.print("/* #undef {s} */\n", .{name}),
551 .defined => try bw.print("#define {s}\n", .{name}),
552 .boolean => |b| try bw.print("#define {s} {c}\n", .{ name, @as(u8, '0') + @intFromBool(b) }),
553 .int => |i| try bw.print("#define {s} {d}\n", .{ name, i }),
554 .ident => |ident| try bw.print("#define {s} {s}\n", .{ name, ident }),
555 // TODO: use C-specific escaping instead of zig string literals
556 .string => |string| try bw.print("#define {s} \"{f}\"\n", .{ name, std.zig.fmtString(string) }),
581557 }
582558}
583559
584fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) !void {
560fn renderValueNasm(bw: *Writer, name: []const u8, value: Value) !void {
585561 switch (value) {
586 .undef => {
587 try output.appendSlice("; %undef ");
588 try output.appendSlice(name);
589 try output.appendSlice("\n");
590 },
591 .defined => {
592 try output.appendSlice("%define ");
593 try output.appendSlice(name);
594 try output.appendSlice("\n");
595 },
596 .boolean => |b| {
597 try output.appendSlice("%define ");
598 try output.appendSlice(name);
599 try output.appendSlice(if (b) " 1\n" else " 0\n");
600 },
601 .int => |i| {
602 try output.writer().print("%define {s} {d}\n", .{ name, i });
603 },
604 .ident => |ident| {
605 try output.writer().print("%define {s} {s}\n", .{ name, ident });
606 },
607 .string => |string| {
608 // TODO: use nasm-specific escaping instead of zig string literals
609 try output.writer().print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) });
610 },
562 .undef => try bw.print("; %undef {s}\n", .{name}),
563 .defined => try bw.print("%define {s}\n", .{name}),
564 .boolean => |b| try bw.print("%define {s} {c}\n", .{ name, @as(u8, '0') + @intFromBool(b) }),
565 .int => |i| try bw.print("%define {s} {d}\n", .{ name, i }),
566 .ident => |ident| try bw.print("%define {s} {s}\n", .{ name, ident }),
567 // TODO: use nasm-specific escaping instead of zig string literals
568 .string => |string| try bw.print("%define {s} \"{f}\"\n", .{ name, std.zig.fmtString(string) }),
611569 }
612570}
613571
614572fn expand_variables_autoconf_at(
615 output: *std.ArrayList(u8),
573 bw: *Writer,
616574 contents: []const u8,
617575 values: std.StringArrayHashMap(Value),
618576 used: []bool,
......@@ -637,23 +595,17 @@ fn expand_variables_autoconf_at(
637595 const key = contents[curr + 1 .. close_pos];
638596 const index = values.getIndex(key) orelse {
639597 // Report the missing key to the caller.
640 try output.appendSlice(key);
598 try bw.writeAll(key);
641599 return error.MissingValue;
642600 };
643601 const value = values.unmanaged.entries.slice().items(.value)[index];
644602 used[index] = true;
645 try output.appendSlice(contents[source_offset..curr]);
603 try bw.writeAll(contents[source_offset..curr]);
646604 switch (value) {
647605 .undef, .defined => {},
648 .boolean => |b| {
649 try output.append(if (b) '1' else '0');
650 },
651 .int => |i| {
652 try output.writer().print("{d}", .{i});
653 },
654 .ident, .string => |s| {
655 try output.appendSlice(s);
656 },
606 .boolean => |b| try bw.writeByte(@as(u8, '0') + @intFromBool(b)),
607 .int => |i| try bw.print("{d}", .{i}),
608 .ident, .string => |s| try bw.writeAll(s),
657609 }
658610
659611 curr = close_pos;
......@@ -661,7 +613,7 @@ fn expand_variables_autoconf_at(
661613 }
662614 }
663615
664 try output.appendSlice(contents[source_offset..]);
616 try bw.writeAll(contents[source_offset..]);
665617}
666618
667619fn expand_variables_cmake(
......@@ -669,7 +621,7 @@ fn expand_variables_cmake(
669621 contents: []const u8,
670622 values: std.StringArrayHashMap(Value),
671623) ![]const u8 {
672 var result = std.ArrayList(u8).init(allocator);
624 var result: std.ArrayList(u8) = .init(allocator);
673625 errdefer result.deinit();
674626
675627 const valid_varname_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/_.+-";
......@@ -681,7 +633,7 @@ fn expand_variables_cmake(
681633 source: usize,
682634 target: usize,
683635 };
684 var var_stack = std.ArrayList(Position).init(allocator);
636 var var_stack: std.ArrayList(Position) = .init(allocator);
685637 defer var_stack.deinit();
686638 loop: while (curr < contents.len) : (curr += 1) {
687639 switch (contents[curr]) {
......@@ -707,7 +659,7 @@ fn expand_variables_cmake(
707659 try result.append(if (b) '1' else '0');
708660 },
709661 .int => |i| {
710 try result.writer().print("{d}", .{i});
662 try result.print("{d}", .{i});
711663 },
712664 .ident, .string => |s| {
713665 try result.appendSlice(s);
......@@ -764,7 +716,7 @@ fn expand_variables_cmake(
764716 try result.append(if (b) '1' else '0');
765717 },
766718 .int => |i| {
767 try result.writer().print("{d}", .{i});
719 try result.print("{d}", .{i});
768720 },
769721 .ident, .string => |s| {
770722 try result.appendSlice(s);
......@@ -801,17 +753,17 @@ fn testReplaceVariablesAutoconfAt(
801753 expected: []const u8,
802754 values: std.StringArrayHashMap(Value),
803755) !void {
804 var output = std.ArrayList(u8).init(allocator);
805 defer output.deinit();
756 var aw: std.io.Writer.Allocating = .init(allocator);
757 defer aw.deinit();
806758
807759 const used = try allocator.alloc(bool, values.count());
808760 for (used) |*u| u.* = false;
809761 defer allocator.free(used);
810762
811 try expand_variables_autoconf_at(&output, contents, values, used);
763 try expand_variables_autoconf_at(&aw.writer, contents, values, used);
812764
813765 for (used) |u| if (!u) return error.UnusedValue;
814 try std.testing.expectEqualStrings(expected, output.items);
766 try std.testing.expectEqualStrings(expected, aw.getWritten());
815767}
816768
817769fn testReplaceVariablesCMake(
......@@ -828,7 +780,7 @@ fn testReplaceVariablesCMake(
828780
829781test "expand_variables_autoconf_at simple cases" {
830782 const allocator = std.testing.allocator;
831 var values = std.StringArrayHashMap(Value).init(allocator);
783 var values: std.StringArrayHashMap(Value) = .init(allocator);
832784 defer values.deinit();
833785
834786 // empty strings are preserved
......@@ -924,7 +876,7 @@ test "expand_variables_autoconf_at simple cases" {
924876
925877test "expand_variables_autoconf_at edge cases" {
926878 const allocator = std.testing.allocator;
927 var values = std.StringArrayHashMap(Value).init(allocator);
879 var values: std.StringArrayHashMap(Value) = .init(allocator);
928880 defer values.deinit();
929881
930882 // @-vars resolved only when they wrap valid characters, otherwise considered literals
......@@ -940,7 +892,7 @@ test "expand_variables_autoconf_at edge cases" {
940892
941893test "expand_variables_cmake simple cases" {
942894 const allocator = std.testing.allocator;
943 var values = std.StringArrayHashMap(Value).init(allocator);
895 var values: std.StringArrayHashMap(Value) = .init(allocator);
944896 defer values.deinit();
945897
946898 try values.putNoClobber("undef", .undef);
......@@ -1028,7 +980,7 @@ test "expand_variables_cmake simple cases" {
1028980
1029981test "expand_variables_cmake edge cases" {
1030982 const allocator = std.testing.allocator;
1031 var values = std.StringArrayHashMap(Value).init(allocator);
983 var values: std.StringArrayHashMap(Value) = .init(allocator);
1032984 defer values.deinit();
1033985
1034986 // special symbols
......@@ -1089,7 +1041,7 @@ test "expand_variables_cmake edge cases" {
10891041
10901042test "expand_variables_cmake escaped characters" {
10911043 const allocator = std.testing.allocator;
1092 var values = std.StringArrayHashMap(Value).init(allocator);
1044 var values: std.StringArrayHashMap(Value) = .init(allocator);
10931045 defer values.deinit();
10941046
10951047 try values.putNoClobber("string", Value{ .string = "text" });
lib/std/Build/Step/InstallArtifact.zig+1-1
......@@ -164,7 +164,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
164164 const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path);
165165
166166 var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
167 return step.fail("unable to open source directory '{}': {s}", .{
167 return step.fail("unable to open source directory '{f}': {s}", .{
168168 src_dir_path, @errorName(err),
169169 });
170170 };
lib/std/Build/Step/InstallDir.zig+1-1
......@@ -65,7 +65,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
6565 const src_dir_path = install_dir.options.source_dir.getPath3(b, step);
6666 const need_derived_inputs = try step.addDirectoryWatchInput(install_dir.options.source_dir);
6767 var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
68 return step.fail("unable to open source directory '{}': {s}", .{
68 return step.fail("unable to open source directory '{f}': {s}", .{
6969 src_dir_path, @errorName(err),
7070 });
7171 };
lib/std/Build/Step/Options.zig+148-113
......@@ -12,23 +12,23 @@ pub const base_id: Step.Id = .options;
1212step: Step,
1313generated_file: GeneratedFile,
1414
15contents: std.ArrayList(u8),
16args: std.ArrayList(Arg),
17encountered_types: std.StringHashMap(void),
15contents: std.ArrayListUnmanaged(u8),
16args: std.ArrayListUnmanaged(Arg),
17encountered_types: std.StringHashMapUnmanaged(void),
1818
1919pub fn create(owner: *std.Build) *Options {
2020 const options = owner.allocator.create(Options) catch @panic("OOM");
2121 options.* = .{
22 .step = Step.init(.{
22 .step = .init(.{
2323 .id = base_id,
2424 .name = "options",
2525 .owner = owner,
2626 .makeFn = make,
2727 }),
2828 .generated_file = undefined,
29 .contents = std.ArrayList(u8).init(owner.allocator),
30 .args = std.ArrayList(Arg).init(owner.allocator),
31 .encountered_types = std.StringHashMap(void).init(owner.allocator),
29 .contents = .empty,
30 .args = .empty,
31 .encountered_types = .empty,
3232 };
3333 options.generated_file = .{ .step = &options.step };
3434
......@@ -40,110 +40,119 @@ pub fn addOption(options: *Options, comptime T: type, name: []const u8, value: T
4040}
4141
4242fn addOptionFallible(options: *Options, comptime T: type, name: []const u8, value: T) !void {
43 const out = options.contents.writer();
44 try printType(options, out, T, value, 0, name);
43 try printType(options, &options.contents, T, value, 0, name);
4544}
4645
47fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent: u8, name: ?[]const u8) !void {
46fn printType(
47 options: *Options,
48 out: *std.ArrayListUnmanaged(u8),
49 comptime T: type,
50 value: T,
51 indent: u8,
52 name: ?[]const u8,
53) !void {
54 const gpa = options.step.owner.allocator;
4855 switch (T) {
4956 []const []const u8 => {
5057 if (name) |payload| {
51 try out.print("pub const {}: []const []const u8 = ", .{std.zig.fmtId(payload)});
58 try out.print(gpa, "pub const {f}: []const []const u8 = ", .{std.zig.fmtId(payload)});
5259 }
5360
54 try out.writeAll("&[_][]const u8{\n");
61 try out.appendSlice(gpa, "&[_][]const u8{\n");
5562
5663 for (value) |slice| {
57 try out.writeByteNTimes(' ', indent);
58 try out.print(" \"{}\",\n", .{std.zig.fmtEscapes(slice)});
64 try out.appendNTimes(gpa, ' ', indent);
65 try out.print(gpa, " \"{f}\",\n", .{std.zig.fmtString(slice)});
5966 }
6067
6168 if (name != null) {
62 try out.writeAll("};\n");
69 try out.appendSlice(gpa, "};\n");
6370 } else {
64 try out.writeAll("},\n");
71 try out.appendSlice(gpa, "},\n");
6572 }
6673
6774 return;
6875 },
6976 []const u8 => {
7077 if (name) |some| {
71 try out.print("pub const {}: []const u8 = \"{}\";", .{ std.zig.fmtId(some), std.zig.fmtEscapes(value) });
78 try out.print(gpa, "pub const {f}: []const u8 = \"{f}\";", .{
79 std.zig.fmtId(some), std.zig.fmtString(value),
80 });
7281 } else {
73 try out.print("\"{}\",", .{std.zig.fmtEscapes(value)});
82 try out.print(gpa, "\"{f}\",", .{std.zig.fmtString(value)});
7483 }
75 return out.writeAll("\n");
84 return out.appendSlice(gpa, "\n");
7685 },
7786 [:0]const u8 => {
7887 if (name) |some| {
79 try out.print("pub const {}: [:0]const u8 = \"{}\";", .{ std.zig.fmtId(some), std.zig.fmtEscapes(value) });
88 try out.print(gpa, "pub const {f}: [:0]const u8 = \"{f}\";", .{ std.zig.fmtId(some), std.zig.fmtString(value) });
8089 } else {
81 try out.print("\"{}\",", .{std.zig.fmtEscapes(value)});
90 try out.print(gpa, "\"{f}\",", .{std.zig.fmtString(value)});
8291 }
83 return out.writeAll("\n");
92 return out.appendSlice(gpa, "\n");
8493 },
8594 ?[]const u8 => {
8695 if (name) |some| {
87 try out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(some)});
96 try out.print(gpa, "pub const {f}: ?[]const u8 = ", .{std.zig.fmtId(some)});
8897 }
8998
9099 if (value) |payload| {
91 try out.print("\"{}\"", .{std.zig.fmtEscapes(payload)});
100 try out.print(gpa, "\"{f}\"", .{std.zig.fmtString(payload)});
92101 } else {
93 try out.writeAll("null");
102 try out.appendSlice(gpa, "null");
94103 }
95104
96105 if (name != null) {
97 try out.writeAll(";\n");
106 try out.appendSlice(gpa, ";\n");
98107 } else {
99 try out.writeAll(",\n");
108 try out.appendSlice(gpa, ",\n");
100109 }
101110 return;
102111 },
103112 ?[:0]const u8 => {
104113 if (name) |some| {
105 try out.print("pub const {}: ?[:0]const u8 = ", .{std.zig.fmtId(some)});
114 try out.print(gpa, "pub const {f}: ?[:0]const u8 = ", .{std.zig.fmtId(some)});
106115 }
107116
108117 if (value) |payload| {
109 try out.print("\"{}\"", .{std.zig.fmtEscapes(payload)});
118 try out.print(gpa, "\"{f}\"", .{std.zig.fmtString(payload)});
110119 } else {
111 try out.writeAll("null");
120 try out.appendSlice(gpa, "null");
112121 }
113122
114123 if (name != null) {
115 try out.writeAll(";\n");
124 try out.appendSlice(gpa, ";\n");
116125 } else {
117 try out.writeAll(",\n");
126 try out.appendSlice(gpa, ",\n");
118127 }
119128 return;
120129 },
121130 std.SemanticVersion => {
122131 if (name) |some| {
123 try out.print("pub const {}: @import(\"std\").SemanticVersion = ", .{std.zig.fmtId(some)});
132 try out.print(gpa, "pub const {f}: @import(\"std\").SemanticVersion = ", .{std.zig.fmtId(some)});
124133 }
125134
126 try out.writeAll(".{\n");
127 try out.writeByteNTimes(' ', indent);
128 try out.print(" .major = {d},\n", .{value.major});
129 try out.writeByteNTimes(' ', indent);
130 try out.print(" .minor = {d},\n", .{value.minor});
131 try out.writeByteNTimes(' ', indent);
132 try out.print(" .patch = {d},\n", .{value.patch});
135 try out.appendSlice(gpa, ".{\n");
136 try out.appendNTimes(gpa, ' ', indent);
137 try out.print(gpa, " .major = {d},\n", .{value.major});
138 try out.appendNTimes(gpa, ' ', indent);
139 try out.print(gpa, " .minor = {d},\n", .{value.minor});
140 try out.appendNTimes(gpa, ' ', indent);
141 try out.print(gpa, " .patch = {d},\n", .{value.patch});
133142
134143 if (value.pre) |some| {
135 try out.writeByteNTimes(' ', indent);
136 try out.print(" .pre = \"{}\",\n", .{std.zig.fmtEscapes(some)});
144 try out.appendNTimes(gpa, ' ', indent);
145 try out.print(gpa, " .pre = \"{f}\",\n", .{std.zig.fmtString(some)});
137146 }
138147 if (value.build) |some| {
139 try out.writeByteNTimes(' ', indent);
140 try out.print(" .build = \"{}\",\n", .{std.zig.fmtEscapes(some)});
148 try out.appendNTimes(gpa, ' ', indent);
149 try out.print(gpa, " .build = \"{f}\",\n", .{std.zig.fmtString(some)});
141150 }
142151
143152 if (name != null) {
144 try out.writeAll("};\n");
153 try out.appendSlice(gpa, "};\n");
145154 } else {
146 try out.writeAll("},\n");
155 try out.appendSlice(gpa, "},\n");
147156 }
148157 return;
149158 },
......@@ -153,21 +162,21 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent
153162 switch (@typeInfo(T)) {
154163 .array => {
155164 if (name) |some| {
156 try out.print("pub const {}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) });
165 try out.print(gpa, "pub const {f}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) });
157166 }
158167
159 try out.print("{s} {{\n", .{@typeName(T)});
168 try out.print(gpa, "{s} {{\n", .{@typeName(T)});
160169 for (value) |item| {
161 try out.writeByteNTimes(' ', indent + 4);
170 try out.appendNTimes(gpa, ' ', indent + 4);
162171 try printType(options, out, @TypeOf(item), item, indent + 4, null);
163172 }
164 try out.writeByteNTimes(' ', indent);
165 try out.writeAll("}");
173 try out.appendNTimes(gpa, ' ', indent);
174 try out.appendSlice(gpa, "}");
166175
167176 if (name != null) {
168 try out.writeAll(";\n");
177 try out.appendSlice(gpa, ";\n");
169178 } else {
170 try out.writeAll(",\n");
179 try out.appendSlice(gpa, ",\n");
171180 }
172181 return;
173182 },
......@@ -177,27 +186,27 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent
177186 }
178187
179188 if (name) |some| {
180 try out.print("pub const {}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) });
189 try out.print(gpa, "pub const {f}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) });
181190 }
182191
183 try out.print("&[_]{s} {{\n", .{@typeName(p.child)});
192 try out.print(gpa, "&[_]{s} {{\n", .{@typeName(p.child)});
184193 for (value) |item| {
185 try out.writeByteNTimes(' ', indent + 4);
194 try out.appendNTimes(gpa, ' ', indent + 4);
186195 try printType(options, out, @TypeOf(item), item, indent + 4, null);
187196 }
188 try out.writeByteNTimes(' ', indent);
189 try out.writeAll("}");
197 try out.appendNTimes(gpa, ' ', indent);
198 try out.appendSlice(gpa, "}");
190199
191200 if (name != null) {
192 try out.writeAll(";\n");
201 try out.appendSlice(gpa, ";\n");
193202 } else {
194 try out.writeAll(",\n");
203 try out.appendSlice(gpa, ",\n");
195204 }
196205 return;
197206 },
198207 .optional => {
199208 if (name) |some| {
200 try out.print("pub const {}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) });
209 try out.print(gpa, "pub const {f}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) });
201210 }
202211
203212 if (value) |inner| {
......@@ -206,13 +215,13 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent
206215 _ = options.contents.pop();
207216 _ = options.contents.pop();
208217 } else {
209 try out.writeAll("null");
218 try out.appendSlice(gpa, "null");
210219 }
211220
212221 if (name != null) {
213 try out.writeAll(";\n");
222 try out.appendSlice(gpa, ";\n");
214223 } else {
215 try out.writeAll(",\n");
224 try out.appendSlice(gpa, ",\n");
216225 }
217226 return;
218227 },
......@@ -224,9 +233,9 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent
224233 .null,
225234 => {
226235 if (name) |some| {
227 try out.print("pub const {}: {s} = {any};\n", .{ std.zig.fmtId(some), @typeName(T), value });
236 try out.print(gpa, "pub const {f}: {s} = {any};\n", .{ std.zig.fmtId(some), @typeName(T), value });
228237 } else {
229 try out.print("{any},\n", .{value});
238 try out.print(gpa, "{any},\n", .{value});
230239 }
231240 return;
232241 },
......@@ -234,10 +243,10 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent
234243 try printEnum(options, out, T, info, indent);
235244
236245 if (name) |some| {
237 try out.print("pub const {}: {} = .{p_};\n", .{
246 try out.print(gpa, "pub const {f}: {f} = .{f};\n", .{
238247 std.zig.fmtId(some),
239248 std.zig.fmtId(@typeName(T)),
240 std.zig.fmtId(@tagName(value)),
249 std.zig.fmtIdFlags(@tagName(value), .{ .allow_underscore = true, .allow_primitive = true }),
241250 });
242251 }
243252 return;
......@@ -246,7 +255,7 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent
246255 try printStruct(options, out, T, info, indent);
247256
248257 if (name) |some| {
249 try out.print("pub const {}: {} = ", .{
258 try out.print(gpa, "pub const {f}: {f} = ", .{
250259 std.zig.fmtId(some),
251260 std.zig.fmtId(@typeName(T)),
252261 });
......@@ -258,7 +267,7 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent
258267 }
259268}
260269
261fn printUserDefinedType(options: *Options, out: anytype, comptime T: type, indent: u8) !void {
270fn printUserDefinedType(options: *Options, out: *std.ArrayListUnmanaged(u8), comptime T: type, indent: u8) !void {
262271 switch (@typeInfo(T)) {
263272 .@"enum" => |info| {
264273 return try printEnum(options, out, T, info, indent);
......@@ -270,94 +279,119 @@ fn printUserDefinedType(options: *Options, out: anytype, comptime T: type, inden
270279 }
271280}
272281
273fn printEnum(options: *Options, out: anytype, comptime T: type, comptime val: std.builtin.Type.Enum, indent: u8) !void {
274 const gop = try options.encountered_types.getOrPut(@typeName(T));
282fn printEnum(
283 options: *Options,
284 out: *std.ArrayListUnmanaged(u8),
285 comptime T: type,
286 comptime val: std.builtin.Type.Enum,
287 indent: u8,
288) !void {
289 const gpa = options.step.owner.allocator;
290 const gop = try options.encountered_types.getOrPut(gpa, @typeName(T));
275291 if (gop.found_existing) return;
276292
277 try out.writeByteNTimes(' ', indent);
278 try out.print("pub const {} = enum ({s}) {{\n", .{ std.zig.fmtId(@typeName(T)), @typeName(val.tag_type) });
293 try out.appendNTimes(gpa, ' ', indent);
294 try out.print(gpa, "pub const {f} = enum ({s}) {{\n", .{ std.zig.fmtId(@typeName(T)), @typeName(val.tag_type) });
279295
280296 inline for (val.fields) |field| {
281 try out.writeByteNTimes(' ', indent);
282 try out.print(" {p} = {d},\n", .{ std.zig.fmtId(field.name), field.value });
297 try out.appendNTimes(gpa, ' ', indent);
298 try out.print(gpa, " {f} = {d},\n", .{
299 std.zig.fmtIdFlags(field.name, .{ .allow_primitive = true }), field.value,
300 });
283301 }
284302
285303 if (!val.is_exhaustive) {
286 try out.writeByteNTimes(' ', indent);
287 try out.writeAll(" _,\n");
304 try out.appendNTimes(gpa, ' ', indent);
305 try out.appendSlice(gpa, " _,\n");
288306 }
289307
290 try out.writeByteNTimes(' ', indent);
291 try out.writeAll("};\n");
308 try out.appendNTimes(gpa, ' ', indent);
309 try out.appendSlice(gpa, "};\n");
292310}
293311
294fn printStruct(options: *Options, out: anytype, comptime T: type, comptime val: std.builtin.Type.Struct, indent: u8) !void {
295 const gop = try options.encountered_types.getOrPut(@typeName(T));
312fn printStruct(options: *Options, out: *std.ArrayListUnmanaged(u8), comptime T: type, comptime val: std.builtin.Type.Struct, indent: u8) !void {
313 const gpa = options.step.owner.allocator;
314 const gop = try options.encountered_types.getOrPut(gpa, @typeName(T));
296315 if (gop.found_existing) return;
297316
298 try out.writeByteNTimes(' ', indent);
299 try out.print("pub const {} = ", .{std.zig.fmtId(@typeName(T))});
317 try out.appendNTimes(gpa, ' ', indent);
318 try out.print(gpa, "pub const {f} = ", .{std.zig.fmtId(@typeName(T))});
300319
301320 switch (val.layout) {
302 .@"extern" => try out.writeAll("extern struct"),
303 .@"packed" => try out.writeAll("packed struct"),
304 else => try out.writeAll("struct"),
321 .@"extern" => try out.appendSlice(gpa, "extern struct"),
322 .@"packed" => try out.appendSlice(gpa, "packed struct"),
323 else => try out.appendSlice(gpa, "struct"),
305324 }
306325
307 try out.writeAll(" {\n");
326 try out.appendSlice(gpa, " {\n");
308327
309328 inline for (val.fields) |field| {
310 try out.writeByteNTimes(' ', indent);
329 try out.appendNTimes(gpa, ' ', indent);
311330
312331 const type_name = @typeName(field.type);
313332
314333 // If the type name doesn't contains a '.' the type is from zig builtins.
315334 if (std.mem.containsAtLeast(u8, type_name, 1, ".")) {
316 try out.print(" {p_}: {}", .{ std.zig.fmtId(field.name), std.zig.fmtId(type_name) });
335 try out.print(gpa, " {f}: {f}", .{
336 std.zig.fmtIdFlags(field.name, .{ .allow_underscore = true, .allow_primitive = true }),
337 std.zig.fmtId(type_name),
338 });
317339 } else {
318 try out.print(" {p_}: {s}", .{ std.zig.fmtId(field.name), type_name });
340 try out.print(gpa, " {f}: {s}", .{
341 std.zig.fmtIdFlags(field.name, .{ .allow_underscore = true, .allow_primitive = true }),
342 type_name,
343 });
319344 }
320345
321346 if (field.defaultValue()) |default_value| {
322 try out.writeAll(" = ");
347 try out.appendSlice(gpa, " = ");
323348 switch (@typeInfo(@TypeOf(default_value))) {
324 .@"enum" => try out.print(".{s},\n", .{@tagName(default_value)}),
349 .@"enum" => try out.print(gpa, ".{s},\n", .{@tagName(default_value)}),
325350 .@"struct" => |info| {
326351 try printStructValue(options, out, info, default_value, indent + 4);
327352 },
328353 else => try printType(options, out, @TypeOf(default_value), default_value, indent, null),
329354 }
330355 } else {
331 try out.writeAll(",\n");
356 try out.appendSlice(gpa, ",\n");
332357 }
333358 }
334359
335360 // TODO: write declarations
336361
337 try out.writeByteNTimes(' ', indent);
338 try out.writeAll("};\n");
362 try out.appendNTimes(gpa, ' ', indent);
363 try out.appendSlice(gpa, "};\n");
339364
340365 inline for (val.fields) |field| {
341366 try printUserDefinedType(options, out, field.type, 0);
342367 }
343368}
344369
345fn printStructValue(options: *Options, out: anytype, comptime struct_val: std.builtin.Type.Struct, val: anytype, indent: u8) !void {
346 try out.writeAll(".{\n");
370fn printStructValue(
371 options: *Options,
372 out: *std.ArrayListUnmanaged(u8),
373 comptime struct_val: std.builtin.Type.Struct,
374 val: anytype,
375 indent: u8,
376) !void {
377 const gpa = options.step.owner.allocator;
378 try out.appendSlice(gpa, ".{\n");
347379
348380 if (struct_val.is_tuple) {
349381 inline for (struct_val.fields) |field| {
350 try out.writeByteNTimes(' ', indent);
382 try out.appendNTimes(gpa, ' ', indent);
351383 try printType(options, out, @TypeOf(@field(val, field.name)), @field(val, field.name), indent, null);
352384 }
353385 } else {
354386 inline for (struct_val.fields) |field| {
355 try out.writeByteNTimes(' ', indent);
356 try out.print(" .{p_} = ", .{std.zig.fmtId(field.name)});
387 try out.appendNTimes(gpa, ' ', indent);
388 try out.print(gpa, " .{f} = ", .{
389 std.zig.fmtIdFlags(field.name, .{ .allow_primitive = true, .allow_underscore = true }),
390 });
357391
358392 const field_name = @field(val, field.name);
359393 switch (@typeInfo(@TypeOf(field_name))) {
360 .@"enum" => try out.print(".{s},\n", .{@tagName(field_name)}),
394 .@"enum" => try out.print(gpa, ".{s},\n", .{@tagName(field_name)}),
361395 .@"struct" => |struct_info| {
362396 try printStructValue(options, out, struct_info, field_name, indent + 4);
363397 },
......@@ -367,10 +401,10 @@ fn printStructValue(options: *Options, out: anytype, comptime struct_val: std.bu
367401 }
368402
369403 if (indent == 0) {
370 try out.writeAll("};\n");
404 try out.appendSlice(gpa, "};\n");
371405 } else {
372 try out.writeByteNTimes(' ', indent);
373 try out.writeAll("},\n");
406 try out.appendNTimes(gpa, ' ', indent);
407 try out.appendSlice(gpa, "},\n");
374408 }
375409}
376410
......@@ -381,7 +415,8 @@ pub fn addOptionPath(
381415 name: []const u8,
382416 path: LazyPath,
383417) void {
384 options.args.append(.{
418 const arena = options.step.owner.allocator;
419 options.args.append(arena, .{
385420 .name = options.step.owner.dupe(name),
386421 .path = path.dupe(options.step.owner),
387422 }) catch @panic("OOM");
......@@ -440,7 +475,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
440475 error.FileNotFound => {
441476 const sub_dirname = fs.path.dirname(sub_path).?;
442477 b.cache_root.handle.makePath(sub_dirname) catch |e| {
443 return step.fail("unable to make path '{}{s}': {s}", .{
478 return step.fail("unable to make path '{f}{s}': {s}", .{
444479 b.cache_root, sub_dirname, @errorName(e),
445480 });
446481 };
......@@ -452,13 +487,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
452487 const tmp_sub_path_dirname = fs.path.dirname(tmp_sub_path).?;
453488
454489 b.cache_root.handle.makePath(tmp_sub_path_dirname) catch |err| {
455 return step.fail("unable to make temporary directory '{}{s}': {s}", .{
490 return step.fail("unable to make temporary directory '{f}{s}': {s}", .{
456491 b.cache_root, tmp_sub_path_dirname, @errorName(err),
457492 });
458493 };
459494
460495 b.cache_root.handle.writeFile(.{ .sub_path = tmp_sub_path, .data = options.contents.items }) catch |err| {
461 return step.fail("unable to write options to '{}{s}': {s}", .{
496 return step.fail("unable to write options to '{f}{s}': {s}", .{
462497 b.cache_root, tmp_sub_path, @errorName(err),
463498 });
464499 };
......@@ -467,7 +502,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
467502 error.PathAlreadyExists => {
468503 // Other process beat us to it. Clean up the temp file.
469504 b.cache_root.handle.deleteFile(tmp_sub_path) catch |e| {
470 try step.addError("warning: unable to delete temp file '{}{s}': {s}", .{
505 try step.addError("warning: unable to delete temp file '{f}{s}': {s}", .{
471506 b.cache_root, tmp_sub_path, @errorName(e),
472507 });
473508 };
......@@ -475,7 +510,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
475510 return;
476511 },
477512 else => {
478 return step.fail("unable to rename options from '{}{s}' to '{}{s}': {s}", .{
513 return step.fail("unable to rename options from '{f}{s}' to '{f}{s}': {s}", .{
479514 b.cache_root, tmp_sub_path,
480515 b.cache_root, sub_path,
481516 @errorName(err),
......@@ -483,7 +518,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
483518 },
484519 };
485520 },
486 else => |e| return step.fail("unable to access options file '{}{s}': {s}", .{
521 else => |e| return step.fail("unable to access options file '{f}{s}': {s}", .{
487522 b.cache_root, sub_path, @errorName(e),
488523 }),
489524 }
......@@ -643,5 +678,5 @@ test Options {
643678 \\
644679 , options.contents.items);
645680
646 _ = try std.zig.Ast.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(0), .zig);
681 _ = try std.zig.Ast.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(arena.allocator(), 0), .zig);
647682}
lib/std/Build/Step/Run.zig+19-26
......@@ -832,7 +832,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
832832 else => unreachable,
833833 };
834834 b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {
835 return step.fail("unable to make path '{}{s}': {s}", .{
835 return step.fail("unable to make path '{f}{s}': {s}", .{
836836 b.cache_root, output_sub_dir_path, @errorName(err),
837837 });
838838 };
......@@ -864,7 +864,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
864864 else => unreachable,
865865 };
866866 b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {
867 return step.fail("unable to make path '{}{s}': {s}", .{
867 return step.fail("unable to make path '{f}{s}': {s}", .{
868868 b.cache_root, output_sub_dir_path, @errorName(err),
869869 });
870870 };
......@@ -903,21 +903,21 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
903903 b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |err| {
904904 if (err == error.PathAlreadyExists) {
905905 b.cache_root.handle.deleteTree(o_sub_path) catch |del_err| {
906 return step.fail("unable to remove dir '{}'{s}: {s}", .{
906 return step.fail("unable to remove dir '{f}'{s}: {s}", .{
907907 b.cache_root,
908908 tmp_dir_path,
909909 @errorName(del_err),
910910 });
911911 };
912912 b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |retry_err| {
913 return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{
913 return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {s}", .{
914914 b.cache_root, tmp_dir_path,
915915 b.cache_root, o_sub_path,
916916 @errorName(retry_err),
917917 });
918918 };
919919 } else {
920 return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{
920 return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {s}", .{
921921 b.cache_root, tmp_dir_path,
922922 b.cache_root, o_sub_path,
923923 @errorName(err),
......@@ -964,7 +964,7 @@ pub fn rerunInFuzzMode(
964964 .artifact => |pa| {
965965 const artifact = pa.artifact;
966966 const file_path: []const u8 = p: {
967 if (artifact == run.producer.?) break :p b.fmt("{}", .{run.rebuilt_executable.?});
967 if (artifact == run.producer.?) break :p b.fmt("{f}", .{run.rebuilt_executable.?});
968968 break :p artifact.installed_path orelse artifact.generated_bin.?.path.?;
969969 };
970970 try argv_list.append(arena, b.fmt("{s}{s}", .{
......@@ -1011,24 +1011,17 @@ fn populateGeneratedPaths(
10111011 }
10121012}
10131013
1014fn formatTerm(
1015 term: ?std.process.Child.Term,
1016 comptime fmt: []const u8,
1017 options: std.fmt.FormatOptions,
1018 writer: anytype,
1019) !void {
1020 _ = fmt;
1021 _ = options;
1014fn formatTerm(term: ?std.process.Child.Term, w: *std.io.Writer) std.io.Writer.Error!void {
10221015 if (term) |t| switch (t) {
1023 .Exited => |code| try writer.print("exited with code {}", .{code}),
1024 .Signal => |sig| try writer.print("terminated with signal {}", .{sig}),
1025 .Stopped => |sig| try writer.print("stopped with signal {}", .{sig}),
1026 .Unknown => |code| try writer.print("terminated for unknown reason with code {}", .{code}),
1016 .Exited => |code| try w.print("exited with code {d}", .{code}),
1017 .Signal => |sig| try w.print("terminated with signal {d}", .{sig}),
1018 .Stopped => |sig| try w.print("stopped with signal {d}", .{sig}),
1019 .Unknown => |code| try w.print("terminated for unknown reason with code {d}", .{code}),
10271020 } else {
1028 try writer.writeAll("exited with any code");
1021 try w.writeAll("exited with any code");
10291022 }
10301023}
1031fn fmtTerm(term: ?std.process.Child.Term) std.fmt.Formatter(formatTerm) {
1024fn fmtTerm(term: ?std.process.Child.Term) std.fmt.Formatter(?std.process.Child.Term, formatTerm) {
10321025 return .{ .data = term };
10331026}
10341027
......@@ -1262,12 +1255,12 @@ fn runCommand(
12621255 const sub_path = b.pathJoin(&output_components);
12631256 const sub_path_dirname = fs.path.dirname(sub_path).?;
12641257 b.cache_root.handle.makePath(sub_path_dirname) catch |err| {
1265 return step.fail("unable to make path '{}{s}': {s}", .{
1258 return step.fail("unable to make path '{f}{s}': {s}", .{
12661259 b.cache_root, sub_path_dirname, @errorName(err),
12671260 });
12681261 };
12691262 b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = stream.bytes.? }) catch |err| {
1270 return step.fail("unable to write file '{}{s}': {s}", .{
1263 return step.fail("unable to write file '{f}{s}': {s}", .{
12711264 b.cache_root, sub_path, @errorName(err),
12721265 });
12731266 };
......@@ -1346,7 +1339,7 @@ fn runCommand(
13461339 },
13471340 .expect_term => |expected_term| {
13481341 if (!termMatches(expected_term, result.term)) {
1349 return step.fail("the following command {} (expected {}):\n{s}", .{
1342 return step.fail("the following command {f} (expected {f}):\n{s}", .{
13501343 fmtTerm(result.term),
13511344 fmtTerm(expected_term),
13521345 try Step.allocPrintCmd(arena, cwd, final_argv),
......@@ -1366,7 +1359,7 @@ fn runCommand(
13661359 };
13671360 const expected_term: std.process.Child.Term = .{ .Exited = 0 };
13681361 if (!termMatches(expected_term, result.term)) {
1369 return step.fail("{s}the following command {} (expected {}):\n{s}", .{
1362 return step.fail("{s}the following command {f} (expected {f}):\n{s}", .{
13701363 prefix,
13711364 fmtTerm(result.term),
13721365 fmtTerm(expected_term),
......@@ -1797,10 +1790,10 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {
17971790 stdout_bytes = try poller.fifo(.stdout).toOwnedSlice();
17981791 stderr_bytes = try poller.fifo(.stderr).toOwnedSlice();
17991792 } else {
1800 stdout_bytes = try stdout.reader().readAllAlloc(arena, run.max_stdio_size);
1793 stdout_bytes = try stdout.deprecatedReader().readAllAlloc(arena, run.max_stdio_size);
18011794 }
18021795 } else if (child.stderr) |stderr| {
1803 stderr_bytes = try stderr.reader().readAllAlloc(arena, run.max_stdio_size);
1796 stderr_bytes = try stderr.deprecatedReader().readAllAlloc(arena, run.max_stdio_size);
18041797 }
18051798
18061799 if (stderr_bytes) |bytes| if (bytes.len > 0) {
lib/std/Build/Step/UpdateSourceFiles.zig+3-3
......@@ -76,7 +76,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
7676 for (usf.output_source_files.items) |output_source_file| {
7777 if (fs.path.dirname(output_source_file.sub_path)) |dirname| {
7878 b.build_root.handle.makePath(dirname) catch |err| {
79 return step.fail("unable to make path '{}{s}': {s}", .{
79 return step.fail("unable to make path '{f}{s}': {s}", .{
8080 b.build_root, dirname, @errorName(err),
8181 });
8282 };
......@@ -84,7 +84,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
8484 switch (output_source_file.contents) {
8585 .bytes => |bytes| {
8686 b.build_root.handle.writeFile(.{ .sub_path = output_source_file.sub_path, .data = bytes }) catch |err| {
87 return step.fail("unable to write file '{}{s}': {s}", .{
87 return step.fail("unable to write file '{f}{s}': {s}", .{
8888 b.build_root, output_source_file.sub_path, @errorName(err),
8989 });
9090 };
......@@ -101,7 +101,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
101101 output_source_file.sub_path,
102102 .{},
103103 ) catch |err| {
104 return step.fail("unable to update file from '{s}' to '{}{s}': {s}", .{
104 return step.fail("unable to update file from '{s}' to '{f}{s}': {s}", .{
105105 source_path, b.build_root, output_source_file.sub_path, @errorName(err),
106106 });
107107 };
lib/std/Build/Step/WriteFile.zig+7-7
......@@ -217,7 +217,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
217217 const src_dir_path = dir.source.getPath3(b, step);
218218
219219 var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| {
220 return step.fail("unable to open source directory '{}': {s}", .{
220 return step.fail("unable to open source directory '{f}': {s}", .{
221221 src_dir_path, @errorName(err),
222222 });
223223 };
......@@ -258,7 +258,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
258258 write_file.generated_directory.path = try b.cache_root.join(arena, &.{ "o", &digest });
259259
260260 var cache_dir = b.cache_root.handle.makeOpenPath(cache_path, .{}) catch |err| {
261 return step.fail("unable to make path '{}{s}': {s}", .{
261 return step.fail("unable to make path '{f}{s}': {s}", .{
262262 b.cache_root, cache_path, @errorName(err),
263263 });
264264 };
......@@ -269,7 +269,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
269269 for (write_file.files.items) |file| {
270270 if (fs.path.dirname(file.sub_path)) |dirname| {
271271 cache_dir.makePath(dirname) catch |err| {
272 return step.fail("unable to make path '{}{s}{c}{s}': {s}", .{
272 return step.fail("unable to make path '{f}{s}{c}{s}': {s}", .{
273273 b.cache_root, cache_path, fs.path.sep, dirname, @errorName(err),
274274 });
275275 };
......@@ -277,7 +277,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
277277 switch (file.contents) {
278278 .bytes => |bytes| {
279279 cache_dir.writeFile(.{ .sub_path = file.sub_path, .data = bytes }) catch |err| {
280 return step.fail("unable to write file '{}{s}{c}{s}': {s}", .{
280 return step.fail("unable to write file '{f}{s}{c}{s}': {s}", .{
281281 b.cache_root, cache_path, fs.path.sep, file.sub_path, @errorName(err),
282282 });
283283 };
......@@ -291,7 +291,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
291291 file.sub_path,
292292 .{},
293293 ) catch |err| {
294 return step.fail("unable to update file from '{s}' to '{}{s}{c}{s}': {s}", .{
294 return step.fail("unable to update file from '{s}' to '{f}{s}{c}{s}': {s}", .{
295295 source_path,
296296 b.cache_root,
297297 cache_path,
......@@ -315,7 +315,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
315315
316316 if (dest_dirname.len != 0) {
317317 cache_dir.makePath(dest_dirname) catch |err| {
318 return step.fail("unable to make path '{}{s}{c}{s}': {s}", .{
318 return step.fail("unable to make path '{f}{s}{c}{s}': {s}", .{
319319 b.cache_root, cache_path, fs.path.sep, dest_dirname, @errorName(err),
320320 });
321321 };
......@@ -338,7 +338,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
338338 dest_path,
339339 .{},
340340 ) catch |err| {
341 return step.fail("unable to update file from '{}' to '{}{s}{c}{s}': {s}", .{
341 return step.fail("unable to update file from '{f}' to '{f}{s}{c}{s}': {s}", .{
342342 src_entry_path, b.cache_root, cache_path, fs.path.sep, dest_path, @errorName(err),
343343 });
344344 };
lib/std/Build/Watch.zig+3-3
......@@ -211,7 +211,7 @@ const Os = switch (builtin.os.tag) {
211211 .ADD = true,
212212 .ONLYDIR = true,
213213 }, fan_mask, path.root_dir.handle.fd, path.subPathOrDot()) catch |err| {
214 fatal("unable to watch {}: {s}", .{ path, @errorName(err) });
214 fatal("unable to watch {f}: {s}", .{ path, @errorName(err) });
215215 };
216216 }
217217 break :rs &dh_gop.value_ptr.reaction_set;
......@@ -265,7 +265,7 @@ const Os = switch (builtin.os.tag) {
265265 .ONLYDIR = true,
266266 }, fan_mask, path.root_dir.handle.fd, path.subPathOrDot()) catch |err| switch (err) {
267267 error.FileNotFound => {}, // Expected, harmless.
268 else => |e| std.log.warn("unable to unwatch '{}': {s}", .{ path, @errorName(e) }),
268 else => |e| std.log.warn("unable to unwatch '{f}': {s}", .{ path, @errorName(e) }),
269269 };
270270
271271 w.dir_table.swapRemoveAt(i);
......@@ -659,7 +659,7 @@ const Os = switch (builtin.os.tag) {
659659 path.root_dir.handle.fd
660660 else
661661 posix.openat(path.root_dir.handle.fd, path.sub_path, dir_open_flags, 0) catch |err| {
662 fatal("failed to open directory {}: {s}", .{ path, @errorName(err) });
662 fatal("failed to open directory {f}: {s}", .{ path, @errorName(err) });
663663 };
664664 // Empirically the dir has to stay open or else no events are triggered.
665665 errdefer if (!skip_open_dir) posix.close(dir_fd);
lib/std/Progress.zig+32-1
......@@ -9,6 +9,7 @@ const Progress = @This();
99const posix = std.posix;
1010const is_big_endian = builtin.cpu.arch.endian() == .big;
1111const is_windows = builtin.os.tag == .windows;
12const Writer = std.io.Writer;
1213
1314/// `null` if the current node (and its children) should
1415/// not print on update()
......@@ -451,7 +452,7 @@ pub fn start(options: Options) Node {
451452 if (options.disable_printing) {
452453 return Node.none;
453454 }
454 const stderr = std.io.getStdErr();
455 const stderr: std.fs.File = .stderr();
455456 global_progress.terminal = stderr;
456457 if (stderr.getOrEnableAnsiEscapeSupport()) {
457458 global_progress.terminal_mode = .ansi_escape_codes;
......@@ -606,6 +607,36 @@ pub fn unlockStdErr() void {
606607 stderr_mutex.unlock();
607608}
608609
610/// Protected by `stderr_mutex`.
611const stderr_writer: *Writer = &stderr_file_writer.interface;
612/// Protected by `stderr_mutex`.
613var stderr_file_writer: std.fs.File.Writer = .{
614 .interface = std.fs.File.Writer.initInterface(&.{}),
615 .file = if (is_windows) undefined else .stderr(),
616 .mode = .streaming,
617};
618
619/// Allows the caller to freely write to the returned `Writer`,
620/// initialized with `buffer`, until `unlockStderrWriter` is called.
621///
622/// During the lock, any `std.Progress` information is cleared from the terminal.
623///
624/// The lock is recursive; the same thread may hold the lock multiple times.
625pub fn lockStderrWriter(buffer: []u8) *Writer {
626 stderr_mutex.lock();
627 clearWrittenWithEscapeCodes() catch {};
628 if (is_windows) stderr_file_writer.file = .stderr();
629 stderr_writer.flush() catch {};
630 stderr_writer.buffer = buffer;
631 return stderr_writer;
632}
633
634pub fn unlockStderrWriter() void {
635 stderr_writer.flush() catch {};
636 stderr_writer.buffer = &.{};
637 stderr_mutex.unlock();
638}
639
609640fn ipcThreadRun(fd: posix.fd_t) anyerror!void {
610641 // Store this data in the thread so that it does not need to be part of the
611642 // linker data of the main executable.
lib/std/Random/benchmark.zig+1-1
......@@ -122,7 +122,7 @@ fn mode(comptime x: comptime_int) comptime_int {
122122}
123123
124124pub fn main() !void {
125 const stdout = std.io.getStdOut().writer();
125 const stdout = std.fs.File.stdout().deprecatedWriter();
126126
127127 var buffer: [1024]u8 = undefined;
128128 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
lib/std/SemanticVersion.zig+7-14
......@@ -150,17 +150,10 @@ fn parseNum(text: []const u8) error{ InvalidVersion, Overflow }!usize {
150150 };
151151}
152152
153pub fn format(
154 self: Version,
155 comptime fmt: []const u8,
156 options: std.fmt.FormatOptions,
157 out_stream: anytype,
158) !void {
159 _ = options;
160 if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
161 try std.fmt.format(out_stream, "{d}.{d}.{d}", .{ self.major, self.minor, self.patch });
162 if (self.pre) |pre| try std.fmt.format(out_stream, "-{s}", .{pre});
163 if (self.build) |build| try std.fmt.format(out_stream, "+{s}", .{build});
153pub fn format(self: Version, w: *std.io.Writer) std.io.Writer.Error!void {
154 try w.print("{d}.{d}.{d}", .{ self.major, self.minor, self.patch });
155 if (self.pre) |pre| try w.print("-{s}", .{pre});
156 if (self.build) |build| try w.print("+{s}", .{build});
164157}
165158
166159const expect = std.testing.expect;
......@@ -202,7 +195,7 @@ test format {
202195 "1.0.0+0.build.1-rc.10000aaa-kk-0.1",
203196 "5.4.0-1018-raspi",
204197 "5.7.123",
205 }) |valid| try std.testing.expectFmt(valid, "{}", .{try parse(valid)});
198 }) |valid| try std.testing.expectFmt(valid, "{f}", .{try parse(valid)});
206199
207200 // Invalid version strings should be rejected.
208201 for ([_][]const u8{
......@@ -269,12 +262,12 @@ test format {
269262 // Valid version string that may overflow.
270263 const big_valid = "99999999999999999999999.999999999999999999.99999999999999999";
271264 if (parse(big_valid)) |ver| {
272 try std.testing.expectFmt(big_valid, "{}", .{ver});
265 try std.testing.expectFmt(big_valid, "{f}", .{ver});
273266 } else |err| try expect(err == error.Overflow);
274267
275268 // Invalid version string that may overflow.
276269 const big_invalid = "99999999999999999999999.999999999999999999.99999999999999999----RC-SNAPSHOT.12.09.1--------------------------------..12";
277 if (parse(big_invalid)) |ver| std.debug.panic("expected error, found {}", .{ver}) else |_| {}
270 if (parse(big_invalid)) |ver| std.debug.panic("expected error, found {f}", .{ver}) else |_| {}
278271}
279272
280273test "precedence" {
lib/std/Target.zig+7-23
......@@ -301,29 +301,13 @@ pub const Os = struct {
301301
302302 /// This function is defined to serialize a Zig source code representation of this
303303 /// type, that, when parsed, will deserialize into the same data.
304 pub fn format(
305 ver: WindowsVersion,
306 comptime fmt_str: []const u8,
307 _: std.fmt.FormatOptions,
308 writer: anytype,
309 ) @TypeOf(writer).Error!void {
310 const maybe_name = std.enums.tagName(WindowsVersion, ver);
311 if (comptime std.mem.eql(u8, fmt_str, "s")) {
312 if (maybe_name) |name|
313 try writer.print(".{s}", .{name})
314 else
315 try writer.print(".{d}", .{@intFromEnum(ver)});
316 } else if (comptime std.mem.eql(u8, fmt_str, "c")) {
317 if (maybe_name) |name|
318 try writer.print(".{s}", .{name})
319 else
320 try writer.print("@enumFromInt(0x{X:0>8})", .{@intFromEnum(ver)});
321 } else if (fmt_str.len == 0) {
322 if (maybe_name) |name|
323 try writer.print("WindowsVersion.{s}", .{name})
324 else
325 try writer.print("WindowsVersion(0x{X:0>8})", .{@intFromEnum(ver)});
326 } else std.fmt.invalidFmtError(fmt_str, ver);
304 pub fn format(wv: WindowsVersion, w: *std.io.Writer) std.io.Writer.Error!void {
305 if (std.enums.tagName(WindowsVersion, wv)) |name| {
306 var vecs: [2][]const u8 = .{ ".", name };
307 return w.writeVecAll(&vecs);
308 } else {
309 return w.print("@enumFromInt(0x{X:0>8})", .{wv});
310 }
327311 }
328312 };
329313
lib/std/Target/Query.zig+20-21
......@@ -394,25 +394,24 @@ pub fn canDetectLibC(self: Query) bool {
394394
395395/// Formats a version with the patch component omitted if it is zero,
396396/// unlike SemanticVersion.format which formats all its version components regardless.
397fn formatVersion(version: SemanticVersion, writer: anytype) !void {
397fn formatVersion(version: SemanticVersion, gpa: Allocator, list: *std.ArrayListUnmanaged(u8)) !void {
398398 if (version.patch == 0) {
399 try writer.print("{d}.{d}", .{ version.major, version.minor });
399 try list.print(gpa, "{d}.{d}", .{ version.major, version.minor });
400400 } else {
401 try writer.print("{d}.{d}.{d}", .{ version.major, version.minor, version.patch });
401 try list.print(gpa, "{d}.{d}.{d}", .{ version.major, version.minor, version.patch });
402402 }
403403}
404404
405pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 {
406 if (self.isNativeTriple())
407 return allocator.dupe(u8, "native");
405pub fn zigTriple(self: Query, gpa: Allocator) Allocator.Error![]u8 {
406 if (self.isNativeTriple()) return gpa.dupe(u8, "native");
408407
409408 const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native";
410409 const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native";
411410
412 var result = std.ArrayList(u8).init(allocator);
413 defer result.deinit();
411 var result: std.ArrayListUnmanaged(u8) = .empty;
412 defer result.deinit(gpa);
414413
415 try result.writer().print("{s}-{s}", .{ arch_name, os_name });
414 try result.print(gpa, "{s}-{s}", .{ arch_name, os_name });
416415
417416 // The zig target syntax does not allow specifying a max os version with no min, so
418417 // if either are present, we need the min.
......@@ -420,11 +419,11 @@ pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 {
420419 switch (min) {
421420 .none => {},
422421 .semver => |v| {
423 try result.writer().writeAll(".");
424 try formatVersion(v, result.writer());
422 try result.appendSlice(gpa, ".");
423 try formatVersion(v, gpa, &result);
425424 },
426425 .windows => |v| {
427 try result.writer().print("{s}", .{v});
426 try result.print(gpa, "{d}", .{v});
428427 },
429428 }
430429 }
......@@ -432,39 +431,39 @@ pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 {
432431 switch (max) {
433432 .none => {},
434433 .semver => |v| {
435 try result.writer().writeAll("...");
436 try formatVersion(v, result.writer());
434 try result.appendSlice(gpa, "...");
435 try formatVersion(v, gpa, &result);
437436 },
438437 .windows => |v| {
439438 // This is counting on a custom format() function defined on `WindowsVersion`
440439 // to add a prefix '.' and make there be a total of three dots.
441 try result.writer().print("..{s}", .{v});
440 try result.print(gpa, "..{d}", .{v});
442441 },
443442 }
444443 }
445444
446445 if (self.glibc_version) |v| {
447446 const name = if (self.abi) |abi| @tagName(abi) else "gnu";
448 try result.ensureUnusedCapacity(name.len + 2);
447 try result.ensureUnusedCapacity(gpa, name.len + 2);
449448 result.appendAssumeCapacity('-');
450449 result.appendSliceAssumeCapacity(name);
451450 result.appendAssumeCapacity('.');
452 try formatVersion(v, result.writer());
451 try formatVersion(v, gpa, &result);
453452 } else if (self.android_api_level) |lvl| {
454453 const name = if (self.abi) |abi| @tagName(abi) else "android";
455 try result.ensureUnusedCapacity(name.len + 2);
454 try result.ensureUnusedCapacity(gpa, name.len + 2);
456455 result.appendAssumeCapacity('-');
457456 result.appendSliceAssumeCapacity(name);
458457 result.appendAssumeCapacity('.');
459 try result.writer().print("{d}", .{lvl});
458 try result.print(gpa, "{d}", .{lvl});
460459 } else if (self.abi) |abi| {
461460 const name = @tagName(abi);
462 try result.ensureUnusedCapacity(name.len + 1);
461 try result.ensureUnusedCapacity(gpa, name.len + 1);
463462 result.appendAssumeCapacity('-');
464463 result.appendSliceAssumeCapacity(name);
465464 }
466465
467 return result.toOwnedSlice();
466 return result.toOwnedSlice(gpa);
468467}
469468
470469/// Renders the query into a textual representation that can be parsed via the
lib/std/Thread.zig+3-3
......@@ -167,7 +167,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
167167 const file = try std.fs.cwd().openFile(path, .{ .mode = .write_only });
168168 defer file.close();
169169
170 try file.writer().writeAll(name);
170 try file.deprecatedWriter().writeAll(name);
171171 return;
172172 },
173173 .windows => {
......@@ -281,7 +281,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
281281 const file = try std.fs.cwd().openFile(path, .{});
282282 defer file.close();
283283
284 const data_len = try file.reader().readAll(buffer_ptr[0 .. max_name_len + 1]);
284 const data_len = try file.deprecatedReader().readAll(buffer_ptr[0 .. max_name_len + 1]);
285285
286286 return if (data_len >= 1) buffer[0 .. data_len - 1] else null;
287287 },
......@@ -1163,7 +1163,7 @@ const LinuxThreadImpl = struct {
11631163
11641164 fn getCurrentId() Id {
11651165 return tls_thread_id orelse {
1166 const tid = @as(u32, @bitCast(linux.gettid()));
1166 const tid: u32 = @bitCast(linux.gettid());
11671167 tls_thread_id = tid;
11681168 return tid;
11691169 };
lib/std/Uri.zig+153-129
......@@ -1,6 +1,10 @@
11//! Uniform Resource Identifier (URI) parsing roughly adhering to <https://tools.ietf.org/html/rfc3986>.
22//! Does not do perfect grammar and character class checking, but should be robust against URIs in the wild.
33
4const std = @import("std.zig");
5const testing = std.testing;
6const Uri = @This();
7
48scheme: []const u8,
59user: ?Component = null,
610password: ?Component = null,
......@@ -34,27 +38,15 @@ pub const Component = union(enum) {
3438 return switch (component) {
3539 .raw => |raw| raw,
3640 .percent_encoded => |percent_encoded| if (std.mem.indexOfScalar(u8, percent_encoded, '%')) |_|
37 try std.fmt.allocPrint(arena, "{raw}", .{component})
41 try std.fmt.allocPrint(arena, "{f}", .{std.fmt.alt(component, .formatRaw)})
3842 else
3943 percent_encoded,
4044 };
4145 }
4246
43 pub fn format(
44 component: Component,
45 comptime fmt_str: []const u8,
46 _: std.fmt.FormatOptions,
47 writer: anytype,
48 ) @TypeOf(writer).Error!void {
49 if (fmt_str.len == 0) {
50 try writer.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{
51 @tagName(component),
52 std.zig.fmtEscapes(switch (component) {
53 .raw, .percent_encoded => |string| string,
54 }),
55 });
56 } else if (comptime std.mem.eql(u8, fmt_str, "raw")) switch (component) {
57 .raw => |raw| try writer.writeAll(raw),
47 pub fn formatRaw(component: Component, w: *std.io.Writer) std.io.Writer.Error!void {
48 switch (component) {
49 .raw => |raw| try w.writeAll(raw),
5850 .percent_encoded => |percent_encoded| {
5951 var start: usize = 0;
6052 var index: usize = 0;
......@@ -63,51 +55,75 @@ pub const Component = union(enum) {
6355 if (percent_encoded.len - index < 2) continue;
6456 const percent_encoded_char =
6557 std.fmt.parseInt(u8, percent_encoded[index..][0..2], 16) catch continue;
66 try writer.print("{s}{c}", .{
58 try w.print("{s}{c}", .{
6759 percent_encoded[start..percent],
6860 percent_encoded_char,
6961 });
7062 start = percent + 3;
7163 index = percent + 3;
7264 }
73 try writer.writeAll(percent_encoded[start..]);
65 try w.writeAll(percent_encoded[start..]);
7466 },
75 } else if (comptime std.mem.eql(u8, fmt_str, "%")) switch (component) {
76 .raw => |raw| try percentEncode(writer, raw, isUnreserved),
77 .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
78 } else if (comptime std.mem.eql(u8, fmt_str, "user")) switch (component) {
79 .raw => |raw| try percentEncode(writer, raw, isUserChar),
80 .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
81 } else if (comptime std.mem.eql(u8, fmt_str, "password")) switch (component) {
82 .raw => |raw| try percentEncode(writer, raw, isPasswordChar),
83 .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
84 } else if (comptime std.mem.eql(u8, fmt_str, "host")) switch (component) {
85 .raw => |raw| try percentEncode(writer, raw, isHostChar),
86 .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
87 } else if (comptime std.mem.eql(u8, fmt_str, "path")) switch (component) {
88 .raw => |raw| try percentEncode(writer, raw, isPathChar),
89 .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
90 } else if (comptime std.mem.eql(u8, fmt_str, "query")) switch (component) {
91 .raw => |raw| try percentEncode(writer, raw, isQueryChar),
92 .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
93 } else if (comptime std.mem.eql(u8, fmt_str, "fragment")) switch (component) {
94 .raw => |raw| try percentEncode(writer, raw, isFragmentChar),
95 .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded),
96 } else @compileError("invalid format string '" ++ fmt_str ++ "'");
97 }
98
99 pub fn percentEncode(
100 writer: anytype,
101 raw: []const u8,
102 comptime isValidChar: fn (u8) bool,
103 ) @TypeOf(writer).Error!void {
67 }
68 }
69
70 pub fn formatEscaped(component: Component, w: *std.io.Writer) std.io.Writer.Error!void {
71 switch (component) {
72 .raw => |raw| try percentEncode(w, raw, isUnreserved),
73 .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
74 }
75 }
76
77 pub fn formatUser(component: Component, w: *std.io.Writer) std.io.Writer.Error!void {
78 switch (component) {
79 .raw => |raw| try percentEncode(w, raw, isUserChar),
80 .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
81 }
82 }
83
84 pub fn formatPassword(component: Component, w: *std.io.Writer) std.io.Writer.Error!void {
85 switch (component) {
86 .raw => |raw| try percentEncode(w, raw, isPasswordChar),
87 .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
88 }
89 }
90
91 pub fn formatHost(component: Component, w: *std.io.Writer) std.io.Writer.Error!void {
92 switch (component) {
93 .raw => |raw| try percentEncode(w, raw, isHostChar),
94 .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
95 }
96 }
97
98 pub fn formatPath(component: Component, w: *std.io.Writer) std.io.Writer.Error!void {
99 switch (component) {
100 .raw => |raw| try percentEncode(w, raw, isPathChar),
101 .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
102 }
103 }
104
105 pub fn formatQuery(component: Component, w: *std.io.Writer) std.io.Writer.Error!void {
106 switch (component) {
107 .raw => |raw| try percentEncode(w, raw, isQueryChar),
108 .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
109 }
110 }
111
112 pub fn formatFragment(component: Component, w: *std.io.Writer) std.io.Writer.Error!void {
113 switch (component) {
114 .raw => |raw| try percentEncode(w, raw, isFragmentChar),
115 .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded),
116 }
117 }
118
119 pub fn percentEncode(w: *std.io.Writer, raw: []const u8, comptime isValidChar: fn (u8) bool) std.io.Writer.Error!void {
104120 var start: usize = 0;
105121 for (raw, 0..) |char, index| {
106122 if (isValidChar(char)) continue;
107 try writer.print("{s}%{X:0>2}", .{ raw[start..index], char });
123 try w.print("{s}%{X:0>2}", .{ raw[start..index], char });
108124 start = index + 1;
109125 }
110 try writer.writeAll(raw[start..]);
126 try w.writeAll(raw[start..]);
111127 }
112128};
113129
......@@ -224,91 +240,91 @@ pub fn parseAfterScheme(scheme: []const u8, text: []const u8) ParseError!Uri {
224240 return uri;
225241}
226242
227pub const WriteToStreamOptions = struct {
228 /// When true, include the scheme part of the URI.
229 scheme: bool = false,
230
231 /// When true, include the user and password part of the URI. Ignored if `authority` is false.
232 authentication: bool = false,
233
234 /// When true, include the authority part of the URI.
235 authority: bool = false,
236
237 /// When true, include the path part of the URI.
238 path: bool = false,
239
240 /// When true, include the query part of the URI. Ignored when `path` is false.
241 query: bool = false,
242
243 /// When true, include the fragment part of the URI. Ignored when `path` is false.
244 fragment: bool = false,
245
246 /// When true, include the port part of the URI. Ignored when `port` is null.
247 port: bool = true,
248};
243pub fn format(uri: *const Uri, writer: *std.io.Writer) std.io.Writer.Error!void {
244 return writeToStream(uri, writer, .all);
245}
249246
250pub fn writeToStream(
251 uri: Uri,
252 options: WriteToStreamOptions,
253 writer: anytype,
254) @TypeOf(writer).Error!void {
255 if (options.scheme) {
247pub fn writeToStream(uri: *const Uri, writer: *std.io.Writer, flags: Format.Flags) std.io.Writer.Error!void {
248 if (flags.scheme) {
256249 try writer.print("{s}:", .{uri.scheme});
257 if (options.authority and uri.host != null) {
250 if (flags.authority and uri.host != null) {
258251 try writer.writeAll("//");
259252 }
260253 }
261 if (options.authority) {
262 if (options.authentication and uri.host != null) {
254 if (flags.authority) {
255 if (flags.authentication and uri.host != null) {
263256 if (uri.user) |user| {
264 try writer.print("{user}", .{user});
257 try user.formatUser(writer);
265258 if (uri.password) |password| {
266 try writer.print(":{password}", .{password});
259 try writer.writeByte(':');
260 try password.formatPassword(writer);
267261 }
268262 try writer.writeByte('@');
269263 }
270264 }
271265 if (uri.host) |host| {
272 try writer.print("{host}", .{host});
273 if (options.port) {
266 try host.formatHost(writer);
267 if (flags.port) {
274268 if (uri.port) |port| try writer.print(":{d}", .{port});
275269 }
276270 }
277271 }
278 if (options.path) {
279 try writer.print("{path}", .{
280 if (uri.path.isEmpty()) Uri.Component{ .percent_encoded = "/" } else uri.path,
281 });
282 if (options.query) {
283 if (uri.query) |query| try writer.print("?{query}", .{query});
272 if (flags.path) {
273 const uri_path: Component = if (uri.path.isEmpty()) .{ .percent_encoded = "/" } else uri.path;
274 try uri_path.formatPath(writer);
275 if (flags.query) {
276 if (uri.query) |query| {
277 try writer.writeByte('?');
278 try query.formatQuery(writer);
279 }
284280 }
285 if (options.fragment) {
286 if (uri.fragment) |fragment| try writer.print("#{fragment}", .{fragment});
281 if (flags.fragment) {
282 if (uri.fragment) |fragment| {
283 try writer.writeByte('#');
284 try fragment.formatFragment(writer);
285 }
287286 }
288287 }
289288}
290289
291pub fn format(
292 uri: Uri,
293 comptime fmt_str: []const u8,
294 _: std.fmt.FormatOptions,
295 writer: anytype,
296) @TypeOf(writer).Error!void {
297 const scheme = comptime std.mem.indexOfScalar(u8, fmt_str, ';') != null or fmt_str.len == 0;
298 const authentication = comptime std.mem.indexOfScalar(u8, fmt_str, '@') != null or fmt_str.len == 0;
299 const authority = comptime std.mem.indexOfScalar(u8, fmt_str, '+') != null or fmt_str.len == 0;
300 const path = comptime std.mem.indexOfScalar(u8, fmt_str, '/') != null or fmt_str.len == 0;
301 const query = comptime std.mem.indexOfScalar(u8, fmt_str, '?') != null or fmt_str.len == 0;
302 const fragment = comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null or fmt_str.len == 0;
303
304 return writeToStream(uri, .{
305 .scheme = scheme,
306 .authentication = authentication,
307 .authority = authority,
308 .path = path,
309 .query = query,
310 .fragment = fragment,
311 }, writer);
290pub const Format = struct {
291 uri: *const Uri,
292 flags: Flags = .{},
293
294 pub const Flags = struct {
295 /// When true, include the scheme part of the URI.
296 scheme: bool = false,
297 /// When true, include the user and password part of the URI. Ignored if `authority` is false.
298 authentication: bool = false,
299 /// When true, include the authority part of the URI.
300 authority: bool = false,
301 /// When true, include the path part of the URI.
302 path: bool = false,
303 /// When true, include the query part of the URI. Ignored when `path` is false.
304 query: bool = false,
305 /// When true, include the fragment part of the URI. Ignored when `path` is false.
306 fragment: bool = false,
307 /// When true, include the port part of the URI. Ignored when `port` is null.
308 port: bool = true,
309
310 pub const all: Flags = .{
311 .scheme = true,
312 .authentication = true,
313 .authority = true,
314 .path = true,
315 .query = true,
316 .fragment = true,
317 .port = true,
318 };
319 };
320
321 pub fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
322 return writeToStream(f.uri, writer, f.flags);
323 }
324};
325
326pub fn fmt(uri: *const Uri, flags: Format.Flags) std.fmt.Formatter(Format, Format.default) {
327 return .{ .data = .{ .uri = uri, .flags = flags } };
312328}
313329
314330/// Parses the URI or returns an error.
......@@ -445,14 +461,13 @@ test remove_dot_segments {
445461
446462/// 5.2.3. Merge Paths
447463fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Component {
448 var aux = std.io.fixedBufferStream(aux_buf.*);
464 var aux: std.io.Writer = .fixed(aux_buf.*);
449465 if (!base.isEmpty()) {
450 try aux.writer().print("{path}", .{base});
451 aux.pos = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse
452 return remove_dot_segments(new);
466 base.formatPath(&aux) catch return error.NoSpaceLeft;
467 aux.end = std.mem.lastIndexOfScalar(u8, aux.buffered(), '/') orelse return remove_dot_segments(new);
453468 }
454 try aux.writer().print("/{s}", .{new});
455 const merged_path = remove_dot_segments(aux.getWritten());
469 aux.print("/{s}", .{new}) catch return error.NoSpaceLeft;
470 const merged_path = remove_dot_segments(aux.buffered());
456471 aux_buf.* = aux_buf.*[merged_path.percent_encoded.len..];
457472 return merged_path;
458473}
......@@ -812,8 +827,11 @@ test "Special test" {
812827test "URI percent encoding" {
813828 try std.testing.expectFmt(
814829 "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad",
815 "{%}",
816 .{Component{ .raw = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad" }},
830 "{f}",
831 .{std.fmt.alt(
832 @as(Component, .{ .raw = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad" }),
833 .formatEscaped,
834 )},
817835 );
818836}
819837
......@@ -822,7 +840,10 @@ test "URI percent decoding" {
822840 const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad";
823841 var input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad".*;
824842
825 try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});
843 try std.testing.expectFmt(expected, "{f}", .{std.fmt.alt(
844 @as(Component, .{ .percent_encoded = &input }),
845 .formatRaw,
846 )});
826847
827848 var output: [expected.len]u8 = undefined;
828849 try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
......@@ -834,7 +855,10 @@ test "URI percent decoding" {
834855 const expected = "/abc%";
835856 var input = expected.*;
836857
837 try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }});
858 try std.testing.expectFmt(expected, "{f}", .{std.fmt.alt(
859 @as(Component, .{ .percent_encoded = &input }),
860 .formatRaw,
861 )});
838862
839863 var output: [expected.len]u8 = undefined;
840864 try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected);
......@@ -848,7 +872,9 @@ test "URI query encoding" {
848872 const parsed = try Uri.parse(address);
849873
850874 // format the URI to percent encode it
851 try std.testing.expectFmt("/?response-content-type=application%2Foctet-stream", "{/?}", .{parsed});
875 try std.testing.expectFmt("/?response-content-type=application%2Foctet-stream", "{f}", .{
876 parsed.fmt(.{ .path = true, .query = true }),
877 });
852878}
853879
854880test "format" {
......@@ -862,7 +888,9 @@ test "format" {
862888 .query = null,
863889 .fragment = null,
864890 };
865 try std.testing.expectFmt("file:/foo/bar/baz", "{;/?#}", .{uri});
891 try std.testing.expectFmt("file:/foo/bar/baz", "{f}", .{
892 uri.fmt(.{ .scheme = true, .path = true, .query = true, .fragment = true }),
893 });
866894}
867895
868896test "URI malformed input" {
......@@ -870,7 +898,3 @@ test "URI malformed input" {
870898 try std.testing.expectError(error.InvalidFormat, std.Uri.parse("http://]@["));
871899 try std.testing.expectError(error.InvalidFormat, std.Uri.parse("http://lo]s\x85hc@[/8\x10?0Q"));
872900}
873
874const std = @import("std.zig");
875const testing = std.testing;
876const Uri = @This();
lib/std/array_list.zig+37-18
......@@ -338,11 +338,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty
338338 @memcpy(self.items[old_len..][0..items.len], items);
339339 }
340340
341 pub const Writer = if (T != u8)
342 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
343 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
344 else
345 std.io.Writer(*Self, Allocator.Error, appendWrite);
341 pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
342 const gpa = self.allocator;
343 var unmanaged = self.moveToUnmanaged();
344 defer self.* = unmanaged.toManaged(gpa);
345 try unmanaged.print(gpa, fmt, args);
346 }
347
348 pub const Writer = if (T != u8) void else std.io.GenericWriter(*Self, Allocator.Error, appendWrite);
346349
347350 /// Initializes a Writer which will append to the list.
348351 pub fn writer(self: *Self) Writer {
......@@ -350,14 +353,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty
350353 }
351354
352355 /// Same as `append` except it returns the number of bytes written, which is always the same
353 /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.
356 /// as `m.len`. The purpose of this function existing is to match `std.io.GenericWriter` API.
354357 /// Invalidates element pointers if additional memory is needed.
355358 fn appendWrite(self: *Self, m: []const u8) Allocator.Error!usize {
356359 try self.appendSlice(m);
357360 return m.len;
358361 }
359362
360 pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed);
363 pub const FixedWriter = std.io.GenericWriter(*Self, Allocator.Error, appendWriteFixed);
361364
362365 /// Initializes a Writer which will append to the list but will return
363366 /// `error.OutOfMemory` rather than increasing capacity.
......@@ -365,7 +368,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?mem.Alignment) ty
365368 return .{ .context = self };
366369 }
367370
368 /// The purpose of this function existing is to match `std.io.Writer` API.
371 /// The purpose of this function existing is to match `std.io.GenericWriter` API.
369372 fn appendWriteFixed(self: *Self, m: []const u8) error{OutOfMemory}!usize {
370373 const available_capacity = self.capacity - self.items.len;
371374 if (m.len > available_capacity)
......@@ -933,40 +936,56 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?mem.Alig
933936 @memcpy(self.items[old_len..][0..items.len], items);
934937 }
935938
939 pub fn print(self: *Self, gpa: Allocator, comptime fmt: []const u8, args: anytype) error{OutOfMemory}!void {
940 comptime assert(T == u8);
941 try self.ensureUnusedCapacity(gpa, fmt.len);
942 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, self);
943 defer self.* = aw.toArrayList();
944 return aw.writer.print(fmt, args) catch |err| switch (err) {
945 error.WriteFailed => return error.OutOfMemory,
946 };
947 }
948
949 pub fn printAssumeCapacity(self: *Self, comptime fmt: []const u8, args: anytype) void {
950 comptime assert(T == u8);
951 var w: std.io.Writer = .fixed(self.unusedCapacitySlice());
952 w.print(fmt, args) catch unreachable;
953 self.items.len += w.end;
954 }
955
956 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
936957 pub const WriterContext = struct {
937958 self: *Self,
938959 allocator: Allocator,
939960 };
940961
962 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
941963 pub const Writer = if (T != u8)
942964 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
943965 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
944966 else
945 std.io.Writer(WriterContext, Allocator.Error, appendWrite);
967 std.io.GenericWriter(WriterContext, Allocator.Error, appendWrite);
946968
947 /// Initializes a Writer which will append to the list.
969 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
948970 pub fn writer(self: *Self, gpa: Allocator) Writer {
949971 return .{ .context = .{ .self = self, .allocator = gpa } };
950972 }
951973
952 /// Same as `append` except it returns the number of bytes written,
953 /// which is always the same as `m.len`. The purpose of this function
954 /// existing is to match `std.io.Writer` API.
955 /// Invalidates element pointers if additional memory is needed.
974 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
956975 fn appendWrite(context: WriterContext, m: []const u8) Allocator.Error!usize {
957976 try context.self.appendSlice(context.allocator, m);
958977 return m.len;
959978 }
960979
961 pub const FixedWriter = std.io.Writer(*Self, Allocator.Error, appendWriteFixed);
980 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
981 pub const FixedWriter = std.io.GenericWriter(*Self, Allocator.Error, appendWriteFixed);
962982
963 /// Initializes a Writer which will append to the list but will return
964 /// `error.OutOfMemory` rather than increasing capacity.
983 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
965984 pub fn fixedWriter(self: *Self) FixedWriter {
966985 return .{ .context = self };
967986 }
968987
969 /// The purpose of this function existing is to match `std.io.Writer` API.
988 /// Deprecated in favor of `print` or `std.io.Writer.Allocating`.
970989 fn appendWriteFixed(self: *Self, m: []const u8) error{OutOfMemory}!usize {
971990 const available_capacity = self.capacity - self.items.len;
972991 if (m.len > available_capacity)
lib/std/ascii.zig+45
......@@ -10,6 +10,10 @@
1010
1111const std = @import("std");
1212
13pub const lowercase = "abcdefghijklmnopqrstuvwxyz";
14pub const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
15pub const letters = lowercase ++ uppercase;
16
1317/// The C0 control codes of the ASCII encoding.
1418///
1519/// See also: https://en.wikipedia.org/wiki/C0_and_C1_control_codes and `isControl`
......@@ -435,3 +439,44 @@ pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order {
435439pub fn lessThanIgnoreCase(lhs: []const u8, rhs: []const u8) bool {
436440 return orderIgnoreCase(lhs, rhs) == .lt;
437441}
442
443pub const HexEscape = struct {
444 bytes: []const u8,
445 charset: *const [16]u8,
446
447 pub const upper_charset = "0123456789ABCDEF";
448 pub const lower_charset = "0123456789abcdef";
449
450 pub fn format(se: HexEscape, w: *std.io.Writer) std.io.Writer.Error!void {
451 const charset = se.charset;
452
453 var buf: [4]u8 = undefined;
454 buf[0] = '\\';
455 buf[1] = 'x';
456
457 for (se.bytes) |c| {
458 if (std.ascii.isPrint(c)) {
459 try w.writeByte(c);
460 } else {
461 buf[2] = charset[c >> 4];
462 buf[3] = charset[c & 15];
463 try w.writeAll(&buf);
464 }
465 }
466 }
467};
468
469/// Replaces non-ASCII bytes with hex escapes.
470pub fn hexEscape(bytes: []const u8, case: std.fmt.Case) std.fmt.Formatter(HexEscape, HexEscape.format) {
471 return .{ .data = .{ .bytes = bytes, .charset = switch (case) {
472 .lower => HexEscape.lower_charset,
473 .upper => HexEscape.upper_charset,
474 } } };
475}
476
477test hexEscape {
478 try std.testing.expectFmt("abc 123", "{f}", .{hexEscape("abc 123", .lower)});
479 try std.testing.expectFmt("ab\\xffc", "{f}", .{hexEscape("ab\xffc", .lower)});
480 try std.testing.expectFmt("abc 123", "{f}", .{hexEscape("abc 123", .upper)});
481 try std.testing.expectFmt("ab\\xFFc", "{f}", .{hexEscape("ab\xffc", .upper)});
482}
lib/std/base64.zig+3-3
......@@ -108,7 +108,7 @@ pub const Base64Encoder = struct {
108108 }
109109 }
110110
111 // dest must be compatible with std.io.Writer's writeAll interface
111 // dest must be compatible with std.io.GenericWriter's writeAll interface
112112 pub fn encodeWriter(encoder: *const Base64Encoder, dest: anytype, source: []const u8) !void {
113113 var chunker = window(u8, source, 3, 3);
114114 while (chunker.next()) |chunk| {
......@@ -118,8 +118,8 @@ pub const Base64Encoder = struct {
118118 }
119119 }
120120
121 // destWriter must be compatible with std.io.Writer's writeAll interface
122 // sourceReader must be compatible with std.io.Reader's read interface
121 // destWriter must be compatible with std.io.GenericWriter's writeAll interface
122 // sourceReader must be compatible with `std.io.GenericReader` read interface
123123 pub fn encodeFromReaderToWriter(encoder: *const Base64Encoder, destWriter: anytype, sourceReader: anytype) !void {
124124 while (true) {
125125 var tempSource: [3]u8 = undefined;
lib/std/bounded_array.zig+2-2
......@@ -277,7 +277,7 @@ pub fn BoundedArrayAligned(
277277 @compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++
278278 "but the given type is BoundedArray(" ++ @typeName(T) ++ ", ...)")
279279 else
280 std.io.Writer(*Self, error{Overflow}, appendWrite);
280 std.io.GenericWriter(*Self, error{Overflow}, appendWrite);
281281
282282 /// Initializes a writer which will write into the array.
283283 pub fn writer(self: *Self) Writer {
......@@ -285,7 +285,7 @@ pub fn BoundedArrayAligned(
285285 }
286286
287287 /// Same as `appendSlice` except it returns the number of bytes written, which is always the same
288 /// as `m.len`. The purpose of this function existing is to match `std.io.Writer` API.
288 /// as `m.len`. The purpose of this function existing is to match `std.io.GenericWriter` API.
289289 fn appendWrite(self: *Self, m: []const u8) error{Overflow}!usize {
290290 try self.appendSlice(m);
291291 return m.len;
lib/std/builtin.zig+2-10
......@@ -34,24 +34,16 @@ pub const StackTrace = struct {
3434 index: usize,
3535 instruction_addresses: []usize,
3636
37 pub fn format(
38 self: StackTrace,
39 comptime fmt: []const u8,
40 options: std.fmt.FormatOptions,
41 writer: anytype,
42 ) !void {
43 if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
44
37 pub fn format(self: StackTrace, writer: *std.io.Writer) std.io.Writer.Error!void {
4538 // TODO: re-evaluate whether to use format() methods at all.
4639 // Until then, avoid an error when using GeneralPurposeAllocator with WebAssembly
4740 // where it tries to call detectTTYConfig here.
4841 if (builtin.os.tag == .freestanding) return;
4942
50 _ = options;
5143 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
5244 return writer.print("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
5345 };
54 const tty_config = std.io.tty.detectConfig(std.io.getStdErr());
46 const tty_config = std.io.tty.detectConfig(std.fs.File.stderr());
5547 try writer.writeAll("\n");
5648 std.debug.writeStackTrace(self, writer, debug_info, tty_config) catch |err| {
5749 try writer.print("Unable to print stack trace: {s}\n", .{@errorName(err)});
lib/std/compress.zig+2-2
......@@ -16,7 +16,7 @@ pub fn HashedReader(ReaderType: type, HasherType: type) type {
1616 hasher: HasherType,
1717
1818 pub const Error = ReaderType.Error;
19 pub const Reader = std.io.Reader(*@This(), Error, read);
19 pub const Reader = std.io.GenericReader(*@This(), Error, read);
2020
2121 pub fn read(self: *@This(), buf: []u8) Error!usize {
2222 const amt = try self.child_reader.read(buf);
......@@ -43,7 +43,7 @@ pub fn HashedWriter(WriterType: type, HasherType: type) type {
4343 hasher: HasherType,
4444
4545 pub const Error = WriterType.Error;
46 pub const Writer = std.io.Writer(*@This(), Error, write);
46 pub const Writer = std.io.GenericWriter(*@This(), Error, write);
4747
4848 pub fn write(self: *@This(), buf: []const u8) Error!usize {
4949 const amt = try self.child_writer.write(buf);
lib/std/compress/flate/deflate.zig+2-2
......@@ -355,7 +355,7 @@ fn Deflate(comptime container: Container, comptime WriterType: type, comptime Bl
355355
356356 // Writer interface
357357
358 pub const Writer = io.Writer(*Self, Error, write);
358 pub const Writer = io.GenericWriter(*Self, Error, write);
359359 pub const Error = BlockWriterType.Error;
360360
361361 /// Write `input` of uncompressed data.
......@@ -512,7 +512,7 @@ fn SimpleCompressor(
512512
513513 // Writer interface
514514
515 pub const Writer = io.Writer(*Self, Error, write);
515 pub const Writer = io.GenericWriter(*Self, Error, write);
516516 pub const Error = BlockWriterType.Error;
517517
518518 // Write `input` of uncompressed data.
lib/std/compress/flate/inflate.zig+1-1
......@@ -341,7 +341,7 @@ pub fn Inflate(comptime container: Container, comptime LookaheadType: type, comp
341341
342342 // Reader interface
343343
344 pub const Reader = std.io.Reader(*Self, Error, read);
344 pub const Reader = std.io.GenericReader(*Self, Error, read);
345345
346346 /// Returns the number of bytes read. It may be less than buffer.len.
347347 /// If the number of bytes read is 0, it means end of stream.
lib/std/compress/lzma.zig+1-1
......@@ -30,7 +30,7 @@ pub fn Decompress(comptime ReaderType: type) type {
3030 Allocator.Error ||
3131 error{ CorruptInput, EndOfStream, Overflow };
3232
33 pub const Reader = std.io.Reader(*Self, Error, read);
33 pub const Reader = std.io.GenericReader(*Self, Error, read);
3434
3535 allocator: Allocator,
3636 in_reader: ReaderType,
lib/std/compress/xz.zig+1-1
......@@ -34,7 +34,7 @@ pub fn Decompress(comptime ReaderType: type) type {
3434 const Self = @This();
3535
3636 pub const Error = ReaderType.Error || block.Decoder(ReaderType).Error;
37 pub const Reader = std.io.Reader(*Self, Error, read);
37 pub const Reader = std.io.GenericReader(*Self, Error, read);
3838
3939 allocator: Allocator,
4040 block_decoder: block.Decoder(ReaderType),
lib/std/compress/xz/block.zig+1-1
......@@ -27,7 +27,7 @@ pub fn Decoder(comptime ReaderType: type) type {
2727 ReaderType.Error ||
2828 DecodeError ||
2929 Allocator.Error;
30 pub const Reader = std.io.Reader(*Self, Error, read);
30 pub const Reader = std.io.GenericReader(*Self, Error, read);
3131
3232 allocator: Allocator,
3333 inner_reader: ReaderType,
lib/std/compress/zstandard.zig+1-1
......@@ -50,7 +50,7 @@ pub fn Decompressor(comptime ReaderType: type) type {
5050 OutOfMemory,
5151 };
5252
53 pub const Reader = std.io.Reader(*Self, Error, read);
53 pub const Reader = std.io.GenericReader(*Self, Error, read);
5454
5555 pub fn init(source: ReaderType, options: DecompressorOptions) Self {
5656 return .{
lib/std/compress/zstandard/readers.zig+1-1
......@@ -4,7 +4,7 @@ pub const ReversedByteReader = struct {
44 remaining_bytes: usize,
55 bytes: []const u8,
66
7 const Reader = std.io.Reader(*ReversedByteReader, error{}, readFn);
7 const Reader = std.io.GenericReader(*ReversedByteReader, error{}, readFn);
88
99 pub fn init(bytes: []const u8) ReversedByteReader {
1010 return .{
lib/std/crypto/25519/curve25519.zig+2-2
......@@ -124,9 +124,9 @@ test "curve25519" {
124124 const p = try Curve25519.basePoint.clampedMul(s);
125125 try p.rejectIdentity();
126126 var buf: [128]u8 = undefined;
127 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145");
127 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&p.toBytes()}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145");
128128 const q = try p.clampedMul(s);
129 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537");
129 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&q.toBytes()}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537");
130130
131131 try Curve25519.rejectNonCanonical(s);
132132 s[31] |= 0x80;
lib/std/crypto/25519/ed25519.zig+3-3
......@@ -509,8 +509,8 @@ test "key pair creation" {
509509 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
510510 const key_pair = try Ed25519.KeyPair.generateDeterministic(seed);
511511 var buf: [256]u8 = undefined;
512 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.secret_key.toBytes())}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
513 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key.toBytes())}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
512 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&key_pair.secret_key.toBytes()}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
513 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&key_pair.public_key.toBytes()}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
514514}
515515
516516test "signature" {
......@@ -520,7 +520,7 @@ test "signature" {
520520
521521 const sig = try key_pair.sign("test", null);
522522 var buf: [128]u8 = undefined;
523 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&sig.toBytes())}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");
523 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&sig.toBytes()}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");
524524 try sig.verify("test", key_pair.public_key);
525525 try std.testing.expectError(error.SignatureVerificationFailed, sig.verify("TEST", key_pair.public_key));
526526}
lib/std/crypto/25519/edwards25519.zig+1-1
......@@ -546,7 +546,7 @@ test "packing/unpacking" {
546546 var b = Edwards25519.basePoint;
547547 const pk = try b.mul(s);
548548 var buf: [128]u8 = undefined;
549 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&pk.toBytes())}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6");
549 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&pk.toBytes()}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6");
550550
551551 const small_order_ss: [7][32]u8 = .{
552552 .{
lib/std/crypto/25519/ristretto255.zig+4-4
......@@ -175,21 +175,21 @@ pub const Ristretto255 = struct {
175175test "ristretto255" {
176176 const p = Ristretto255.basePoint;
177177 var buf: [256]u8 = undefined;
178 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
178 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
179179
180180 var r: [Ristretto255.encoded_length]u8 = undefined;
181181 _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
182182 var q = try Ristretto255.fromBytes(r);
183183 q = q.dbl().add(p);
184 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
184 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
185185
186186 const s = [_]u8{15} ++ [_]u8{0} ** 31;
187187 const w = try p.mul(s);
188 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&w.toBytes())}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E");
188 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&w.toBytes()}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E");
189189
190190 try std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p)));
191191
192192 const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32;
193193 const ph = Ristretto255.fromUniform(h);
194 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ph.toBytes())}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19");
194 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&ph.toBytes()}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19");
195195}
lib/std/crypto/25519/scalar.zig+3-3
......@@ -850,10 +850,10 @@ test "scalar25519" {
850850 var y = x.toBytes();
851851 try rejectNonCanonical(y);
852852 var buf: [128]u8 = undefined;
853 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
853 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&y}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F");
854854
855855 const reduced = reduce(field_order_s);
856 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000");
856 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&reduced}), "0000000000000000000000000000000000000000000000000000000000000000");
857857}
858858
859859test "non-canonical scalar25519" {
......@@ -867,7 +867,7 @@ test "mulAdd overflow check" {
867867 const c: [32]u8 = [_]u8{0xff} ** 32;
868868 const x = mulAdd(a, b, c);
869869 var buf: [128]u8 = undefined;
870 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&x)}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
870 try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&x}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903");
871871}
872872
873873test "scalar field inversion" {
lib/std/crypto/aegis.zig+1-1
......@@ -803,7 +803,7 @@ fn AegisMac(comptime T: type) type {
803803 }
804804
805805 pub const Error = error{};
806 pub const Writer = std.io.Writer(*Mac, Error, write);
806 pub const Writer = std.io.GenericWriter(*Mac, Error, write);
807807
808808 fn write(self: *Mac, bytes: []const u8) Error!usize {
809809 self.update(bytes);
lib/std/crypto/benchmark.zig+1-1
......@@ -458,7 +458,7 @@ fn mode(comptime x: comptime_int) comptime_int {
458458}
459459
460460pub fn main() !void {
461 const stdout = std.io.getStdOut().writer();
461 const stdout = std.fs.File.stdout().deprecatedWriter();
462462
463463 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
464464 defer arena.deinit();
lib/std/crypto/blake2.zig+1-1
......@@ -187,7 +187,7 @@ pub fn Blake2s(comptime out_bits: usize) type {
187187 }
188188
189189 pub const Error = error{};
190 pub const Writer = std.io.Writer(*Self, Error, write);
190 pub const Writer = std.io.GenericWriter(*Self, Error, write);
191191
192192 fn write(self: *Self, bytes: []const u8) Error!usize {
193193 self.update(bytes);
lib/std/crypto/blake3.zig+1-1
......@@ -476,7 +476,7 @@ pub const Blake3 = struct {
476476 }
477477
478478 pub const Error = error{};
479 pub const Writer = std.io.Writer(*Blake3, Error, write);
479 pub const Writer = std.io.GenericWriter(*Blake3, Error, write);
480480
481481 fn write(self: *Blake3, bytes: []const u8) Error!usize {
482482 self.update(bytes);
lib/std/crypto/chacha20.zig+2-2
......@@ -1145,7 +1145,7 @@ test "xchacha20" {
11451145 var c: [m.len]u8 = undefined;
11461146 XChaCha20IETF.xor(c[0..], m[0..], 0, key, nonce);
11471147 var buf: [2 * c.len]u8 = undefined;
1148 try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&c)}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
1148 try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&c}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D");
11491149 }
11501150 {
11511151 const ad = "Additional data";
......@@ -1154,7 +1154,7 @@ test "xchacha20" {
11541154 var out: [m.len]u8 = undefined;
11551155 try XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key);
11561156 var buf: [2 * c.len]u8 = undefined;
1157 try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&c)}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234");
1157 try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&c}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234");
11581158 try testing.expectEqualSlices(u8, out[0..], m);
11591159 c[0] +%= 1;
11601160 try testing.expectError(error.AuthenticationFailed, XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key));
lib/std/crypto/codecs/asn1/der/ArrayListReverse.zig+1-1
......@@ -45,7 +45,7 @@ pub fn prependSlice(self: *ArrayListReverse, data: []const u8) Error!void {
4545 self.data.ptr = begin;
4646}
4747
48pub const Writer = std.io.Writer(*ArrayListReverse, Error, prependSliceSize);
48pub const Writer = std.io.GenericWriter(*ArrayListReverse, Error, prependSliceSize);
4949/// Warning: This writer writes backwards. `fn print` will NOT work as expected.
5050pub fn writer(self: *ArrayListReverse) Writer {
5151 return .{ .context = self };
lib/std/crypto/ml_kem.zig+6-6
......@@ -1741,7 +1741,7 @@ test "NIST KAT test" {
17411741 for (0..100) |i| {
17421742 g.fill(&seed);
17431743 try std.fmt.format(fw, "count = {}\n", .{i});
1744 try std.fmt.format(fw, "seed = {s}\n", .{std.fmt.fmtSliceHexUpper(&seed)});
1744 try std.fmt.format(fw, "seed = {X}\n", .{&seed});
17451745 var g2 = NistDRBG.init(seed);
17461746
17471747 // This is not equivalent to g2.fill(kseed[:]). As the reference
......@@ -1756,16 +1756,16 @@ test "NIST KAT test" {
17561756 const e = kp.public_key.encaps(eseed);
17571757 const ss2 = try kp.secret_key.decaps(&e.ciphertext);
17581758 try testing.expectEqual(ss2, e.shared_secret);
1759 try std.fmt.format(fw, "pk = {s}\n", .{std.fmt.fmtSliceHexUpper(&kp.public_key.toBytes())});
1760 try std.fmt.format(fw, "sk = {s}\n", .{std.fmt.fmtSliceHexUpper(&kp.secret_key.toBytes())});
1761 try std.fmt.format(fw, "ct = {s}\n", .{std.fmt.fmtSliceHexUpper(&e.ciphertext)});
1762 try std.fmt.format(fw, "ss = {s}\n\n", .{std.fmt.fmtSliceHexUpper(&e.shared_secret)});
1759 try std.fmt.format(fw, "pk = {X}\n", .{&kp.public_key.toBytes()});
1760 try std.fmt.format(fw, "sk = {X}\n", .{&kp.secret_key.toBytes()});
1761 try std.fmt.format(fw, "ct = {X}\n", .{&e.ciphertext});
1762 try std.fmt.format(fw, "ss = {X}\n\n", .{&e.shared_secret});
17631763 }
17641764
17651765 var out: [32]u8 = undefined;
17661766 f.final(&out);
17671767 var outHex: [64]u8 = undefined;
1768 _ = try std.fmt.bufPrint(&outHex, "{s}", .{std.fmt.fmtSliceHexLower(&out)});
1768 _ = try std.fmt.bufPrint(&outHex, "{x}", .{&out});
17691769 try testing.expectEqual(outHex, modeHash[1].*);
17701770 }
17711771}
lib/std/crypto/sha1.zig+1-1
......@@ -269,7 +269,7 @@ pub const Sha1 = struct {
269269 }
270270
271271 pub const Error = error{};
272 pub const Writer = std.io.Writer(*Self, Error, write);
272 pub const Writer = std.io.GenericWriter(*Self, Error, write);
273273
274274 fn write(self: *Self, bytes: []const u8) Error!usize {
275275 self.update(bytes);
lib/std/crypto/sha2.zig+1-1
......@@ -376,7 +376,7 @@ fn Sha2x32(comptime iv: Iv32, digest_bits: comptime_int) type {
376376 }
377377
378378 pub const Error = error{};
379 pub const Writer = std.io.Writer(*Self, Error, write);
379 pub const Writer = std.io.GenericWriter(*Self, Error, write);
380380
381381 fn write(self: *Self, bytes: []const u8) Error!usize {
382382 self.update(bytes);
lib/std/crypto/sha3.zig+5-5
......@@ -82,7 +82,7 @@ pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime default_delim
8282 }
8383
8484 pub const Error = error{};
85 pub const Writer = std.io.Writer(*Self, Error, write);
85 pub const Writer = std.io.GenericWriter(*Self, Error, write);
8686
8787 fn write(self: *Self, bytes: []const u8) Error!usize {
8888 self.update(bytes);
......@@ -193,7 +193,7 @@ fn ShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime
193193 }
194194
195195 pub const Error = error{};
196 pub const Writer = std.io.Writer(*Self, Error, write);
196 pub const Writer = std.io.GenericWriter(*Self, Error, write);
197197
198198 fn write(self: *Self, bytes: []const u8) Error!usize {
199199 self.update(bytes);
......@@ -286,7 +286,7 @@ fn CShakeLike(comptime security_level: u11, comptime default_delim: u8, comptime
286286 }
287287
288288 pub const Error = error{};
289 pub const Writer = std.io.Writer(*Self, Error, write);
289 pub const Writer = std.io.GenericWriter(*Self, Error, write);
290290
291291 fn write(self: *Self, bytes: []const u8) Error!usize {
292292 self.update(bytes);
......@@ -392,7 +392,7 @@ fn KMacLike(comptime security_level: u11, comptime default_delim: u8, comptime r
392392 }
393393
394394 pub const Error = error{};
395 pub const Writer = std.io.Writer(*Self, Error, write);
395 pub const Writer = std.io.GenericWriter(*Self, Error, write);
396396
397397 fn write(self: *Self, bytes: []const u8) Error!usize {
398398 self.update(bytes);
......@@ -484,7 +484,7 @@ fn TupleHashLike(comptime security_level: u11, comptime default_delim: u8, compt
484484 }
485485
486486 pub const Error = error{};
487 pub const Writer = std.io.Writer(*Self, Error, write);
487 pub const Writer = std.io.GenericWriter(*Self, Error, write);
488488
489489 fn write(self: *Self, bytes: []const u8) Error!usize {
490490 self.update(bytes);
lib/std/crypto/siphash.zig+1-1
......@@ -240,7 +240,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
240240 }
241241
242242 pub const Error = error{};
243 pub const Writer = std.io.Writer(*Self, Error, write);
243 pub const Writer = std.io.GenericWriter(*Self, Error, write);
244244
245245 fn write(self: *Self, bytes: []const u8) Error!usize {
246246 self.update(bytes);
lib/std/crypto/tls/Client.zig+4-4
......@@ -1512,11 +1512,11 @@ fn logSecrets(key_log_file: std.fs.File, context: anytype, secrets: anytype) voi
15121512 const locked = if (key_log_file.lock(.exclusive)) |_| true else |_| false;
15131513 defer if (locked) key_log_file.unlock();
15141514 key_log_file.seekFromEnd(0) catch {};
1515 inline for (@typeInfo(@TypeOf(secrets)).@"struct".fields) |field| key_log_file.writer().print("{s}" ++
1516 (if (@hasField(@TypeOf(context), "counter")) "_{d}" else "") ++ " {} {}\n", .{field.name} ++
1515 inline for (@typeInfo(@TypeOf(secrets)).@"struct".fields) |field| key_log_file.deprecatedWriter().print("{s}" ++
1516 (if (@hasField(@TypeOf(context), "counter")) "_{d}" else "") ++ " {x} {x}\n", .{field.name} ++
15171517 (if (@hasField(@TypeOf(context), "counter")) .{context.counter} else .{}) ++ .{
1518 std.fmt.fmtSliceHexLower(context.client_random),
1519 std.fmt.fmtSliceHexLower(@field(secrets, field.name)),
1518 context.client_random,
1519 @field(secrets, field.name),
15201520 }) catch {};
15211521}
15221522
lib/std/debug.zig+186-170
......@@ -12,6 +12,7 @@ const windows = std.os.windows;
1212const native_arch = builtin.cpu.arch;
1313const native_os = builtin.os.tag;
1414const native_endian = native_arch.endian();
15const Writer = std.io.Writer;
1516
1617pub const MemoryAccessor = @import("debug/MemoryAccessor.zig");
1718pub const FixedBufferReader = @import("debug/FixedBufferReader.zig");
......@@ -204,13 +205,26 @@ pub fn unlockStdErr() void {
204205 std.Progress.unlockStdErr();
205206}
206207
208/// Allows the caller to freely write to stderr until `unlockStdErr` is called.
209///
210/// During the lock, any `std.Progress` information is cleared from the terminal.
211///
212/// Returns a `Writer` with empty buffer, meaning that it is
213/// in fact unbuffered and does not need to be flushed.
214pub fn lockStderrWriter(buffer: []u8) *Writer {
215 return std.Progress.lockStderrWriter(buffer);
216}
217
218pub fn unlockStderrWriter() void {
219 std.Progress.unlockStderrWriter();
220}
221
207222/// Print to stderr, unbuffered, and silently returning on failure. Intended
208/// for use in "printf debugging." Use `std.log` functions for proper logging.
223/// for use in "printf debugging". Use `std.log` functions for proper logging.
209224pub fn print(comptime fmt: []const u8, args: anytype) void {
210 lockStdErr();
211 defer unlockStdErr();
212 const stderr = io.getStdErr().writer();
213 nosuspend stderr.print(fmt, args) catch return;
225 const bw = lockStderrWriter(&.{});
226 defer unlockStderrWriter();
227 nosuspend bw.print(fmt, args) catch return;
214228}
215229
216230pub fn getStderrMutex() *std.Thread.Mutex {
......@@ -232,50 +246,44 @@ pub fn getSelfDebugInfo() !*SelfInfo {
232246/// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned.
233247/// Obtains the stderr mutex while dumping.
234248pub fn dumpHex(bytes: []const u8) void {
235 lockStdErr();
236 defer unlockStdErr();
237 dumpHexFallible(bytes) catch {};
238}
239
240/// Prints a hexadecimal view of the bytes, unbuffered, returning any error that occurs.
241pub fn dumpHexFallible(bytes: []const u8) !void {
242 const stderr = std.io.getStdErr();
243 const ttyconf = std.io.tty.detectConfig(stderr);
244 const writer = stderr.writer();
245 try dumpHexInternal(bytes, ttyconf, writer);
249 const bw = lockStderrWriter(&.{});
250 defer unlockStderrWriter();
251 const ttyconf = std.io.tty.detectConfig(.stderr());
252 dumpHexFallible(bw, ttyconf, bytes) catch {};
246253}
247254
248fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytype) !void {
255/// Prints a hexadecimal view of the bytes, returning any error that occurs.
256pub fn dumpHexFallible(bw: *Writer, ttyconf: std.io.tty.Config, bytes: []const u8) !void {
249257 var chunks = mem.window(u8, bytes, 16, 16);
250258 while (chunks.next()) |window| {
251259 // 1. Print the address.
252260 const address = (@intFromPtr(bytes.ptr) + 0x10 * (std.math.divCeil(usize, chunks.index orelse bytes.len, 16) catch unreachable)) - 0x10;
253 try ttyconf.setColor(writer, .dim);
261 try ttyconf.setColor(bw, .dim);
254262 // We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more.
255263 // Also, make sure all lines are aligned by padding the address.
256 try writer.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 });
257 try ttyconf.setColor(writer, .reset);
264 try bw.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 });
265 try ttyconf.setColor(bw, .reset);
258266
259267 // 2. Print the bytes.
260268 for (window, 0..) |byte, index| {
261 try writer.print("{X:0>2} ", .{byte});
262 if (index == 7) try writer.writeByte(' ');
269 try bw.print("{X:0>2} ", .{byte});
270 if (index == 7) try bw.writeByte(' ');
263271 }
264 try writer.writeByte(' ');
272 try bw.writeByte(' ');
265273 if (window.len < 16) {
266274 var missing_columns = (16 - window.len) * 3;
267275 if (window.len < 8) missing_columns += 1;
268 try writer.writeByteNTimes(' ', missing_columns);
276 try bw.splatByteAll(' ', missing_columns);
269277 }
270278
271279 // 3. Print the characters.
272280 for (window) |byte| {
273281 if (std.ascii.isPrint(byte)) {
274 try writer.writeByte(byte);
282 try bw.writeByte(byte);
275283 } else {
276284 // Related: https://github.com/ziglang/zig/issues/7600
277285 if (ttyconf == .windows_api) {
278 try writer.writeByte('.');
286 try bw.writeByte('.');
279287 continue;
280288 }
281289
......@@ -283,22 +291,23 @@ fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytyp
283291 // We don't want to do this for all control codes because most control codes apart from
284292 // the ones that Zig has escape sequences for are likely not very useful to print as symbols.
285293 switch (byte) {
286 '\n' => try writer.writeAll("␊"),
287 '\r' => try writer.writeAll("␍"),
288 '\t' => try writer.writeAll("␉"),
289 else => try writer.writeByte('.'),
294 '\n' => try bw.writeAll("␊"),
295 '\r' => try bw.writeAll("␍"),
296 '\t' => try bw.writeAll("␉"),
297 else => try bw.writeByte('.'),
290298 }
291299 }
292300 }
293 try writer.writeByte('\n');
301 try bw.writeByte('\n');
294302 }
295303}
296304
297test dumpHexInternal {
305test dumpHexFallible {
298306 const bytes: []const u8 = &.{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x12, 0x13 };
299 var output = std.ArrayList(u8).init(std.testing.allocator);
300 defer output.deinit();
301 try dumpHexInternal(bytes, .no_color, output.writer());
307 var aw: std.io.Writer.Allocating = .init(std.testing.allocator);
308 defer aw.deinit();
309
310 try dumpHexFallible(&aw.writer, .no_color, bytes);
302311 const expected = try std.fmt.allocPrint(std.testing.allocator,
303312 \\{x:0>[2]} 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF .."3DUfw........
304313 \\{x:0>[2]} 01 12 13 ...
......@@ -309,34 +318,36 @@ test dumpHexInternal {
309318 @sizeOf(usize) * 2,
310319 });
311320 defer std.testing.allocator.free(expected);
312 try std.testing.expectEqualStrings(expected, output.items);
321 try std.testing.expectEqualStrings(expected, aw.getWritten());
313322}
314323
315324/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
316/// TODO multithreaded awareness
317325pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
318 nosuspend {
319 if (builtin.target.cpu.arch.isWasm()) {
320 if (native_os == .wasi) {
321 const stderr = io.getStdErr().writer();
322 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
323 }
324 return;
325 }
326 const stderr = io.getStdErr().writer();
327 if (builtin.strip_debug_info) {
328 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
329 return;
326 const stderr = lockStderrWriter(&.{});
327 defer unlockStderrWriter();
328 nosuspend dumpCurrentStackTraceToWriter(start_addr, stderr) catch return;
329}
330
331/// Prints the current stack trace to the provided writer.
332pub fn dumpCurrentStackTraceToWriter(start_addr: ?usize, writer: *Writer) !void {
333 if (builtin.target.cpu.arch.isWasm()) {
334 if (native_os == .wasi) {
335 try writer.writeAll("Unable to dump stack trace: not implemented for Wasm\n");
330336 }
331 const debug_info = getSelfDebugInfo() catch |err| {
332 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
333 return;
334 };
335 writeCurrentStackTrace(stderr, debug_info, io.tty.detectConfig(io.getStdErr()), start_addr) catch |err| {
336 stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
337 return;
338 };
337 return;
339338 }
339 if (builtin.strip_debug_info) {
340 try writer.writeAll("Unable to dump stack trace: debug info stripped\n");
341 return;
342 }
343 const debug_info = getSelfDebugInfo() catch |err| {
344 try writer.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
345 return;
346 };
347 writeCurrentStackTrace(writer, debug_info, io.tty.detectConfig(.stderr()), start_addr) catch |err| {
348 try writer.print("Unable to dump stack trace: {s}\n", .{@errorName(err)});
349 return;
350 };
340351}
341352
342353pub const have_ucontext = posix.ucontext_t != void;
......@@ -402,16 +413,14 @@ pub inline fn getContext(context: *ThreadContext) bool {
402413/// Tries to print the stack trace starting from the supplied base pointer to stderr,
403414/// unbuffered, and ignores any error returned.
404415/// TODO multithreaded awareness
405pub fn dumpStackTraceFromBase(context: *ThreadContext) void {
416pub fn dumpStackTraceFromBase(context: *ThreadContext, stderr: *Writer) void {
406417 nosuspend {
407418 if (builtin.target.cpu.arch.isWasm()) {
408419 if (native_os == .wasi) {
409 const stderr = io.getStdErr().writer();
410420 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
411421 }
412422 return;
413423 }
414 const stderr = io.getStdErr().writer();
415424 if (builtin.strip_debug_info) {
416425 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
417426 return;
......@@ -420,7 +429,7 @@ pub fn dumpStackTraceFromBase(context: *ThreadContext) void {
420429 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
421430 return;
422431 };
423 const tty_config = io.tty.detectConfig(io.getStdErr());
432 const tty_config = io.tty.detectConfig(.stderr());
424433 if (native_os == .windows) {
425434 // On x86_64 and aarch64, the stack will be unwound using RtlVirtualUnwind using the context
426435 // 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 {
510519 nosuspend {
511520 if (builtin.target.cpu.arch.isWasm()) {
512521 if (native_os == .wasi) {
513 const stderr = io.getStdErr().writer();
514 stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return;
522 const stderr = lockStderrWriter(&.{});
523 defer unlockStderrWriter();
524 stderr.writeAll("Unable to dump stack trace: not implemented for Wasm\n") catch return;
515525 }
516526 return;
517527 }
518 const stderr = io.getStdErr().writer();
528 const stderr = lockStderrWriter(&.{});
529 defer unlockStderrWriter();
519530 if (builtin.strip_debug_info) {
520 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
531 stderr.writeAll("Unable to dump stack trace: debug info stripped\n") catch return;
521532 return;
522533 }
523534 const debug_info = getSelfDebugInfo() catch |err| {
524535 stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
525536 return;
526537 };
527 writeStackTrace(stack_trace, stderr, debug_info, io.tty.detectConfig(io.getStdErr())) catch |err| {
538 writeStackTrace(stack_trace, stderr, debug_info, io.tty.detectConfig(.stderr())) catch |err| {
528539 stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
529540 return;
530541 };
......@@ -573,14 +584,13 @@ pub fn panicExtra(
573584 const size = 0x1000;
574585 const trunc_msg = "(msg truncated)";
575586 var buf: [size + trunc_msg.len]u8 = undefined;
587 var bw: Writer = .fixed(buf[0..size]);
576588 // a minor annoyance with this is that it will result in the NoSpaceLeft
577589 // error being part of the @panic stack trace (but that error should
578590 // only happen rarely)
579 const msg = std.fmt.bufPrint(buf[0..size], format, args) catch |err| switch (err) {
580 error.NoSpaceLeft => blk: {
581 @memcpy(buf[size..], trunc_msg);
582 break :blk &buf;
583 },
591 const msg = if (bw.print(format, args)) |_| bw.buffered() else |_| blk: {
592 @memcpy(buf[size..], trunc_msg);
593 break :blk &buf;
584594 };
585595 std.builtin.panic.call(msg, ret_addr);
586596}
......@@ -675,10 +685,9 @@ pub fn defaultPanic(
675685 _ = panicking.fetchAdd(1, .seq_cst);
676686
677687 {
678 lockStdErr();
679 defer unlockStdErr();
688 const stderr = lockStderrWriter(&.{});
689 defer unlockStderrWriter();
680690
681 const stderr = io.getStdErr().writer();
682691 if (builtin.single_threaded) {
683692 stderr.print("panic: ", .{}) catch posix.abort();
684693 } else {
......@@ -688,7 +697,7 @@ pub fn defaultPanic(
688697 stderr.print("{s}\n", .{msg}) catch posix.abort();
689698
690699 if (@errorReturnTrace()) |t| dumpStackTrace(t.*);
691 dumpCurrentStackTrace(first_trace_addr orelse @returnAddress());
700 dumpCurrentStackTraceToWriter(first_trace_addr orelse @returnAddress(), stderr) catch {};
692701 }
693702
694703 waitForOtherThreadToFinishPanicking();
......@@ -699,7 +708,7 @@ pub fn defaultPanic(
699708 // A panic happened while trying to print a previous panic message.
700709 // We're still holding the mutex but that's fine as we're going to
701710 // call abort().
702 io.getStdErr().writeAll("aborting due to recursive panic\n") catch {};
711 fs.File.stderr().writeAll("aborting due to recursive panic\n") catch {};
703712 },
704713 else => {}, // Panicked while printing the recursive panic message.
705714 };
......@@ -723,7 +732,7 @@ fn waitForOtherThreadToFinishPanicking() void {
723732
724733pub fn writeStackTrace(
725734 stack_trace: std.builtin.StackTrace,
726 out_stream: anytype,
735 writer: *Writer,
727736 debug_info: *SelfInfo,
728737 tty_config: io.tty.Config,
729738) !void {
......@@ -736,15 +745,15 @@ pub fn writeStackTrace(
736745 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
737746 }) {
738747 const return_address = stack_trace.instruction_addresses[frame_index];
739 try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config);
748 try printSourceAtAddress(debug_info, writer, return_address - 1, tty_config);
740749 }
741750
742751 if (stack_trace.index > stack_trace.instruction_addresses.len) {
743752 const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len;
744753
745 tty_config.setColor(out_stream, .bold) catch {};
746 try out_stream.print("({d} additional stack frames skipped...)\n", .{dropped_frames});
747 tty_config.setColor(out_stream, .reset) catch {};
754 tty_config.setColor(writer, .bold) catch {};
755 try writer.print("({d} additional stack frames skipped...)\n", .{dropped_frames});
756 tty_config.setColor(writer, .reset) catch {};
748757 }
749758}
750759
......@@ -954,7 +963,7 @@ pub const StackIterator = struct {
954963};
955964
956965pub fn writeCurrentStackTrace(
957 out_stream: anytype,
966 writer: *Writer,
958967 debug_info: *SelfInfo,
959968 tty_config: io.tty.Config,
960969 start_addr: ?usize,
......@@ -962,7 +971,7 @@ pub fn writeCurrentStackTrace(
962971 if (native_os == .windows) {
963972 var context: ThreadContext = undefined;
964973 assert(getContext(&context));
965 return writeStackTraceWindows(out_stream, debug_info, tty_config, &context, start_addr);
974 return writeStackTraceWindows(writer, debug_info, tty_config, &context, start_addr);
966975 }
967976 var context: ThreadContext = undefined;
968977 const has_context = getContext(&context);
......@@ -973,7 +982,7 @@ pub fn writeCurrentStackTrace(
973982 defer it.deinit();
974983
975984 while (it.next()) |return_address| {
976 printLastUnwindError(&it, debug_info, out_stream, tty_config);
985 printLastUnwindError(&it, debug_info, writer, tty_config);
977986
978987 // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,
979988 // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid
......@@ -981,8 +990,8 @@ pub fn writeCurrentStackTrace(
981990 // condition on the subsequent iteration and return `null` thus terminating the loop.
982991 // same behaviour for x86-windows-msvc
983992 const address = return_address -| 1;
984 try printSourceAtAddress(debug_info, out_stream, address, tty_config);
985 } else printLastUnwindError(&it, debug_info, out_stream, tty_config);
993 try printSourceAtAddress(debug_info, writer, address, tty_config);
994 } else printLastUnwindError(&it, debug_info, writer, tty_config);
986995}
987996
988997pub 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
10421051}
10431052
10441053pub fn writeStackTraceWindows(
1045 out_stream: anytype,
1054 writer: *Writer,
10461055 debug_info: *SelfInfo,
10471056 tty_config: io.tty.Config,
10481057 context: *const windows.CONTEXT,
......@@ -1058,14 +1067,14 @@ pub fn writeStackTraceWindows(
10581067 return;
10591068 } else 0;
10601069 for (addrs[start_i..]) |addr| {
1061 try printSourceAtAddress(debug_info, out_stream, addr - 1, tty_config);
1070 try printSourceAtAddress(debug_info, writer, addr - 1, tty_config);
10621071 }
10631072}
10641073
1065fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
1074fn printUnknownSource(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: io.tty.Config) !void {
10661075 const module_name = debug_info.getModuleNameForAddress(address);
10671076 return printLineInfo(
1068 out_stream,
1077 writer,
10691078 null,
10701079 address,
10711080 "???",
......@@ -1075,38 +1084,38 @@ fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize
10751084 );
10761085}
10771086
1078fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, out_stream: anytype, tty_config: io.tty.Config) void {
1087fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *Writer, tty_config: io.tty.Config) void {
10791088 if (!have_ucontext) return;
10801089 if (it.getLastError()) |unwind_error| {
1081 printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config) catch {};
1090 printUnwindError(debug_info, writer, unwind_error.address, unwind_error.err, tty_config) catch {};
10821091 }
10831092}
10841093
1085fn printUnwindError(debug_info: *SelfInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
1094fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, err: UnwindError, tty_config: io.tty.Config) !void {
10861095 const module_name = debug_info.getModuleNameForAddress(address) orelse "???";
1087 try tty_config.setColor(out_stream, .dim);
1096 try tty_config.setColor(writer, .dim);
10881097 if (err == error.MissingDebugInfo) {
1089 try out_stream.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address });
1098 try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address });
10901099 } else {
1091 try out_stream.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, err });
1100 try writer.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, err });
10921101 }
1093 try tty_config.setColor(out_stream, .reset);
1102 try tty_config.setColor(writer, .reset);
10941103}
10951104
1096pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void {
1105pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: io.tty.Config) !void {
10971106 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
1098 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
1107 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, writer, address, tty_config),
10991108 else => return err,
11001109 };
11011110
11021111 const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) {
1103 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
1112 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, writer, address, tty_config),
11041113 else => return err,
11051114 };
11061115 defer if (symbol_info.source_location) |sl| debug_info.allocator.free(sl.file_name);
11071116
11081117 return printLineInfo(
1109 out_stream,
1118 writer,
11101119 symbol_info.source_location,
11111120 address,
11121121 symbol_info.name,
......@@ -1117,7 +1126,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address:
11171126}
11181127
11191128fn printLineInfo(
1120 out_stream: anytype,
1129 writer: *Writer,
11211130 source_location: ?SourceLocation,
11221131 address: usize,
11231132 symbol_name: []const u8,
......@@ -1126,34 +1135,34 @@ fn printLineInfo(
11261135 comptime printLineFromFile: anytype,
11271136) !void {
11281137 nosuspend {
1129 try tty_config.setColor(out_stream, .bold);
1138 try tty_config.setColor(writer, .bold);
11301139
11311140 if (source_location) |*sl| {
1132 try out_stream.print("{s}:{d}:{d}", .{ sl.file_name, sl.line, sl.column });
1141 try writer.print("{s}:{d}:{d}", .{ sl.file_name, sl.line, sl.column });
11331142 } else {
1134 try out_stream.writeAll("???:?:?");
1143 try writer.writeAll("???:?:?");
11351144 }
11361145
1137 try tty_config.setColor(out_stream, .reset);
1138 try out_stream.writeAll(": ");
1139 try tty_config.setColor(out_stream, .dim);
1140 try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });
1141 try tty_config.setColor(out_stream, .reset);
1142 try out_stream.writeAll("\n");
1146 try tty_config.setColor(writer, .reset);
1147 try writer.writeAll(": ");
1148 try tty_config.setColor(writer, .dim);
1149 try writer.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });
1150 try tty_config.setColor(writer, .reset);
1151 try writer.writeAll("\n");
11431152
11441153 // Show the matching source code line if possible
11451154 if (source_location) |sl| {
1146 if (printLineFromFile(out_stream, sl)) {
1155 if (printLineFromFile(writer, sl)) {
11471156 if (sl.column > 0) {
11481157 // The caret already takes one char
11491158 const space_needed = @as(usize, @intCast(sl.column - 1));
11501159
1151 try out_stream.writeByteNTimes(' ', space_needed);
1152 try tty_config.setColor(out_stream, .green);
1153 try out_stream.writeAll("^");
1154 try tty_config.setColor(out_stream, .reset);
1160 try writer.splatByteAll(' ', space_needed);
1161 try tty_config.setColor(writer, .green);
1162 try writer.writeAll("^");
1163 try tty_config.setColor(writer, .reset);
11551164 }
1156 try out_stream.writeAll("\n");
1165 try writer.writeAll("\n");
11571166 } else |err| switch (err) {
11581167 error.EndOfFile, error.FileNotFound => {},
11591168 error.BadPathName => {},
......@@ -1164,7 +1173,7 @@ fn printLineInfo(
11641173 }
11651174}
11661175
1167fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation) !void {
1176fn printLineFromFileAnyOs(writer: *Writer, source_location: SourceLocation) !void {
11681177 // Need this to always block even in async I/O mode, because this could potentially
11691178 // be called from e.g. the event loop code crashing.
11701179 var f = try fs.cwd().openFile(source_location.file_name, .{});
......@@ -1197,31 +1206,31 @@ fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation)
11971206 if (mem.indexOfScalar(u8, slice, '\n')) |pos| {
11981207 const line = slice[0 .. pos + 1];
11991208 mem.replaceScalar(u8, line, '\t', ' ');
1200 return out_stream.writeAll(line);
1209 return writer.writeAll(line);
12011210 } else { // Line is the last inside the buffer, and requires another read to find delimiter. Alternatively the file ends.
12021211 mem.replaceScalar(u8, slice, '\t', ' ');
1203 try out_stream.writeAll(slice);
1212 try writer.writeAll(slice);
12041213 while (amt_read == buf.len) {
12051214 amt_read = try f.read(buf[0..]);
12061215 if (mem.indexOfScalar(u8, buf[0..amt_read], '\n')) |pos| {
12071216 const line = buf[0 .. pos + 1];
12081217 mem.replaceScalar(u8, line, '\t', ' ');
1209 return out_stream.writeAll(line);
1218 return writer.writeAll(line);
12101219 } else {
12111220 const line = buf[0..amt_read];
12121221 mem.replaceScalar(u8, line, '\t', ' ');
1213 try out_stream.writeAll(line);
1222 try writer.writeAll(line);
12141223 }
12151224 }
12161225 // Make sure printing last line of file inserts extra newline
1217 try out_stream.writeByte('\n');
1226 try writer.writeByte('\n');
12181227 }
12191228}
12201229
12211230test printLineFromFileAnyOs {
1222 var output = std.ArrayList(u8).init(std.testing.allocator);
1223 defer output.deinit();
1224 const output_stream = output.writer();
1231 var aw: Writer.Allocating = .init(std.testing.allocator);
1232 defer aw.deinit();
1233 const output_stream = &aw.writer;
12251234
12261235 const allocator = std.testing.allocator;
12271236 const join = std.fs.path.join;
......@@ -1243,8 +1252,8 @@ test printLineFromFileAnyOs {
12431252 try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }));
12441253
12451254 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
1246 try expectEqualStrings("no new lines in this file, but one is printed anyway\n", output.items);
1247 output.clearRetainingCapacity();
1255 try expectEqualStrings("no new lines in this file, but one is printed anyway\n", aw.getWritten());
1256 aw.clearRetainingCapacity();
12481257 }
12491258 {
12501259 const path = try fs.path.join(allocator, &.{ test_dir_path, "three_lines.zig" });
......@@ -1259,12 +1268,12 @@ test printLineFromFileAnyOs {
12591268 });
12601269
12611270 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
1262 try expectEqualStrings("1\n", output.items);
1263 output.clearRetainingCapacity();
1271 try expectEqualStrings("1\n", aw.getWritten());
1272 aw.clearRetainingCapacity();
12641273
12651274 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 3, .column = 0 });
1266 try expectEqualStrings("3\n", output.items);
1267 output.clearRetainingCapacity();
1275 try expectEqualStrings("3\n", aw.getWritten());
1276 aw.clearRetainingCapacity();
12681277 }
12691278 {
12701279 const file = try test_dir.dir.createFile("line_overlaps_page_boundary.zig", .{});
......@@ -1273,14 +1282,17 @@ test printLineFromFileAnyOs {
12731282 defer allocator.free(path);
12741283
12751284 const overlap = 10;
1276 var writer = file.writer();
1277 try writer.writeByteNTimes('a', std.heap.page_size_min - overlap);
1285 var buf: [16]u8 = undefined;
1286 var file_writer = file.writer(&buf);
1287 const writer = &file_writer.interface;
1288 try writer.splatByteAll('a', std.heap.page_size_min - overlap);
12781289 try writer.writeByte('\n');
1279 try writer.writeByteNTimes('a', overlap);
1290 try writer.splatByteAll('a', overlap);
1291 try writer.flush();
12801292
12811293 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 });
1282 try expectEqualStrings(("a" ** overlap) ++ "\n", output.items);
1283 output.clearRetainingCapacity();
1294 try expectEqualStrings(("a" ** overlap) ++ "\n", aw.getWritten());
1295 aw.clearRetainingCapacity();
12841296 }
12851297 {
12861298 const file = try test_dir.dir.createFile("file_ends_on_page_boundary.zig", .{});
......@@ -1288,12 +1300,13 @@ test printLineFromFileAnyOs {
12881300 const path = try fs.path.join(allocator, &.{ test_dir_path, "file_ends_on_page_boundary.zig" });
12891301 defer allocator.free(path);
12901302
1291 var writer = file.writer();
1292 try writer.writeByteNTimes('a', std.heap.page_size_max);
1303 var file_writer = file.writer(&.{});
1304 const writer = &file_writer.interface;
1305 try writer.splatByteAll('a', std.heap.page_size_max);
12931306
12941307 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
1295 try expectEqualStrings(("a" ** std.heap.page_size_max) ++ "\n", output.items);
1296 output.clearRetainingCapacity();
1308 try expectEqualStrings(("a" ** std.heap.page_size_max) ++ "\n", aw.getWritten());
1309 aw.clearRetainingCapacity();
12971310 }
12981311 {
12991312 const file = try test_dir.dir.createFile("very_long_first_line_spanning_multiple_pages.zig", .{});
......@@ -1301,24 +1314,25 @@ test printLineFromFileAnyOs {
13011314 const path = try fs.path.join(allocator, &.{ test_dir_path, "very_long_first_line_spanning_multiple_pages.zig" });
13021315 defer allocator.free(path);
13031316
1304 var writer = file.writer();
1305 try writer.writeByteNTimes('a', 3 * std.heap.page_size_max);
1317 var file_writer = file.writer(&.{});
1318 const writer = &file_writer.interface;
1319 try writer.splatByteAll('a', 3 * std.heap.page_size_max);
13061320
13071321 try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }));
13081322
13091323 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
1310 try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "\n", output.items);
1311 output.clearRetainingCapacity();
1324 try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "\n", aw.getWritten());
1325 aw.clearRetainingCapacity();
13121326
13131327 try writer.writeAll("a\na");
13141328
13151329 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 });
1316 try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "a\n", output.items);
1317 output.clearRetainingCapacity();
1330 try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "a\n", aw.getWritten());
1331 aw.clearRetainingCapacity();
13181332
13191333 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 });
1320 try expectEqualStrings("a\n", output.items);
1321 output.clearRetainingCapacity();
1334 try expectEqualStrings("a\n", aw.getWritten());
1335 aw.clearRetainingCapacity();
13221336 }
13231337 {
13241338 const file = try test_dir.dir.createFile("file_of_newlines.zig", .{});
......@@ -1326,18 +1340,19 @@ test printLineFromFileAnyOs {
13261340 const path = try fs.path.join(allocator, &.{ test_dir_path, "file_of_newlines.zig" });
13271341 defer allocator.free(path);
13281342
1329 var writer = file.writer();
1343 var file_writer = file.writer(&.{});
1344 const writer = &file_writer.interface;
13301345 const real_file_start = 3 * std.heap.page_size_min;
1331 try writer.writeByteNTimes('\n', real_file_start);
1346 try writer.splatByteAll('\n', real_file_start);
13321347 try writer.writeAll("abc\ndef");
13331348
13341349 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = real_file_start + 1, .column = 0 });
1335 try expectEqualStrings("abc\n", output.items);
1336 output.clearRetainingCapacity();
1350 try expectEqualStrings("abc\n", aw.getWritten());
1351 aw.clearRetainingCapacity();
13371352
13381353 try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = real_file_start + 2, .column = 0 });
1339 try expectEqualStrings("def\n", output.items);
1340 output.clearRetainingCapacity();
1354 try expectEqualStrings("def\n", aw.getWritten());
1355 aw.clearRetainingCapacity();
13411356 }
13421357}
13431358
......@@ -1461,7 +1476,8 @@ fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopa
14611476}
14621477
14631478fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) void {
1464 const stderr = io.getStdErr().writer();
1479 const stderr = lockStderrWriter(&.{});
1480 defer unlockStderrWriter();
14651481 _ = switch (sig) {
14661482 posix.SIG.SEGV => if (native_arch == .x86_64 and native_os == .linux and code == 128) // SI_KERNEL
14671483 // x86_64 doesn't have a full 64-bit virtual address space.
......@@ -1471,7 +1487,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque)
14711487 // but can also happen when no addressable memory is involved;
14721488 // for example when reading/writing model-specific registers
14731489 // by executing `rdmsr` or `wrmsr` in user-space (unprivileged mode).
1474 stderr.print("General protection exception (no address available)\n", .{})
1490 stderr.writeAll("General protection exception (no address available)\n")
14751491 else
14761492 stderr.print("Segmentation fault at address 0x{x}\n", .{addr}),
14771493 posix.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}),
......@@ -1509,7 +1525,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque)
15091525 }, @ptrCast(ctx)).__mcontext_data;
15101526 }
15111527 relocateContext(&new_ctx);
1512 dumpStackTraceFromBase(&new_ctx);
1528 dumpStackTraceFromBase(&new_ctx, stderr);
15131529 },
15141530 else => {},
15151531 }
......@@ -1539,25 +1555,24 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label:
15391555 _ = panicking.fetchAdd(1, .seq_cst);
15401556
15411557 {
1542 lockStdErr();
1543 defer unlockStdErr();
1558 const stderr = lockStderrWriter(&.{});
1559 defer unlockStderrWriter();
15441560
1545 dumpSegfaultInfoWindows(info, msg, label);
1561 dumpSegfaultInfoWindows(info, msg, label, stderr);
15461562 }
15471563
15481564 waitForOtherThreadToFinishPanicking();
15491565 },
15501566 1 => {
15511567 panic_stage = 2;
1552 io.getStdErr().writeAll("aborting due to recursive panic\n") catch {};
1568 fs.File.stderr().writeAll("aborting due to recursive panic\n") catch {};
15531569 },
15541570 else => {},
15551571 };
15561572 posix.abort();
15571573}
15581574
1559fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void {
1560 const stderr = io.getStdErr().writer();
1575fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8, stderr: *Writer) void {
15611576 _ = switch (msg) {
15621577 0 => stderr.print("{s}\n", .{label.?}),
15631578 1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}),
......@@ -1565,7 +1580,7 @@ fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[
15651580 else => unreachable,
15661581 } catch posix.abort();
15671582
1568 dumpStackTraceFromBase(info.ContextRecord);
1583 dumpStackTraceFromBase(info.ContextRecord, stderr);
15691584}
15701585
15711586pub fn dumpStackPointerAddr(prefix: []const u8) void {
......@@ -1588,10 +1603,10 @@ test "manage resources correctly" {
15881603 // self-hosted debug info is still too buggy
15891604 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
15901605
1591 const writer = std.io.null_writer;
1606 var discarding: std.io.Writer.Discarding = .init(&.{});
15921607 var di = try SelfInfo.open(testing.allocator);
15931608 defer di.deinit();
1594 try printSourceAtAddress(&di, writer, showMyTrace(), io.tty.detectConfig(std.io.getStdErr()));
1609 try printSourceAtAddress(&di, &discarding.writer, showMyTrace(), io.tty.detectConfig(.stderr()));
15951610}
15961611
15971612noinline fn showMyTrace() usize {
......@@ -1657,8 +1672,9 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
16571672 pub fn dump(t: @This()) void {
16581673 if (!enabled) return;
16591674
1660 const tty_config = io.tty.detectConfig(std.io.getStdErr());
1661 const stderr = io.getStdErr().writer();
1675 const tty_config = io.tty.detectConfig(.stderr());
1676 const stderr = lockStderrWriter(&.{});
1677 defer unlockStderrWriter();
16621678 const end = @min(t.index, size);
16631679 const debug_info = getSelfDebugInfo() catch |err| {
16641680 stderr.print(
......@@ -1688,7 +1704,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
16881704 t: @This(),
16891705 comptime fmt: []const u8,
16901706 options: std.fmt.FormatOptions,
1691 writer: anytype,
1707 writer: *Writer,
16921708 ) !void {
16931709 if (fmt.len != 0) std.fmt.invalidFmtError(fmt, t);
16941710 _ = options;
lib/std/debug/Dwarf.zig+3-11
......@@ -2302,11 +2302,7 @@ pub const ElfModule = struct {
23022302 };
23032303 defer debuginfod_dir.close();
23042304
2305 const filename = std.fmt.allocPrint(
2306 gpa,
2307 "{s}/debuginfo",
2308 .{std.fmt.fmtSliceHexLower(id)},
2309 ) catch break :blk;
2305 const filename = std.fmt.allocPrint(gpa, "{x}/debuginfo", .{id}) catch break :blk;
23102306 defer gpa.free(filename);
23112307
23122308 const path: Path = .{
......@@ -2330,12 +2326,8 @@ pub const ElfModule = struct {
23302326 var id_prefix_buf: [2]u8 = undefined;
23312327 var filename_buf: [38 + extension.len]u8 = undefined;
23322328
2333 _ = std.fmt.bufPrint(&id_prefix_buf, "{s}", .{std.fmt.fmtSliceHexLower(id[0..1])}) catch unreachable;
2334 const filename = std.fmt.bufPrint(
2335 &filename_buf,
2336 "{s}" ++ extension,
2337 .{std.fmt.fmtSliceHexLower(id[1..])},
2338 ) catch break :blk;
2329 _ = std.fmt.bufPrint(&id_prefix_buf, "{x}", .{id[0..1]}) catch unreachable;
2330 const filename = std.fmt.bufPrint(&filename_buf, "{x}" ++ extension, .{id[1..]}) catch break :blk;
23392331
23402332 for (global_debug_directories) |global_directory| {
23412333 const path: Path = .{
lib/std/debug/Pdb.zig+3-3
......@@ -395,7 +395,7 @@ const Msf = struct {
395395 streams: []MsfStream,
396396
397397 fn init(allocator: Allocator, file: File) !Msf {
398 const in = file.reader();
398 const in = file.deprecatedReader();
399399
400400 const superblock = try in.readStruct(pdb.SuperBlock);
401401
......@@ -514,7 +514,7 @@ const MsfStream = struct {
514514 var offset = self.pos % self.block_size;
515515
516516 try self.in_file.seekTo(block * self.block_size + offset);
517 const in = self.in_file.reader();
517 const in = self.in_file.deprecatedReader();
518518
519519 var size: usize = 0;
520520 var rem_buffer = buffer;
......@@ -562,7 +562,7 @@ const MsfStream = struct {
562562 return block * self.block_size + offset;
563563 }
564564
565 pub fn reader(self: *MsfStream) std.io.Reader(*MsfStream, Error, read) {
565 pub fn reader(self: *MsfStream) std.io.GenericReader(*MsfStream, Error, read) {
566566 return .{ .context = self };
567567 }
568568};
lib/std/debug/simple_panic.zig+1-1
......@@ -15,7 +15,7 @@ pub fn call(msg: []const u8, ra: ?usize) noreturn {
1515 @branchHint(.cold);
1616 _ = ra;
1717 std.debug.lockStdErr();
18 const stderr = std.io.getStdErr();
18 const stderr: std.fs.File = .stderr();
1919 stderr.writeAll(msg) catch {};
2020 @trap();
2121}
lib/std/elf.zig+5-5
......@@ -511,7 +511,7 @@ pub const Header = struct {
511511 pub fn read(parse_source: anytype) !Header {
512512 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
513513 try parse_source.seekableStream().seekTo(0);
514 try parse_source.reader().readNoEof(&hdr_buf);
514 try parse_source.deprecatedReader().readNoEof(&hdr_buf);
515515 return Header.parse(&hdr_buf);
516516 }
517517
......@@ -586,7 +586,7 @@ pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
586586 var phdr: Elf64_Phdr = undefined;
587587 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
588588 try self.parse_source.seekableStream().seekTo(offset);
589 try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
589 try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr));
590590
591591 // ELF endianness matches native endianness.
592592 if (self.elf_header.endian == native_endian) return phdr;
......@@ -599,7 +599,7 @@ pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
599599 var phdr: Elf32_Phdr = undefined;
600600 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
601601 try self.parse_source.seekableStream().seekTo(offset);
602 try self.parse_source.reader().readNoEof(mem.asBytes(&phdr));
602 try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr));
603603
604604 // ELF endianness does NOT match native endianness.
605605 if (self.elf_header.endian != native_endian) {
......@@ -636,7 +636,7 @@ pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
636636 var shdr: Elf64_Shdr = undefined;
637637 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
638638 try self.parse_source.seekableStream().seekTo(offset);
639 try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
639 try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr));
640640
641641 // ELF endianness matches native endianness.
642642 if (self.elf_header.endian == native_endian) return shdr;
......@@ -649,7 +649,7 @@ pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
649649 var shdr: Elf32_Shdr = undefined;
650650 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
651651 try self.parse_source.seekableStream().seekTo(offset);
652 try self.parse_source.reader().readNoEof(mem.asBytes(&shdr));
652 try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr));
653653
654654 // ELF endianness does NOT match native endianness.
655655 if (self.elf_header.endian != native_endian) {
lib/std/fifo.zig+4-4
......@@ -38,8 +38,8 @@ pub fn LinearFifo(
3838 count: usize,
3939
4040 const Self = @This();
41 pub const Reader = std.io.Reader(*Self, error{}, readFn);
42 pub const Writer = std.io.Writer(*Self, error{OutOfMemory}, appendWrite);
41 pub const Reader = std.io.GenericReader(*Self, error{}, readFn);
42 pub const Writer = std.io.GenericWriter(*Self, error{OutOfMemory}, appendWrite);
4343
4444 // Type of Self argument for slice operations.
4545 // If buffer is inline (Static) then we need to ensure we haven't
......@@ -231,7 +231,7 @@ pub fn LinearFifo(
231231 }
232232
233233 /// Same as `read` except it returns an error union
234 /// The purpose of this function existing is to match `std.io.Reader` API.
234 /// The purpose of this function existing is to match `std.io.GenericReader` API.
235235 fn readFn(self: *Self, dest: []u8) error{}!usize {
236236 return self.read(dest);
237237 }
......@@ -320,7 +320,7 @@ pub fn LinearFifo(
320320 }
321321
322322 /// Same as `write` except it returns the number of bytes written, which is always the same
323 /// as `bytes.len`. The purpose of this function existing is to match `std.io.Writer` API.
323 /// as `bytes.len`. The purpose of this function existing is to match `std.io.GenericWriter` API.
324324 fn appendWrite(self: *Self, bytes: []const u8) error{OutOfMemory}!usize {
325325 try self.write(bytes);
326326 return bytes.len;
lib/std/fmt.zig+290-1715
......@@ -1,17 +1,20 @@
11//! String formatting and parsing.
22
3const std = @import("std.zig");
43const builtin = @import("builtin");
54
5const std = @import("std.zig");
66const io = std.io;
77const math = std.math;
88const assert = std.debug.assert;
99const mem = std.mem;
10const unicode = std.unicode;
1110const meta = std.meta;
1211const lossyCast = math.lossyCast;
1312const expectFmt = std.testing.expectFmt;
1413const testing = std.testing;
14const Allocator = std.mem.Allocator;
15const Writer = std.io.Writer;
16
17pub const float = @import("fmt/float.zig");
1518
1619pub const default_max_depth = 3;
1720
......@@ -21,237 +24,91 @@ pub const Alignment = enum {
2124 right,
2225};
2326
27pub const Case = enum { lower, upper };
28
2429const default_alignment = .right;
2530const default_fill_char = ' ';
2631
27pub const FormatOptions = struct {
32/// Deprecated in favor of `Options`.
33pub const FormatOptions = Options;
34
35pub const Options = struct {
2836 precision: ?usize = null,
2937 width: ?usize = null,
3038 alignment: Alignment = default_alignment,
31 fill: u21 = default_fill_char,
32};
33
34/// Renders fmt string with args, calling `writer` with slices of bytes.
35/// If `writer` returns an error, the error is returned from `format` and
36/// `writer` is not called again.
37///
38/// The format string must be comptime-known and may contain placeholders following
39/// this format:
40/// `{[argument][specifier]:[fill][alignment][width].[precision]}`
41///
42/// Above, each word including its surrounding [ and ] is a parameter which you have to replace with something:
43///
44/// - *argument* is either the numeric index or the field name of the argument that should be inserted
45/// - when using a field name, you are required to enclose the field name (an identifier) in square
46/// brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...}
47/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
48/// - *fill* is a single unicode codepoint which is used to pad the formatted text
49/// - *alignment* is one of the three bytes '<', '^', or '>' to make the text left-, center-, or right-aligned, respectively
50/// - *width* is the total width of the field in unicode codepoints
51/// - *precision* specifies how many decimals a formatted number should have
52///
53/// Note that most of the parameters are optional and may be omitted. Also you can leave out separators like `:` and `.` when
54/// all parameters after the separator are omitted.
55/// Only exception is the *fill* parameter. If a non-zero *fill* character is required at the same time as *width* is specified,
56/// one has to specify *alignment* as well, as otherwise the digit following `:` is interpreted as *width*, not *fill*.
57///
58/// The *specifier* has several options for types:
59/// - `x` and `X`: output numeric value in hexadecimal notation
60/// - `s`:
61/// - for pointer-to-many and C pointers of u8, print as a C-string using zero-termination
62/// - for slices of u8, print the entire slice as a string without zero-termination
63/// - `e`: output floating point value in scientific notation
64/// - `d`: output numeric value in decimal notation
65/// - `b`: output integer value in binary notation
66/// - `o`: output integer value in octal notation
67/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
68/// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max.
69/// - `?`: output optional value as either the unwrapped value, or `null`; may be followed by a format specifier for the underlying value.
70/// - `!`: 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.
71/// - `*`: output the address of the value instead of the value itself.
72/// - `any`: output a value of any type using its default format.
73///
74/// If a formatted user type contains a function of the type
75/// ```
76/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void
77/// ```
78/// with `?` being the type formatted, this function will be called instead of the default implementation.
79/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
80///
81/// A user type may be a `struct`, `vector`, `union` or `enum` type.
82///
83/// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`.
84pub fn format(
85 writer: anytype,
86 comptime fmt: []const u8,
87 args: anytype,
88) !void {
89 const ArgsType = @TypeOf(args);
90 const args_type_info = @typeInfo(ArgsType);
91 if (args_type_info != .@"struct") {
92 @compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
93 }
94
95 const fields_info = args_type_info.@"struct".fields;
96 if (fields_info.len > max_format_args) {
97 @compileError("32 arguments max are supported per format call");
98 }
99
100 @setEvalBranchQuota(2000000);
101 comptime var arg_state: ArgState = .{ .args_len = fields_info.len };
102 comptime var i = 0;
103 comptime var literal: []const u8 = "";
104 inline while (true) {
105 const start_index = i;
106
107 inline while (i < fmt.len) : (i += 1) {
108 switch (fmt[i]) {
109 '{', '}' => break,
110 else => {},
111 }
112 }
113
114 comptime var end_index = i;
115 comptime var unescape_brace = false;
116
117 // Handle {{ and }}, those are un-escaped as single braces
118 if (i + 1 < fmt.len and fmt[i + 1] == fmt[i]) {
119 unescape_brace = true;
120 // Make the first brace part of the literal...
121 end_index += 1;
122 // ...and skip both
123 i += 2;
124 }
125
126 literal = literal ++ fmt[start_index..end_index];
127
128 // We've already skipped the other brace, restart the loop
129 if (unescape_brace) continue;
130
131 // Write out the literal
132 if (literal.len != 0) {
133 try writer.writeAll(literal);
134 literal = "";
135 }
136
137 if (i >= fmt.len) break;
138
139 if (fmt[i] == '}') {
140 @compileError("missing opening {");
141 }
142
143 // Get past the {
144 comptime assert(fmt[i] == '{');
145 i += 1;
146
147 const fmt_begin = i;
148 // Find the closing brace
149 inline while (i < fmt.len and fmt[i] != '}') : (i += 1) {}
150 const fmt_end = i;
151
152 if (i >= fmt.len) {
153 @compileError("missing closing }");
154 }
155
156 // Get past the }
157 comptime assert(fmt[i] == '}');
158 i += 1;
159
160 const placeholder = comptime Placeholder.parse(fmt[fmt_begin..fmt_end].*);
161 const arg_pos = comptime switch (placeholder.arg) {
162 .none => null,
163 .number => |pos| pos,
164 .named => |arg_name| meta.fieldIndex(ArgsType, arg_name) orelse
165 @compileError("no argument with name '" ++ arg_name ++ "'"),
166 };
167
168 const width = switch (placeholder.width) {
169 .none => null,
170 .number => |v| v,
171 .named => |arg_name| blk: {
172 const arg_i = comptime meta.fieldIndex(ArgsType, arg_name) orelse
173 @compileError("no argument with name '" ++ arg_name ++ "'");
174 _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments");
175 break :blk @field(args, arg_name);
176 },
177 };
178
179 const precision = switch (placeholder.precision) {
180 .none => null,
181 .number => |v| v,
182 .named => |arg_name| blk: {
183 const arg_i = comptime meta.fieldIndex(ArgsType, arg_name) orelse
184 @compileError("no argument with name '" ++ arg_name ++ "'");
185 _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments");
186 break :blk @field(args, arg_name);
187 },
39 fill: u8 = default_fill_char,
40
41 pub fn toNumber(o: Options, mode: Number.Mode, case: Case) Number {
42 return .{
43 .mode = mode,
44 .case = case,
45 .precision = o.precision,
46 .width = o.width,
47 .alignment = o.alignment,
48 .fill = o.fill,
18849 };
50 }
51};
18952
190 const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse
191 @compileError("too few arguments");
192
193 try formatType(
194 @field(args, fields_info[arg_to_print].name),
195 placeholder.specifier_arg,
196 FormatOptions{
197 .fill = placeholder.fill,
198 .alignment = placeholder.alignment,
199 .width = width,
200 .precision = precision,
201 },
202 writer,
203 std.options.fmt_max_depth,
204 );
205 }
206
207 if (comptime arg_state.hasUnusedArgs()) {
208 const missing_count = arg_state.args_len - @popCount(arg_state.used_args);
209 switch (missing_count) {
210 0 => unreachable,
211 1 => @compileError("unused argument in '" ++ fmt ++ "'"),
212 else => @compileError(comptimePrint("{d}", .{missing_count}) ++ " unused arguments in '" ++ fmt ++ "'"),
53pub const Number = struct {
54 mode: Mode = .decimal,
55 /// Affects hex digits as well as floating point "inf"/"INF".
56 case: Case = .lower,
57 precision: ?usize = null,
58 width: ?usize = null,
59 alignment: Alignment = default_alignment,
60 fill: u8 = default_fill_char,
61
62 pub const Mode = enum {
63 decimal,
64 binary,
65 octal,
66 hex,
67 scientific,
68
69 pub fn base(mode: Mode) ?u8 {
70 return switch (mode) {
71 .decimal => 10,
72 .binary => 2,
73 .octal => 8,
74 .hex => 16,
75 .scientific => null,
76 };
21377 }
214 }
215}
78 };
79};
21680
217fn cacheString(str: anytype) []const u8 {
218 return &str;
81/// Deprecated in favor of `Writer.print`.
82pub fn format(writer: anytype, comptime fmt: []const u8, args: anytype) !void {
83 var adapter = writer.adaptToNewApi();
84 return adapter.new_interface.print(fmt, args) catch |err| switch (err) {
85 error.WriteFailed => return adapter.err.?,
86 };
21987}
22088
22189pub const Placeholder = struct {
22290 specifier_arg: []const u8,
223 fill: u21,
91 fill: u8,
22492 alignment: Alignment,
22593 arg: Specifier,
22694 width: Specifier,
22795 precision: Specifier,
22896
229 pub fn parse(comptime str: anytype) Placeholder {
230 const view = std.unicode.Utf8View.initComptime(&str);
231 comptime var parser = Parser{
232 .iter = view.iterator(),
233 };
234
235 // Parse the positional argument number
236 const arg = comptime parser.specifier() catch |err|
237 @compileError(@errorName(err));
238
239 // Parse the format specifier
240 const specifier_arg = comptime parser.until(':');
241
242 // Skip the colon, if present
243 if (comptime parser.char()) |ch| {
244 if (ch != ':') {
245 @compileError("expected : or }, found '" ++ unicode.utf8EncodeComptime(ch) ++ "'");
246 }
97 pub fn parse(comptime bytes: []const u8) Placeholder {
98 var parser: Parser = .{ .bytes = bytes, .i = 0 };
99 const arg = parser.specifier() catch |err| @compileError(@errorName(err));
100 const specifier_arg = parser.until(':');
101 if (parser.char()) |b| {
102 if (b != ':') @compileError("expected : or }, found '" ++ &[1]u8{b} ++ "'");
247103 }
248104
249 // Parse the fill character, if present.
250 // When the width field is also specified, the fill character must
105 // Parse the fill byte, if present.
106 //
107 // When the width field is also specified, the fill byte must
251108 // be followed by an alignment specifier, unless it's '0' (zero)
252 // (in which case it's handled as part of the width specifier)
253 var fill: ?u21 = comptime if (parser.peek(1)) |ch|
254 switch (ch) {
109 // (in which case it's handled as part of the width specifier).
110 var fill: ?u8 = if (parser.peek(1)) |b|
111 switch (b) {
255112 '<', '^', '>' => parser.char(),
256113 else => null,
257114 }
......@@ -259,8 +116,8 @@ pub const Placeholder = struct {
259116 null;
260117
261118 // Parse the alignment parameter
262 const alignment: ?Alignment = comptime if (parser.peek(0)) |ch| init: {
263 switch (ch) {
119 const alignment: ?Alignment = if (parser.peek(0)) |b| init: {
120 switch (b) {
264121 '<', '^', '>' => {
265122 // consume the character
266123 break :init switch (parser.char().?) {
......@@ -276,30 +133,26 @@ pub const Placeholder = struct {
276133 // When none of the fill character and the alignment specifier have
277134 // been provided, check whether the width starts with a zero.
278135 if (fill == null and alignment == null) {
279 fill = comptime if (parser.peek(0) == '0') '0' else null;
136 fill = if (parser.peek(0) == '0') '0' else null;
280137 }
281138
282139 // Parse the width parameter
283 const width = comptime parser.specifier() catch |err|
284 @compileError(@errorName(err));
140 const width = parser.specifier() catch |err| @compileError(@errorName(err));
285141
286142 // Skip the dot, if present
287 if (comptime parser.char()) |ch| {
288 if (ch != '.') {
289 @compileError("expected . or }, found '" ++ unicode.utf8EncodeComptime(ch) ++ "'");
290 }
143 if (parser.char()) |b| {
144 if (b != '.') @compileError("expected . or }, found '" ++ &[1]u8{b} ++ "'");
291145 }
292146
293147 // Parse the precision parameter
294 const precision = comptime parser.specifier() catch |err|
295 @compileError(@errorName(err));
148 const precision = parser.specifier() catch |err| @compileError(@errorName(err));
296149
297 if (comptime parser.char()) |ch| {
298 @compileError("extraneous trailing character '" ++ unicode.utf8EncodeComptime(ch) ++ "'");
299 }
150 if (parser.char()) |b| @compileError("extraneous trailing character '" ++ &[1]u8{b} ++ "'");
151
152 const specifier_array = specifier_arg[0..specifier_arg.len].*;
300153
301 return Placeholder{
302 .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*),
154 return .{
155 .specifier_arg = &specifier_array,
303156 .fill = fill orelse default_fill_char,
304157 .alignment = alignment orelse default_alignment,
305158 .arg = arg,
......@@ -320,93 +173,64 @@ pub const Specifier = union(enum) {
320173/// Allows to implement formatters compatible with std.fmt without replicating
321174/// the standard library behavior.
322175pub const Parser = struct {
323 iter: std.unicode.Utf8Iterator,
176 bytes: []const u8,
177 i: usize,
324178
325 // Returns a decimal number or null if the current character is not a
326 // digit
327179 pub fn number(self: *@This()) ?usize {
328180 var r: ?usize = null;
329
330 while (self.peek(0)) |code_point| {
331 switch (code_point) {
181 while (self.peek(0)) |byte| {
182 switch (byte) {
332183 '0'...'9' => {
333184 if (r == null) r = 0;
334185 r.? *= 10;
335 r.? += code_point - '0';
186 r.? += byte - '0';
336187 },
337188 else => break,
338189 }
339 _ = self.iter.nextCodepoint();
190 self.i += 1;
340191 }
341
342192 return r;
343193 }
344194
345 // Returns a substring of the input starting from the current position
346 // and ending where `ch` is found or until the end if not found
347 pub fn until(self: *@This(), ch: u21) []const u8 {
348 const start = self.iter.i;
349 while (self.peek(0)) |code_point| {
350 if (code_point == ch)
351 break;
352 _ = self.iter.nextCodepoint();
353 }
354 return self.iter.bytes[start..self.iter.i];
195 pub fn until(self: *@This(), delimiter: u8) []const u8 {
196 const start = self.i;
197 self.i = std.mem.indexOfScalarPos(u8, self.bytes, self.i, delimiter) orelse self.bytes.len;
198 return self.bytes[start..self.i];
355199 }
356200
357 // Returns the character pointed to by the iterator if available, or
358 // null otherwise
359 pub fn char(self: *@This()) ?u21 {
360 if (self.iter.nextCodepoint()) |code_point| {
361 return code_point;
362 }
363 return null;
201 pub fn char(self: *@This()) ?u8 {
202 const i = self.i;
203 if (self.bytes.len - i == 0) return null;
204 self.i = i + 1;
205 return self.bytes[i];
364206 }
365207
366 // Returns true if the iterator points to an existing character and
367 // false otherwise
368 pub fn maybe(self: *@This(), val: u21) bool {
369 if (self.peek(0) == val) {
370 _ = self.iter.nextCodepoint();
208 pub fn maybe(self: *@This(), byte: u8) bool {
209 if (self.peek(0) == byte) {
210 self.i += 1;
371211 return true;
372212 }
373213 return false;
374214 }
375215
376 // Returns a decimal number or null if the current character is not a
377 // digit
378216 pub fn specifier(self: *@This()) !Specifier {
379217 if (self.maybe('[')) {
380218 const arg_name = self.until(']');
381
382 if (!self.maybe(']'))
383 return @field(anyerror, "Expected closing ]");
384
385 return Specifier{ .named = arg_name };
219 if (!self.maybe(']')) return error.@"Expected closing ]";
220 return .{ .named = arg_name };
386221 }
387 if (self.number()) |i|
388 return Specifier{ .number = i };
389
390 return Specifier{ .none = {} };
222 if (self.number()) |i| return .{ .number = i };
223 return .{ .none = {} };
391224 }
392225
393 // Returns the n-th next character or null if that's past the end
394 pub fn peek(self: *@This(), n: usize) ?u21 {
395 const original_i = self.iter.i;
396 defer self.iter.i = original_i;
397
398 var i: usize = 0;
399 var code_point: ?u21 = null;
400 while (i <= n) : (i += 1) {
401 code_point = self.iter.nextCodepoint();
402 if (code_point == null) return null;
403 }
404 return code_point;
226 pub fn peek(self: *@This(), i: usize) ?u8 {
227 const peek_index = self.i + i;
228 if (peek_index >= self.bytes.len) return null;
229 return self.bytes[peek_index];
405230 }
406231};
407232
408233pub const ArgSetType = u32;
409const max_format_args = @typeInfo(ArgSetType).int.bits;
410234
411235pub const ArgState = struct {
412236 next_arg: usize = 0,
......@@ -434,1075 +258,66 @@ pub const ArgState = struct {
434258 }
435259};
436260
437pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @TypeOf(writer).Error!void {
438 _ = options;
439 const T = @TypeOf(value);
440
441 switch (@typeInfo(T)) {
442 .pointer => |info| {
443 try writer.writeAll(@typeName(info.child) ++ "@");
444 if (info.size == .slice)
445 try formatInt(@intFromPtr(value.ptr), 16, .lower, FormatOptions{}, writer)
446 else
447 try formatInt(@intFromPtr(value), 16, .lower, FormatOptions{}, writer);
448 return;
449 },
450 .optional => |info| {
451 if (@typeInfo(info.child) == .pointer) {
452 try writer.writeAll(@typeName(info.child) ++ "@");
453 try formatInt(@intFromPtr(value), 16, .lower, FormatOptions{}, writer);
454 return;
455 }
456 },
457 else => {},
458 }
459
460 @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");
261/// Asserts the rendered integer value fits in `buffer`.
262/// Returns the end index within `buffer`.
263pub fn printInt(buffer: []u8, value: anytype, base: u8, case: Case, options: Options) usize {
264 var w: Writer = .fixed(buffer);
265 w.printInt(value, base, case, options) catch unreachable;
266 return w.end;
461267}
462268
463// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948
464const ANY = "any";
465
466pub fn defaultSpec(comptime T: type) [:0]const u8 {
467 switch (@typeInfo(T)) {
468 .array, .vector => return ANY,
469 .pointer => |ptr_info| switch (ptr_info.size) {
470 .one => switch (@typeInfo(ptr_info.child)) {
471 .array => return ANY,
472 else => {},
473 },
474 .many, .c => return "*",
475 .slice => return ANY,
476 },
477 .optional => |info| return "?" ++ defaultSpec(info.child),
478 .error_union => |info| return "!" ++ defaultSpec(info.payload),
479 else => {},
480 }
481 return "";
482}
483
484fn stripOptionalOrErrorUnionSpec(comptime fmt: []const u8) []const u8 {
485 return if (std.mem.eql(u8, fmt[1..], ANY))
486 ANY
487 else
488 fmt[1..];
489}
490
491pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) void {
492 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
493}
494
495pub fn formatType(
496 value: anytype,
497 comptime fmt: []const u8,
498 options: FormatOptions,
499 writer: anytype,
500 max_depth: usize,
501) @TypeOf(writer).Error!void {
502 const T = @TypeOf(value);
503 const actual_fmt = comptime if (std.mem.eql(u8, fmt, ANY))
504 defaultSpec(T)
505 else if (fmt.len != 0 and (fmt[0] == '?' or fmt[0] == '!')) switch (@typeInfo(T)) {
506 .optional, .error_union => fmt,
507 else => stripOptionalOrErrorUnionSpec(fmt),
508 } else fmt;
509
510 if (comptime std.mem.eql(u8, actual_fmt, "*")) {
511 return formatAddress(value, options, writer);
512 }
513
514 if (std.meta.hasMethod(T, "format")) {
515 return try value.format(actual_fmt, options, writer);
516 }
517
518 switch (@typeInfo(T)) {
519 .comptime_int, .int, .comptime_float, .float => {
520 return formatValue(value, actual_fmt, options, writer);
521 },
522 .void => {
523 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
524 return formatBuf("void", options, writer);
525 },
526 .bool => {
527 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
528 return formatBuf(if (value) "true" else "false", options, writer);
529 },
530 .optional => {
531 if (actual_fmt.len == 0 or actual_fmt[0] != '?')
532 @compileError("cannot format optional without a specifier (i.e. {?} or {any})");
533 const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt);
534 if (value) |payload| {
535 return formatType(payload, remaining_fmt, options, writer, max_depth);
536 } else {
537 return formatBuf("null", options, writer);
538 }
539 },
540 .error_union => {
541 if (actual_fmt.len == 0 or actual_fmt[0] != '!')
542 @compileError("cannot format error union without a specifier (i.e. {!} or {any})");
543 const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt);
544 if (value) |payload| {
545 return formatType(payload, remaining_fmt, options, writer, max_depth);
546 } else |err| {
547 return formatType(err, "", options, writer, max_depth);
548 }
549 },
550 .error_set => {
551 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
552 try writer.writeAll("error.");
553 return writer.writeAll(@errorName(value));
554 },
555 .@"enum" => |enumInfo| {
556 try writer.writeAll(@typeName(T));
557 if (enumInfo.is_exhaustive) {
558 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
559 try writer.writeAll(".");
560 try writer.writeAll(@tagName(value));
561 return;
562 }
563
564 // Use @tagName only if value is one of known fields
565 @setEvalBranchQuota(3 * enumInfo.fields.len);
566 inline for (enumInfo.fields) |enumField| {
567 if (@intFromEnum(value) == enumField.value) {
568 try writer.writeAll(".");
569 try writer.writeAll(@tagName(value));
570 return;
571 }
572 }
573
574 try writer.writeAll("(");
575 try formatType(@intFromEnum(value), actual_fmt, options, writer, max_depth);
576 try writer.writeAll(")");
577 },
578 .@"union" => |info| {
579 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
580 try writer.writeAll(@typeName(T));
581 if (max_depth == 0) {
582 return writer.writeAll("{ ... }");
583 }
584 if (info.tag_type) |UnionTagType| {
585 try writer.writeAll("{ .");
586 try writer.writeAll(@tagName(@as(UnionTagType, value)));
587 try writer.writeAll(" = ");
588 inline for (info.fields) |u_field| {
589 if (value == @field(UnionTagType, u_field.name)) {
590 try formatType(@field(value, u_field.name), ANY, options, writer, max_depth - 1);
591 }
592 }
593 try writer.writeAll(" }");
594 } else {
595 try format(writer, "@{x}", .{@intFromPtr(&value)});
596 }
597 },
598 .@"struct" => |info| {
599 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
600 if (info.is_tuple) {
601 // Skip the type and field names when formatting tuples.
602 if (max_depth == 0) {
603 return writer.writeAll("{ ... }");
604 }
605 try writer.writeAll("{");
606 inline for (info.fields, 0..) |f, i| {
607 if (i == 0) {
608 try writer.writeAll(" ");
609 } else {
610 try writer.writeAll(", ");
611 }
612 try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
613 }
614 return writer.writeAll(" }");
615 }
616 try writer.writeAll(@typeName(T));
617 if (max_depth == 0) {
618 return writer.writeAll("{ ... }");
619 }
620 try writer.writeAll("{");
621 inline for (info.fields, 0..) |f, i| {
622 if (i == 0) {
623 try writer.writeAll(" .");
624 } else {
625 try writer.writeAll(", .");
626 }
627 try writer.writeAll(f.name);
628 try writer.writeAll(" = ");
629 try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
630 }
631 try writer.writeAll(" }");
632 },
633 .pointer => |ptr_info| switch (ptr_info.size) {
634 .one => switch (@typeInfo(ptr_info.child)) {
635 .array, .@"enum", .@"union", .@"struct" => {
636 return formatType(value.*, actual_fmt, options, writer, max_depth);
637 },
638 else => return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @intFromPtr(value) }),
639 },
640 .many, .c => {
641 if (actual_fmt.len == 0)
642 @compileError("cannot format pointer without a specifier (i.e. {s} or {*})");
643 if (ptr_info.sentinel() != null) {
644 return formatType(mem.span(value), actual_fmt, options, writer, max_depth);
645 }
646 if (actual_fmt[0] == 's' and ptr_info.child == u8) {
647 return formatBuf(mem.span(value), options, writer);
648 }
649 invalidFmtError(fmt, value);
650 },
651 .slice => {
652 if (actual_fmt.len == 0)
653 @compileError("cannot format slice without a specifier (i.e. {s} or {any})");
654 if (max_depth == 0) {
655 return writer.writeAll("{ ... }");
656 }
657 if (actual_fmt[0] == 's' and ptr_info.child == u8) {
658 return formatBuf(value, options, writer);
659 }
660 try writer.writeAll("{ ");
661 for (value, 0..) |elem, i| {
662 try formatType(elem, actual_fmt, options, writer, max_depth - 1);
663 if (i != value.len - 1) {
664 try writer.writeAll(", ");
665 }
666 }
667 try writer.writeAll(" }");
668 },
669 },
670 .array => |info| {
671 if (actual_fmt.len == 0)
672 @compileError("cannot format array without a specifier (i.e. {s} or {any})");
673 if (max_depth == 0) {
674 return writer.writeAll("{ ... }");
675 }
676 if (actual_fmt[0] == 's' and info.child == u8) {
677 return formatBuf(&value, options, writer);
678 }
679 try writer.writeAll("{ ");
680 for (value, 0..) |elem, i| {
681 try formatType(elem, actual_fmt, options, writer, max_depth - 1);
682 if (i < value.len - 1) {
683 try writer.writeAll(", ");
684 }
685 }
686 try writer.writeAll(" }");
687 },
688 .vector => |info| {
689 if (max_depth == 0) {
690 return writer.writeAll("{ ... }");
691 }
692 try writer.writeAll("{ ");
693 var i: usize = 0;
694 while (i < info.len) : (i += 1) {
695 try formatType(value[i], actual_fmt, options, writer, max_depth - 1);
696 if (i < info.len - 1) {
697 try writer.writeAll(", ");
698 }
699 }
700 try writer.writeAll(" }");
701 },
702 .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"),
703 .type => {
704 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
705 return formatBuf(@typeName(value), options, writer);
706 },
707 .enum_literal => {
708 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
709 const buffer = [_]u8{'.'} ++ @tagName(value);
710 return formatBuf(buffer, options, writer);
711 },
712 .null => {
713 if (actual_fmt.len != 0) invalidFmtError(fmt, value);
714 return formatBuf("null", options, writer);
715 },
716 else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"),
717 }
718}
719
720fn formatValue(
721 value: anytype,
722 comptime fmt: []const u8,
723 options: FormatOptions,
724 writer: anytype,
725) !void {
726 const T = @TypeOf(value);
727 switch (@typeInfo(T)) {
728 .float, .comptime_float => return formatFloatValue(value, fmt, options, writer),
729 .int, .comptime_int => return formatIntValue(value, fmt, options, writer),
730 .bool => return formatBuf(if (value) "true" else "false", options, writer),
731 else => comptime unreachable,
732 }
733}
734
735pub fn formatIntValue(
736 value: anytype,
737 comptime fmt: []const u8,
738 options: FormatOptions,
739 writer: anytype,
740) !void {
741 comptime var base = 10;
742 comptime var case: Case = .lower;
743
744 const int_value = if (@TypeOf(value) == comptime_int) blk: {
745 const Int = math.IntFittingRange(value, value);
746 break :blk @as(Int, value);
747 } else value;
748
749 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
750 base = 10;
751 case = .lower;
752 } else if (comptime std.mem.eql(u8, fmt, "c")) {
753 if (@typeInfo(@TypeOf(int_value)).int.bits <= 8) {
754 return formatAsciiChar(@as(u8, int_value), options, writer);
755 } else {
756 @compileError("cannot print integer that is larger than 8 bits as an ASCII character");
757 }
758 } else if (comptime std.mem.eql(u8, fmt, "u")) {
759 if (@typeInfo(@TypeOf(int_value)).int.bits <= 21) {
760 return formatUnicodeCodepoint(@as(u21, int_value), options, writer);
761 } else {
762 @compileError("cannot print integer that is larger than 21 bits as an UTF-8 sequence");
763 }
764 } else if (comptime std.mem.eql(u8, fmt, "b")) {
765 base = 2;
766 case = .lower;
767 } else if (comptime std.mem.eql(u8, fmt, "x")) {
768 base = 16;
769 case = .lower;
770 } else if (comptime std.mem.eql(u8, fmt, "X")) {
771 base = 16;
772 case = .upper;
773 } else if (comptime std.mem.eql(u8, fmt, "o")) {
774 base = 8;
775 case = .lower;
776 } else {
777 invalidFmtError(fmt, value);
778 }
779
780 return formatInt(int_value, base, case, options, writer);
781}
782
783pub const format_float = @import("fmt/format_float.zig");
784pub const formatFloat = format_float.formatFloat;
785pub const FormatFloatError = format_float.FormatError;
786
787fn formatFloatValue(
788 value: anytype,
789 comptime fmt: []const u8,
790 options: FormatOptions,
791 writer: anytype,
792) !void {
793 var buf: [format_float.bufferSize(.decimal, f64)]u8 = undefined;
794
795 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
796 const s = formatFloat(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) {
797 error.BufferTooSmall => "(float)",
798 };
799 return formatBuf(s, options, writer);
800 } else if (comptime std.mem.eql(u8, fmt, "d")) {
801 const s = formatFloat(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
802 error.BufferTooSmall => "(float)",
803 };
804 return formatBuf(s, options, writer);
805 } else if (comptime std.mem.eql(u8, fmt, "x")) {
806 var buf_stream = std.io.fixedBufferStream(&buf);
807 formatFloatHexadecimal(value, options, buf_stream.writer()) catch |err| switch (err) {
808 error.NoSpaceLeft => unreachable,
809 };
810 return formatBuf(buf_stream.getWritten(), options, writer);
269/// Converts values in the range [0, 100) to a base 10 string.
270pub fn digits2(value: u8) [2]u8 {
271 if (builtin.mode == .ReleaseSmall) {
272 return .{ @intCast('0' + value / 10), @intCast('0' + value % 10) };
811273 } else {
812 invalidFmtError(fmt, value);
274 return "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"[value * 2 ..][0..2].*;
813275 }
814276}
815277
816test {
817 _ = &format_float;
818}
819
820pub const Case = enum { lower, upper };
821
822fn SliceHex(comptime case: Case) type {
823 const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef";
824
825 return struct {
826 pub fn format(
827 bytes: []const u8,
828 comptime fmt: []const u8,
829 options: std.fmt.FormatOptions,
830 writer: anytype,
831 ) !void {
832 _ = fmt;
833 _ = options;
834 var buf: [2]u8 = undefined;
835
836 for (bytes) |c| {
837 buf[0] = charset[c >> 4];
838 buf[1] = charset[c & 15];
839 try writer.writeAll(&buf);
840 }
841 }
842 };
843}
844
845const formatSliceHexLower = SliceHex(.lower).format;
846const formatSliceHexUpper = SliceHex(.upper).format;
847
848/// Return a Formatter for a []const u8 where every byte is formatted as a pair
849/// of lowercase hexadecimal digits.
850pub fn fmtSliceHexLower(bytes: []const u8) std.fmt.Formatter(formatSliceHexLower) {
851 return .{ .data = bytes };
852}
853
854/// Return a Formatter for a []const u8 where every byte is formatted as pair
855/// of uppercase hexadecimal digits.
856pub fn fmtSliceHexUpper(bytes: []const u8) std.fmt.Formatter(formatSliceHexUpper) {
857 return .{ .data = bytes };
858}
859
860fn SliceEscape(comptime case: Case) type {
861 const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef";
278/// Deprecated in favor of `Alt`.
279pub const Formatter = Alt;
862280
281/// Creates a type suitable for instantiating and passing to a "{f}" placeholder.
282pub fn Alt(
283 comptime Data: type,
284 comptime formatFn: fn (data: Data, writer: *Writer) Writer.Error!void,
285) type {
863286 return struct {
864 pub fn format(
865 bytes: []const u8,
866 comptime fmt: []const u8,
867 options: std.fmt.FormatOptions,
868 writer: anytype,
869 ) !void {
870 _ = fmt;
871 _ = options;
872 var buf: [4]u8 = undefined;
873
874 buf[0] = '\\';
875 buf[1] = 'x';
876
877 for (bytes) |c| {
878 if (std.ascii.isPrint(c)) {
879 try writer.writeByte(c);
880 } else {
881 buf[2] = charset[c >> 4];
882 buf[3] = charset[c & 15];
883 try writer.writeAll(&buf);
884 }
885 }
287 data: Data,
288 pub inline fn format(self: @This(), writer: *Writer) Writer.Error!void {
289 try formatFn(self.data, writer);
886290 }
887291 };
888292}
889293
890const formatSliceEscapeLower = SliceEscape(.lower).format;
891const formatSliceEscapeUpper = SliceEscape(.upper).format;
892
893/// Return a Formatter for a []const u8 where every non-printable ASCII
894/// character is escaped as \xNN, where NN is the character in lowercase
895/// hexadecimal notation.
896pub fn fmtSliceEscapeLower(bytes: []const u8) std.fmt.Formatter(formatSliceEscapeLower) {
897 return .{ .data = bytes };
294/// Helper for calling alternate format methods besides one named "format".
295pub fn alt(
296 context: anytype,
297 comptime func_name: @TypeOf(.enum_literal),
298) Formatter(@TypeOf(context), @field(@TypeOf(context), @tagName(func_name))) {
299 return .{ .data = context };
898300}
899301
900/// Return a Formatter for a []const u8 where every non-printable ASCII
901/// character is escaped as \xNN, where NN is the character in uppercase
902/// hexadecimal notation.
903pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscapeUpper) {
904 return .{ .data = bytes };
905}
906
907fn Size(comptime base: comptime_int) type {
908 return struct {
909 fn format(
910 value: u64,
911 comptime fmt: []const u8,
912 options: FormatOptions,
913 writer: anytype,
914 ) !void {
915 _ = fmt;
916 if (value == 0) {
917 return formatBuf("0B", options, writer);
918 }
919 // The worst case in terms of space needed is 32 bytes + 3 for the suffix.
920 var buf: [format_float.min_buffer_size + 3]u8 = undefined;
921
922 const mags_si = " kMGTPEZY";
923 const mags_iec = " KMGTPEZY";
302test alt {
303 const Example = struct {
304 number: u8,
924305
925 const log2 = math.log2(value);
926 const magnitude = switch (base) {
927 1000 => @min(log2 / comptime math.log2(1000), mags_si.len - 1),
928 1024 => @min(log2 / 10, mags_iec.len - 1),
929 else => unreachable,
930 };
931 const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, base), lossyCast(f64, magnitude));
932 const suffix = switch (base) {
933 1000 => mags_si[magnitude],
934 1024 => mags_iec[magnitude],
935 else => unreachable,
936 };
937
938 const s = switch (magnitude) {
939 0 => buf[0..formatIntBuf(&buf, value, 10, .lower, .{})],
940 else => formatFloat(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
941 error.BufferTooSmall => unreachable,
942 },
943 };
944
945 var i: usize = s.len;
946 if (suffix == ' ') {
947 buf[i] = 'B';
948 i += 1;
949 } else switch (base) {
950 1000 => {
951 buf[i..][0..2].* = [_]u8{ suffix, 'B' };
952 i += 2;
953 },
954 1024 => {
955 buf[i..][0..3].* = [_]u8{ suffix, 'i', 'B' };
956 i += 3;
957 },
958 else => unreachable,
959 }
960
961 return formatBuf(buf[0..i], options, writer);
306 pub fn other(ex: @This(), w: *Writer) Writer.Error!void {
307 try w.writeByte(ex.number);
962308 }
963309 };
964}
965const formatSizeDec = Size(1000).format;
966const formatSizeBin = Size(1024).format;
967
968/// Return a Formatter for a u64 value representing a file size.
969/// This formatter represents the number as multiple of 1000 and uses the SI
970/// measurement units (kB, MB, GB, ...).
971/// Format option `precision` is ignored when `value` is less than 1kB
972pub fn fmtIntSizeDec(value: u64) std.fmt.Formatter(formatSizeDec) {
973 return .{ .data = value };
974}
975
976/// Return a Formatter for a u64 value representing a file size.
977/// This formatter represents the number as multiple of 1024 and uses the IEC
978/// measurement units (KiB, MiB, GiB, ...).
979/// Format option `precision` is ignored when `value` is less than 1KiB
980pub fn fmtIntSizeBin(value: u64) std.fmt.Formatter(formatSizeBin) {
981 return .{ .data = value };
982}
983
984fn checkTextFmt(comptime fmt: []const u8) void {
985 if (fmt.len != 1)
986 @compileError("unsupported format string '" ++ fmt ++ "' when formatting text");
987 switch (fmt[0]) {
988 // Example of deprecation:
989 // '[deprecated_specifier]' => @compileError("specifier '[deprecated_specifier]' has been deprecated, wrap your argument in `std.some_function` instead"),
990 'x' => @compileError("specifier 'x' has been deprecated, wrap your argument in std.fmt.fmtSliceHexLower instead"),
991 'X' => @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceHexUpper instead"),
992 else => {},
993 }
994}
995
996pub fn formatText(
997 bytes: []const u8,
998 comptime fmt: []const u8,
999 options: FormatOptions,
1000 writer: anytype,
1001) !void {
1002 comptime checkTextFmt(fmt);
1003 return formatBuf(bytes, options, writer);
1004}
1005
1006pub fn formatAsciiChar(
1007 c: u8,
1008 options: FormatOptions,
1009 writer: anytype,
1010) !void {
1011 return formatBuf(@as(*const [1]u8, &c), options, writer);
1012}
1013
1014pub fn formatUnicodeCodepoint(
1015 c: u21,
1016 options: FormatOptions,
1017 writer: anytype,
1018) !void {
1019 var buf: [4]u8 = undefined;
1020 const len = unicode.utf8Encode(c, &buf) catch |err| switch (err) {
1021 error.Utf8CannotEncodeSurrogateHalf, error.CodepointTooLarge => {
1022 return formatBuf(&unicode.utf8EncodeComptime(unicode.replacement_character), options, writer);
1023 },
1024 };
1025 return formatBuf(buf[0..len], options, writer);
1026}
1027
1028pub fn formatBuf(
1029 buf: []const u8,
1030 options: FormatOptions,
1031 writer: anytype,
1032) !void {
1033 if (options.width) |min_width| {
1034 // In case of error assume the buffer content is ASCII-encoded
1035 const width = unicode.utf8CountCodepoints(buf) catch buf.len;
1036 const padding = if (width < min_width) min_width - width else 0;
1037
1038 if (padding == 0)
1039 return writer.writeAll(buf);
1040
1041 var fill_buffer: [4]u8 = undefined;
1042 const fill_utf8 = if (unicode.utf8Encode(options.fill, &fill_buffer)) |len|
1043 fill_buffer[0..len]
1044 else |err| switch (err) {
1045 error.Utf8CannotEncodeSurrogateHalf,
1046 error.CodepointTooLarge,
1047 => &unicode.utf8EncodeComptime(unicode.replacement_character),
1048 };
1049 switch (options.alignment) {
1050 .left => {
1051 try writer.writeAll(buf);
1052 try writer.writeBytesNTimes(fill_utf8, padding);
1053 },
1054 .center => {
1055 const left_padding = padding / 2;
1056 const right_padding = (padding + 1) / 2;
1057 try writer.writeBytesNTimes(fill_utf8, left_padding);
1058 try writer.writeAll(buf);
1059 try writer.writeBytesNTimes(fill_utf8, right_padding);
1060 },
1061 .right => {
1062 try writer.writeBytesNTimes(fill_utf8, padding);
1063 try writer.writeAll(buf);
1064 },
1065 }
1066 } else {
1067 // Fast path, avoid counting the number of codepoints
1068 try writer.writeAll(buf);
1069 }
1070}
1071
1072pub fn formatFloatHexadecimal(
1073 value: anytype,
1074 options: FormatOptions,
1075 writer: anytype,
1076) !void {
1077 if (math.signbit(value)) {
1078 try writer.writeByte('-');
1079 }
1080 if (math.isNan(value)) {
1081 return writer.writeAll("nan");
1082 }
1083 if (math.isInf(value)) {
1084 return writer.writeAll("inf");
1085 }
1086
1087 const T = @TypeOf(value);
1088 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
1089
1090 const mantissa_bits = math.floatMantissaBits(T);
1091 const fractional_bits = math.floatFractionalBits(T);
1092 const exponent_bits = math.floatExponentBits(T);
1093 const mantissa_mask = (1 << mantissa_bits) - 1;
1094 const exponent_mask = (1 << exponent_bits) - 1;
1095 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
1096
1097 const as_bits = @as(TU, @bitCast(value));
1098 var mantissa = as_bits & mantissa_mask;
1099 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
1100
1101 const is_denormal = exponent == 0 and mantissa != 0;
1102 const is_zero = exponent == 0 and mantissa == 0;
1103
1104 if (is_zero) {
1105 // Handle this case here to simplify the logic below.
1106 try writer.writeAll("0x0");
1107 if (options.precision) |precision| {
1108 if (precision > 0) {
1109 try writer.writeAll(".");
1110 try writer.writeByteNTimes('0', precision);
1111 }
1112 } else {
1113 try writer.writeAll(".0");
1114 }
1115 try writer.writeAll("p0");
1116 return;
1117 }
1118
1119 if (is_denormal) {
1120 // Adjust the exponent for printing.
1121 exponent += 1;
1122 } else {
1123 if (fractional_bits == mantissa_bits)
1124 mantissa |= 1 << fractional_bits; // Add the implicit integer bit.
1125 }
1126
1127 const mantissa_digits = (fractional_bits + 3) / 4;
1128 // Fill in zeroes to round the fraction width to a multiple of 4.
1129 mantissa <<= mantissa_digits * 4 - fractional_bits;
1130
1131 if (options.precision) |precision| {
1132 // Round if needed.
1133 if (precision < mantissa_digits) {
1134 // We always have at least 4 extra bits.
1135 var extra_bits = (mantissa_digits - precision) * 4;
1136 // The result LSB is the Guard bit, we need two more (Round and
1137 // Sticky) to round the value.
1138 while (extra_bits > 2) {
1139 mantissa = (mantissa >> 1) | (mantissa & 1);
1140 extra_bits -= 1;
1141 }
1142 // Round to nearest, tie to even.
1143 mantissa |= @intFromBool(mantissa & 0b100 != 0);
1144 mantissa += 1;
1145 // Drop the excess bits.
1146 mantissa >>= 2;
1147 // Restore the alignment.
1148 mantissa <<= @as(math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4));
1149
1150 const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0;
1151 // Prefer a normalized result in case of overflow.
1152 if (overflow) {
1153 mantissa >>= 1;
1154 exponent += 1;
1155 }
1156 }
1157 }
1158
1159 // +1 for the decimal part.
1160 var buf: [1 + mantissa_digits]u8 = undefined;
1161 _ = formatIntBuf(&buf, mantissa, 16, .lower, .{ .fill = '0', .width = 1 + mantissa_digits });
1162
1163 try writer.writeAll("0x");
1164 try writer.writeByte(buf[0]);
1165 const trimmed = mem.trimEnd(u8, buf[1..], "0");
1166 if (options.precision) |precision| {
1167 if (precision > 0) try writer.writeAll(".");
1168 } else if (trimmed.len > 0) {
1169 try writer.writeAll(".");
1170 }
1171 try writer.writeAll(trimmed);
1172 // Add trailing zeros if explicitly requested.
1173 if (options.precision) |precision| if (precision > 0) {
1174 if (precision > trimmed.len)
1175 try writer.writeByteNTimes('0', precision - trimmed.len);
1176 };
1177 try writer.writeAll("p");
1178 try formatInt(exponent - exponent_bias, 10, .lower, .{}, writer);
1179}
1180
1181pub fn formatInt(
1182 value: anytype,
1183 base: u8,
1184 case: Case,
1185 options: FormatOptions,
1186 writer: anytype,
1187) !void {
1188 assert(base >= 2);
1189
1190 const int_value = if (@TypeOf(value) == comptime_int) blk: {
1191 const Int = math.IntFittingRange(value, value);
1192 break :blk @as(Int, value);
1193 } else value;
1194
1195 const value_info = @typeInfo(@TypeOf(int_value)).int;
1196
1197 // The type must have the same size as `base` or be wider in order for the
1198 // division to work
1199 const min_int_bits = comptime @max(value_info.bits, 8);
1200 const MinInt = std.meta.Int(.unsigned, min_int_bits);
1201
1202 const abs_value = @abs(int_value);
1203 // The worst case in terms of space needed is base 2, plus 1 for the sign
1204 var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined;
1205
1206 var a: MinInt = abs_value;
1207 var index: usize = buf.len;
1208
1209 if (base == 10) {
1210 while (a >= 100) : (a = @divTrunc(a, 100)) {
1211 index -= 2;
1212 buf[index..][0..2].* = digits2(@intCast(a % 100));
1213 }
1214
1215 if (a < 10) {
1216 index -= 1;
1217 buf[index] = '0' + @as(u8, @intCast(a));
1218 } else {
1219 index -= 2;
1220 buf[index..][0..2].* = digits2(@intCast(a));
1221 }
1222 } else {
1223 while (true) {
1224 const digit = a % base;
1225 index -= 1;
1226 buf[index] = digitToChar(@intCast(digit), case);
1227 a /= base;
1228 if (a == 0) break;
1229 }
1230 }
1231
1232 if (value_info.signedness == .signed) {
1233 if (value < 0) {
1234 // Negative integer
1235 index -= 1;
1236 buf[index] = '-';
1237 } else if (options.width == null or options.width.? == 0) {
1238 // Positive integer, omit the plus sign
1239 } else {
1240 // Positive integer
1241 index -= 1;
1242 buf[index] = '+';
1243 }
1244 }
1245
1246 return formatBuf(buf[index..], options, writer);
1247}
1248
1249pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, case: Case, options: FormatOptions) usize {
1250 var fbs = std.io.fixedBufferStream(out_buf);
1251 formatInt(value, base, case, options, fbs.writer()) catch unreachable;
1252 return fbs.pos;
1253}
1254
1255/// Converts values in the range [0, 100) to a base 10 string.
1256pub fn digits2(value: u8) [2]u8 {
1257 if (builtin.mode == .ReleaseSmall) {
1258 return .{ @intCast('0' + value / 10), @intCast('0' + value % 10) };
1259 } else {
1260 return "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"[value * 2 ..][0..2].*;
1261 }
1262}
1263
1264const FormatDurationData = struct {
1265 ns: u64,
1266 negative: bool = false,
1267};
1268
1269fn formatDuration(data: FormatDurationData, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
1270 _ = fmt;
1271
1272 // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24
1273 var buf: [24]u8 = undefined;
1274 var fbs = std.io.fixedBufferStream(&buf);
1275 var buf_writer = fbs.writer();
1276 if (data.negative) {
1277 buf_writer.writeByte('-') catch unreachable;
1278 }
1279
1280 var ns_remaining = data.ns;
1281 inline for (.{
1282 .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' },
1283 .{ .ns = std.time.ns_per_week, .sep = 'w' },
1284 .{ .ns = std.time.ns_per_day, .sep = 'd' },
1285 .{ .ns = std.time.ns_per_hour, .sep = 'h' },
1286 .{ .ns = std.time.ns_per_min, .sep = 'm' },
1287 }) |unit| {
1288 if (ns_remaining >= unit.ns) {
1289 const units = ns_remaining / unit.ns;
1290 formatInt(units, 10, .lower, .{}, buf_writer) catch unreachable;
1291 buf_writer.writeByte(unit.sep) catch unreachable;
1292 ns_remaining -= units * unit.ns;
1293 if (ns_remaining == 0)
1294 return formatBuf(fbs.getWritten(), options, writer);
1295 }
1296 }
1297
1298 inline for (.{
1299 .{ .ns = std.time.ns_per_s, .sep = "s" },
1300 .{ .ns = std.time.ns_per_ms, .sep = "ms" },
1301 .{ .ns = std.time.ns_per_us, .sep = "us" },
1302 }) |unit| {
1303 const kunits = ns_remaining * 1000 / unit.ns;
1304 if (kunits >= 1000) {
1305 formatInt(kunits / 1000, 10, .lower, .{}, buf_writer) catch unreachable;
1306 const frac = kunits % 1000;
1307 if (frac > 0) {
1308 // Write up to 3 decimal places
1309 var decimal_buf = [_]u8{ '.', 0, 0, 0 };
1310 _ = formatIntBuf(decimal_buf[1..], frac, 10, .lower, .{ .fill = '0', .width = 3 });
1311 var end: usize = 4;
1312 while (end > 1) : (end -= 1) {
1313 if (decimal_buf[end - 1] != '0') break;
1314 }
1315 buf_writer.writeAll(decimal_buf[0..end]) catch unreachable;
1316 }
1317 buf_writer.writeAll(unit.sep) catch unreachable;
1318 return formatBuf(fbs.getWritten(), options, writer);
1319 }
1320 }
1321
1322 formatInt(ns_remaining, 10, .lower, .{}, buf_writer) catch unreachable;
1323 buf_writer.writeAll("ns") catch unreachable;
1324 return formatBuf(fbs.getWritten(), options, writer);
1325}
1326
1327/// Return a Formatter for number of nanoseconds according to its magnitude:
1328/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s
1329pub fn fmtDuration(ns: u64) Formatter(formatDuration) {
1330 const data = FormatDurationData{ .ns = ns };
1331 return .{ .data = data };
1332}
1333
1334test fmtDuration {
1335 var buf: [24]u8 = undefined;
1336 inline for (.{
1337 .{ .s = "0ns", .d = 0 },
1338 .{ .s = "1ns", .d = 1 },
1339 .{ .s = "999ns", .d = std.time.ns_per_us - 1 },
1340 .{ .s = "1us", .d = std.time.ns_per_us },
1341 .{ .s = "1.45us", .d = 1450 },
1342 .{ .s = "1.5us", .d = 3 * std.time.ns_per_us / 2 },
1343 .{ .s = "14.5us", .d = 14500 },
1344 .{ .s = "145us", .d = 145000 },
1345 .{ .s = "999.999us", .d = std.time.ns_per_ms - 1 },
1346 .{ .s = "1ms", .d = std.time.ns_per_ms + 1 },
1347 .{ .s = "1.5ms", .d = 3 * std.time.ns_per_ms / 2 },
1348 .{ .s = "1.11ms", .d = 1110000 },
1349 .{ .s = "1.111ms", .d = 1111000 },
1350 .{ .s = "1.111ms", .d = 1111100 },
1351 .{ .s = "999.999ms", .d = std.time.ns_per_s - 1 },
1352 .{ .s = "1s", .d = std.time.ns_per_s },
1353 .{ .s = "59.999s", .d = std.time.ns_per_min - 1 },
1354 .{ .s = "1m", .d = std.time.ns_per_min },
1355 .{ .s = "1h", .d = std.time.ns_per_hour },
1356 .{ .s = "1d", .d = std.time.ns_per_day },
1357 .{ .s = "1w", .d = std.time.ns_per_week },
1358 .{ .s = "1y", .d = 365 * std.time.ns_per_day },
1359 .{ .s = "1y52w23h59m59.999s", .d = 730 * std.time.ns_per_day - 1 }, // 365d = 52w1d
1360 .{ .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 },
1361 .{ .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 },
1362 .{ .s = "1y1h999.999us", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1 },
1363 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms },
1364 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 },
1365 .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 },
1366 .{ .s = "584y49w23h34m33.709s", .d = math.maxInt(u64) },
1367 }) |tc| {
1368 const slice = try bufPrint(&buf, "{}", .{fmtDuration(tc.d)});
1369 try std.testing.expectEqualStrings(tc.s, slice);
1370 }
1371
1372 inline for (.{
1373 .{ .s = "=======0ns", .f = "{s:=>10}", .d = 0 },
1374 .{ .s = "1ns=======", .f = "{s:=<10}", .d = 1 },
1375 .{ .s = " 999ns ", .f = "{s:^10}", .d = std.time.ns_per_us - 1 },
1376 }) |tc| {
1377 const slice = try bufPrint(&buf, tc.f, .{fmtDuration(tc.d)});
1378 try std.testing.expectEqualStrings(tc.s, slice);
1379 }
1380}
1381
1382fn formatDurationSigned(ns: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
1383 const data = FormatDurationData{ .ns = @abs(ns), .negative = ns < 0 };
1384 try formatDuration(data, fmt, options, writer);
1385}
1386
1387/// Return a Formatter for number of nanoseconds according to its signed magnitude:
1388/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s
1389pub fn fmtDurationSigned(ns: i64) Formatter(formatDurationSigned) {
1390 return .{ .data = ns };
1391}
1392
1393test fmtDurationSigned {
1394 var buf: [24]u8 = undefined;
1395 inline for (.{
1396 .{ .s = "0ns", .d = 0 },
1397 .{ .s = "1ns", .d = 1 },
1398 .{ .s = "-1ns", .d = -(1) },
1399 .{ .s = "999ns", .d = std.time.ns_per_us - 1 },
1400 .{ .s = "-999ns", .d = -(std.time.ns_per_us - 1) },
1401 .{ .s = "1us", .d = std.time.ns_per_us },
1402 .{ .s = "-1us", .d = -(std.time.ns_per_us) },
1403 .{ .s = "1.45us", .d = 1450 },
1404 .{ .s = "-1.45us", .d = -(1450) },
1405 .{ .s = "1.5us", .d = 3 * std.time.ns_per_us / 2 },
1406 .{ .s = "-1.5us", .d = -(3 * std.time.ns_per_us / 2) },
1407 .{ .s = "14.5us", .d = 14500 },
1408 .{ .s = "-14.5us", .d = -(14500) },
1409 .{ .s = "145us", .d = 145000 },
1410 .{ .s = "-145us", .d = -(145000) },
1411 .{ .s = "999.999us", .d = std.time.ns_per_ms - 1 },
1412 .{ .s = "-999.999us", .d = -(std.time.ns_per_ms - 1) },
1413 .{ .s = "1ms", .d = std.time.ns_per_ms + 1 },
1414 .{ .s = "-1ms", .d = -(std.time.ns_per_ms + 1) },
1415 .{ .s = "1.5ms", .d = 3 * std.time.ns_per_ms / 2 },
1416 .{ .s = "-1.5ms", .d = -(3 * std.time.ns_per_ms / 2) },
1417 .{ .s = "1.11ms", .d = 1110000 },
1418 .{ .s = "-1.11ms", .d = -(1110000) },
1419 .{ .s = "1.111ms", .d = 1111000 },
1420 .{ .s = "-1.111ms", .d = -(1111000) },
1421 .{ .s = "1.111ms", .d = 1111100 },
1422 .{ .s = "-1.111ms", .d = -(1111100) },
1423 .{ .s = "999.999ms", .d = std.time.ns_per_s - 1 },
1424 .{ .s = "-999.999ms", .d = -(std.time.ns_per_s - 1) },
1425 .{ .s = "1s", .d = std.time.ns_per_s },
1426 .{ .s = "-1s", .d = -(std.time.ns_per_s) },
1427 .{ .s = "59.999s", .d = std.time.ns_per_min - 1 },
1428 .{ .s = "-59.999s", .d = -(std.time.ns_per_min - 1) },
1429 .{ .s = "1m", .d = std.time.ns_per_min },
1430 .{ .s = "-1m", .d = -(std.time.ns_per_min) },
1431 .{ .s = "1h", .d = std.time.ns_per_hour },
1432 .{ .s = "-1h", .d = -(std.time.ns_per_hour) },
1433 .{ .s = "1d", .d = std.time.ns_per_day },
1434 .{ .s = "-1d", .d = -(std.time.ns_per_day) },
1435 .{ .s = "1w", .d = std.time.ns_per_week },
1436 .{ .s = "-1w", .d = -(std.time.ns_per_week) },
1437 .{ .s = "1y", .d = 365 * std.time.ns_per_day },
1438 .{ .s = "-1y", .d = -(365 * std.time.ns_per_day) },
1439 .{ .s = "1y52w23h59m59.999s", .d = 730 * std.time.ns_per_day - 1 }, // 365d = 52w1d
1440 .{ .s = "-1y52w23h59m59.999s", .d = -(730 * std.time.ns_per_day - 1) }, // 365d = 52w1d
1441 .{ .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 },
1442 .{ .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) },
1443 .{ .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 },
1444 .{ .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) },
1445 .{ .s = "1y1h999.999us", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1 },
1446 .{ .s = "-1y1h999.999us", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1) },
1447 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms },
1448 .{ .s = "-1y1h1ms", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms) },
1449 .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 },
1450 .{ .s = "-1y1h1ms", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1) },
1451 .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 },
1452 .{ .s = "-1y1m999ns", .d = -(365 * std.time.ns_per_day + std.time.ns_per_min + 999) },
1453 .{ .s = "292y24w3d23h47m16.854s", .d = math.maxInt(i64) },
1454 .{ .s = "-292y24w3d23h47m16.854s", .d = math.minInt(i64) + 1 },
1455 .{ .s = "-292y24w3d23h47m16.854s", .d = math.minInt(i64) },
1456 }) |tc| {
1457 const slice = try bufPrint(&buf, "{}", .{fmtDurationSigned(tc.d)});
1458 try std.testing.expectEqualStrings(tc.s, slice);
1459 }
1460
1461 inline for (.{
1462 .{ .s = "=======0ns", .f = "{s:=>10}", .d = 0 },
1463 .{ .s = "1ns=======", .f = "{s:=<10}", .d = 1 },
1464 .{ .s = "-1ns======", .f = "{s:=<10}", .d = -(1) },
1465 .{ .s = " -999ns ", .f = "{s:^10}", .d = -(std.time.ns_per_us - 1) },
1466 }) |tc| {
1467 const slice = try bufPrint(&buf, tc.f, .{fmtDurationSigned(tc.d)});
1468 try std.testing.expectEqualStrings(tc.s, slice);
1469 }
310 const ex: Example = .{ .number = 'a' };
311 try expectFmt("a", "{f}", .{alt(ex, .other)});
1470312}
1471313
1472314pub const ParseIntError = error{
1473 /// The result cannot fit in the type specified
315 /// The result cannot fit in the type specified.
1474316 Overflow,
1475
1476 /// The input was empty or contained an invalid character
317 /// The input was empty or contained an invalid character.
1477318 InvalidCharacter,
1478319};
1479320
1480/// Creates a Formatter type from a format function. Wrapping data in Formatter(func) causes
1481/// the data to be formatted using the given function `func`. `func` must be of the following
1482/// form:
1483///
1484/// fn formatExample(
1485/// data: T,
1486/// comptime fmt: []const u8,
1487/// options: std.fmt.FormatOptions,
1488/// writer: anytype,
1489/// ) !void;
1490///
1491pub fn Formatter(comptime formatFn: anytype) type {
1492 const Data = @typeInfo(@TypeOf(formatFn)).@"fn".params[0].type.?;
1493 return struct {
1494 data: Data,
1495 pub fn format(
1496 self: @This(),
1497 comptime fmt: []const u8,
1498 options: std.fmt.FormatOptions,
1499 writer: anytype,
1500 ) @TypeOf(writer).Error!void {
1501 try formatFn(self.data, fmt, options, writer);
1502 }
1503 };
1504}
1505
1506321/// Parses the string `buf` as signed or unsigned representation in the
1507322/// specified base of an integral value of type `T`.
1508323///
......@@ -1793,15 +608,13 @@ pub const BufPrintError = error{
1793608 NoSpaceLeft,
1794609};
1795610
1796/// Print a Formatter string into `buf`. Actually just a thin wrapper around `format` and `fixedBufferStream`.
1797/// Returns a slice of the bytes printed to.
611/// Print a Formatter string into `buf`. Returns a slice of the bytes printed.
1798612pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 {
1799 var fbs = std.io.fixedBufferStream(buf);
1800 format(fbs.writer().any(), fmt, args) catch |err| switch (err) {
1801 error.NoSpaceLeft => return error.NoSpaceLeft,
1802 else => unreachable,
613 var w: Writer = .fixed(buf);
614 w.print(fmt, args) catch |err| switch (err) {
615 error.WriteFailed => return error.NoSpaceLeft,
1803616 };
1804 return fbs.getWritten();
617 return w.buffered();
1805618}
1806619
1807620pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![:0]u8 {
......@@ -1809,51 +622,37 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr
1809622 return result[0 .. result.len - 1 :0];
1810623}
1811624
1812/// Count the characters needed for format. Useful for preallocating memory
1813pub fn count(comptime fmt: []const u8, args: anytype) u64 {
1814 var counting_writer = std.io.countingWriter(std.io.null_writer);
1815 format(counting_writer.writer().any(), fmt, args) catch unreachable;
1816 return counting_writer.bytes_written;
1817}
1818
1819pub const AllocPrintError = error{OutOfMemory};
1820
1821pub fn allocPrint(allocator: mem.Allocator, comptime fmt: []const u8, args: anytype) AllocPrintError![]u8 {
1822 const size = math.cast(usize, count(fmt, args)) orelse return error.OutOfMemory;
1823 const buf = try allocator.alloc(u8, size);
1824 return bufPrint(buf, fmt, args) catch |err| switch (err) {
1825 error.NoSpaceLeft => unreachable, // we just counted the size above
625/// Count the characters needed for format.
626pub fn count(comptime fmt: []const u8, args: anytype) usize {
627 var trash_buffer: [64]u8 = undefined;
628 var dw: Writer.Discarding = .init(&trash_buffer);
629 dw.writer.print(fmt, args) catch |err| switch (err) {
630 error.WriteFailed => unreachable,
1826631 };
632 return @intCast(dw.count + dw.writer.end);
1827633}
1828634
1829pub fn allocPrintZ(allocator: mem.Allocator, comptime fmt: []const u8, args: anytype) AllocPrintError![:0]u8 {
1830 const result = try allocPrint(allocator, fmt ++ "\x00", args);
1831 return result[0 .. result.len - 1 :0];
1832}
1833
1834test bufPrintIntToSlice {
1835 var buffer: [100]u8 = undefined;
1836 const buf = buffer[0..];
1837
1838 try std.testing.expectEqualSlices(u8, "-1", bufPrintIntToSlice(buf, @as(i1, -1), 10, .lower, FormatOptions{}));
1839
1840 try std.testing.expectEqualSlices(u8, "-101111000110000101001110", bufPrintIntToSlice(buf, @as(i32, -12345678), 2, .lower, FormatOptions{}));
1841 try std.testing.expectEqualSlices(u8, "-12345678", bufPrintIntToSlice(buf, @as(i32, -12345678), 10, .lower, FormatOptions{}));
1842 try std.testing.expectEqualSlices(u8, "-bc614e", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, .lower, FormatOptions{}));
1843 try std.testing.expectEqualSlices(u8, "-BC614E", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, .upper, FormatOptions{}));
1844
1845 try std.testing.expectEqualSlices(u8, "12345678", bufPrintIntToSlice(buf, @as(u32, 12345678), 10, .upper, FormatOptions{}));
1846
1847 try std.testing.expectEqualSlices(u8, " 666", bufPrintIntToSlice(buf, @as(u32, 666), 10, .lower, FormatOptions{ .width = 6 }));
1848 try std.testing.expectEqualSlices(u8, " 1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, .lower, FormatOptions{ .width = 6 }));
1849 try std.testing.expectEqualSlices(u8, "1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, .lower, FormatOptions{ .width = 1 }));
1850
1851 try std.testing.expectEqualSlices(u8, "+42", bufPrintIntToSlice(buf, @as(i32, 42), 10, .lower, FormatOptions{ .width = 3 }));
1852 try std.testing.expectEqualSlices(u8, "-42", bufPrintIntToSlice(buf, @as(i32, -42), 10, .lower, FormatOptions{ .width = 3 }));
635pub fn allocPrint(gpa: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error![]u8 {
636 var aw = try Writer.Allocating.initCapacity(gpa, fmt.len);
637 defer aw.deinit();
638 aw.writer.print(fmt, args) catch |err| switch (err) {
639 error.WriteFailed => return error.OutOfMemory,
640 };
641 return aw.toOwnedSlice();
1853642}
1854643
1855pub fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, case: Case, options: FormatOptions) []u8 {
1856 return buf[0..formatIntBuf(buf, value, base, case, options)];
644pub fn allocPrintSentinel(
645 gpa: Allocator,
646 comptime fmt: []const u8,
647 args: anytype,
648 comptime sentinel: u8,
649) Allocator.Error![:sentinel]u8 {
650 var aw = try Writer.Allocating.initCapacity(gpa, fmt.len);
651 defer aw.deinit();
652 aw.writer.print(fmt, args) catch |err| switch (err) {
653 error.WriteFailed => return error.OutOfMemory,
654 };
655 return aw.toOwnedSliceSentinel(sentinel);
1857656}
1858657
1859658pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 {
......@@ -1984,26 +783,22 @@ test "int.padded" {
1984783 try expectFmt("i16: '-12345'", "i16: '{:4}'", .{@as(i16, -12345)});
1985784 try expectFmt("i16: '+12345'", "i16: '{:4}'", .{@as(i16, 12345)});
1986785 try expectFmt("u16: '12345'", "u16: '{:4}'", .{@as(u16, 12345)});
1987
1988 try expectFmt("UTF-8: 'ü '", "UTF-8: '{u:<4}'", .{'ü'});
1989 try expectFmt("UTF-8: ' ü'", "UTF-8: '{u:>4}'", .{'ü'});
1990 try expectFmt("UTF-8: ' ü '", "UTF-8: '{u:^4}'", .{'ü'});
1991786}
1992787
1993788test "buffer" {
1994789 {
1995790 var buf1: [32]u8 = undefined;
1996 var fbs = std.io.fixedBufferStream(&buf1);
1997 try formatType(1234, "", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth);
1998 try std.testing.expectEqualStrings("1234", fbs.getWritten());
791 var w: Writer = .fixed(&buf1);
792 try w.printValue("", .{}, 1234, std.options.fmt_max_depth);
793 try std.testing.expectEqualStrings("1234", w.buffered());
1999794
2000 fbs.reset();
2001 try formatType('a', "c", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth);
2002 try std.testing.expectEqualStrings("a", fbs.getWritten());
795 w = .fixed(&buf1);
796 try w.printValue("c", .{}, 'a', std.options.fmt_max_depth);
797 try std.testing.expectEqualStrings("a", w.buffered());
2003798
2004 fbs.reset();
2005 try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth);
2006 try std.testing.expectEqualStrings("1100", fbs.getWritten());
799 w = .fixed(&buf1);
800 try w.printValue("b", .{}, 0b1100, std.options.fmt_max_depth);
801 try std.testing.expectEqualStrings("1100", w.buffered());
2007802 }
2008803}
2009804
......@@ -2017,36 +812,24 @@ fn expectArrayFmt(expected: []const u8, comptime template: []const u8, comptime
2017812}
2018813
2019814test "array" {
2020 {
2021 const value: [3]u8 = "abc".*;
2022 try expectArrayFmt("array: abc\n", "array: {s}\n", value);
2023 try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {d}\n", value);
2024 try expectArrayFmt("array: { 61, 62, 63 }\n", "array: {x}\n", value);
2025 try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {any}\n", value);
2026
2027 var buf: [100]u8 = undefined;
2028 try expectFmt(
2029 try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@intFromPtr(&value)}),
2030 "array: {*}\n",
2031 .{&value},
2032 );
2033 }
2034
2035 {
2036 const value = [2][3]u8{ "abc".*, "def".* };
815 const value: [3]u8 = "abc".*;
816 try expectArrayFmt("array: abc\n", "array: {s}\n", value);
817 try expectArrayFmt("array: 616263\n", "array: {x}\n", value);
818 try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {any}\n", value);
2037819
2038 try expectArrayFmt("array: { abc, def }\n", "array: {s}\n", value);
2039 try expectArrayFmt("array: { { 97, 98, 99 }, { 100, 101, 102 } }\n", "array: {d}\n", value);
2040 try expectArrayFmt("array: { { 61, 62, 63 }, { 64, 65, 66 } }\n", "array: {x}\n", value);
2041 }
820 var buf: [100]u8 = undefined;
821 try expectFmt(
822 try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@intFromPtr(&value)}),
823 "array: {*}\n",
824 .{&value},
825 );
2042826}
2043827
2044828test "slice" {
2045829 {
2046830 const value: []const u8 = "abc";
2047831 try expectFmt("slice: abc\n", "slice: {s}\n", .{value});
2048 try expectFmt("slice: { 97, 98, 99 }\n", "slice: {d}\n", .{value});
2049 try expectFmt("slice: { 61, 62, 63 }\n", "slice: {x}\n", .{value});
832 try expectFmt("slice: 616263\n", "slice: {x}\n", .{value});
2050833 try expectFmt("slice: { 97, 98, 99 }\n", "slice: {any}\n", .{value});
2051834 }
2052835 {
......@@ -2060,45 +843,33 @@ test "slice" {
2060843 try expectFmt("buf: \x00hello\x00\n", "buf: {s}\n", .{null_term_slice});
2061844 }
2062845
2063 try expectFmt("buf: Test\n", "buf: {s:5}\n", .{"Test"});
2064846 try expectFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
2065847
2066848 {
2067849 var int_slice = [_]u32{ 1, 4096, 391891, 1111111111 };
2068 var runtime_zero: usize = 0;
2069 _ = &runtime_zero;
2070 try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {any}", .{int_slice[runtime_zero..]});
2071 try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {d}", .{int_slice[runtime_zero..]});
2072 try expectFmt("int: { 1, 1000, 5fad3, 423a35c7 }", "int: {x}", .{int_slice[runtime_zero..]});
2073 try expectFmt("int: { 00001, 01000, 5fad3, 423a35c7 }", "int: {x:0>5}", .{int_slice[runtime_zero..]});
850 const input: []const u32 = &int_slice;
851 try expectFmt("int: { 1, 4096, 391891, 1111111111 }", "int: {any}", .{input});
2074852 }
2075853 {
2076854 const S1 = struct {
2077855 x: u8,
2078856 };
2079857 const struct_slice: []const S1 = &[_]S1{ S1{ .x = 8 }, S1{ .x = 42 } };
2080 try expectFmt("slice: { fmt.test.slice.S1{ .x = 8 }, fmt.test.slice.S1{ .x = 42 } }", "slice: {any}", .{struct_slice});
858 try expectFmt("slice: { .{ .x = 8 }, .{ .x = 42 } }", "slice: {any}", .{struct_slice});
2081859 }
2082860 {
2083861 const S2 = struct {
2084862 x: u8,
2085863
2086 pub fn format(s: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
864 pub fn format(s: @This(), writer: *Writer) Writer.Error!void {
2087865 try writer.print("S2({})", .{s.x});
2088866 }
2089867 };
2090868 const struct_slice: []const S2 = &[_]S2{ S2{ .x = 8 }, S2{ .x = 42 } };
2091 try expectFmt("slice: { S2(8), S2(42) }", "slice: {any}", .{struct_slice});
869 try expectFmt("slice: { .{ .x = 8 }, .{ .x = 42 } }", "slice: {any}", .{struct_slice});
2092870 }
2093871}
2094872
2095test "escape non-printable" {
2096 try expectFmt("abc 123", "{s}", .{fmtSliceEscapeLower("abc 123")});
2097 try expectFmt("ab\\xffc", "{s}", .{fmtSliceEscapeLower("ab\xffc")});
2098 try expectFmt("abc 123", "{s}", .{fmtSliceEscapeUpper("abc 123")});
2099 try expectFmt("ab\\xFFc", "{s}", .{fmtSliceEscapeUpper("ab\xffc")});
2100}
2101
2102873test "pointer" {
2103874 {
2104875 const value = @as(*align(1) i32, @ptrFromInt(0xdeadbeef));
......@@ -2122,26 +893,6 @@ test "cstr" {
2122893 "cstr: {s}\n",
2123894 .{@as([*c]const u8, @ptrCast("Test C"))},
2124895 );
2125 try expectFmt(
2126 "cstr: Test C\n",
2127 "cstr: {s:10}\n",
2128 .{@as([*c]const u8, @ptrCast("Test C"))},
2129 );
2130}
2131
2132test "filesize" {
2133 try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeDec(42)});
2134 try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeBin(42)});
2135 try expectFmt("file size: 63MB\n", "file size: {}\n", .{fmtIntSizeDec(63 * 1000 * 1000)});
2136 try expectFmt("file size: 63MiB\n", "file size: {}\n", .{fmtIntSizeBin(63 * 1024 * 1024)});
2137 try expectFmt("file size: 42B\n", "file size: {:.2}\n", .{fmtIntSizeDec(42)});
2138 try expectFmt("file size: 42B\n", "file size: {:>9.2}\n", .{fmtIntSizeDec(42)});
2139 try expectFmt("file size: 66.06MB\n", "file size: {:.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
2140 try expectFmt("file size: 60.08MiB\n", "file size: {:.2}\n", .{fmtIntSizeBin(63 * 1000 * 1000)});
2141 try expectFmt("file size: =66.06MB=\n", "file size: {:=^9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
2142 try expectFmt("file size: 66.06MB\n", "file size: {: >9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
2143 try expectFmt("file size: 66.06MB \n", "file size: {: <9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)});
2144 try expectFmt("file size: 0.01844674407370955ZB\n", "file size: {}\n", .{fmtIntSizeDec(math.maxInt(u64))});
2145896}
2146897
2147898test "struct" {
......@@ -2150,8 +901,8 @@ test "struct" {
2150901 field: u8,
2151902 };
2152903 const value = Struct{ .field = 42 };
2153 try expectFmt("struct: fmt.test.struct.Struct{ .field = 42 }\n", "struct: {}\n", .{value});
2154 try expectFmt("struct: fmt.test.struct.Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
904 try expectFmt("struct: .{ .field = 42 }\n", "struct: {}\n", .{value});
905 try expectFmt("struct: .{ .field = 42 }\n", "struct: {}\n", .{&value});
2155906 }
2156907 {
2157908 const Struct = struct {
......@@ -2159,7 +910,7 @@ test "struct" {
2159910 b: u1,
2160911 };
2161912 const value = Struct{ .a = 0, .b = 1 };
2162 try expectFmt("struct: fmt.test.struct.Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
913 try expectFmt("struct: .{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
2163914 }
2164915
2165916 const S = struct {
......@@ -2172,11 +923,11 @@ test "struct" {
2172923 .b = error.Unused,
2173924 };
2174925
2175 try expectFmt("fmt.test.struct.S{ .a = 456, .b = error.Unused }", "{}", .{inst});
926 try expectFmt(".{ .a = 456, .b = error.Unused }", "{}", .{inst});
2176927 // Tuples
2177 try expectFmt("{ }", "{}", .{.{}});
2178 try expectFmt("{ -1 }", "{}", .{.{-1}});
2179 try expectFmt("{ -1, 42, 2.5e4 }", "{}", .{.{ -1, 42, 0.25e5 }});
928 try expectFmt(".{ }", "{}", .{.{}});
929 try expectFmt(".{ -1 }", "{}", .{.{-1}});
930 try expectFmt(".{ -1, 42, 25000 }", "{}", .{.{ -1, 42, 0.25e5 }});
2180931}
2181932
2182933test "enum" {
......@@ -2185,15 +936,15 @@ test "enum" {
2185936 Two,
2186937 };
2187938 const value = Enum.Two;
2188 try expectFmt("enum: fmt.test.enum.Enum.Two\n", "enum: {}\n", .{value});
2189 try expectFmt("enum: fmt.test.enum.Enum.Two\n", "enum: {}\n", .{&value});
2190 try expectFmt("enum: fmt.test.enum.Enum.One\n", "enum: {}\n", .{Enum.One});
2191 try expectFmt("enum: fmt.test.enum.Enum.Two\n", "enum: {}\n", .{Enum.Two});
939 try expectFmt("enum: .Two\n", "enum: {}\n", .{value});
940 try expectFmt("enum: .Two\n", "enum: {}\n", .{&value});
941 try expectFmt("enum: .One\n", "enum: {}\n", .{Enum.One});
942 try expectFmt("enum: .Two\n", "enum: {}\n", .{Enum.Two});
2192943
2193944 // test very large enum to verify ct branch quota is large enough
2194945 // TODO: https://github.com/ziglang/zig/issues/15609
2195946 if (!((builtin.cpu.arch == .wasm32) and builtin.mode == .Debug)) {
2196 try expectFmt("enum: os.windows.win32error.Win32Error.INVALID_FUNCTION\n", "enum: {}\n", .{std.os.windows.Win32Error.INVALID_FUNCTION});
947 try expectFmt("enum: .INVALID_FUNCTION\n", "enum: {}\n", .{std.os.windows.Win32Error.INVALID_FUNCTION});
2197948 }
2198949
2199950 const E = enum {
......@@ -2204,7 +955,7 @@ test "enum" {
2204955
2205956 const inst = E.Two;
2206957
2207 try expectFmt("fmt.test.enum.E.Two", "{}", .{inst});
958 try expectFmt(".Two", "{}", .{inst});
2208959}
2209960
2210961test "non-exhaustive enum" {
......@@ -2213,13 +964,17 @@ test "non-exhaustive enum" {
2213964 Two = 0xbeef,
2214965 _,
2215966 };
2216 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.One\n", "enum: {}\n", .{Enum.One});
2217 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {}\n", .{Enum.Two});
2218 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum(4660)\n", "enum: {}\n", .{@as(Enum, @enumFromInt(0x1234))});
2219 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.One\n", "enum: {x}\n", .{Enum.One});
2220 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {x}\n", .{Enum.Two});
2221 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {X}\n", .{Enum.Two});
2222 try expectFmt("enum: fmt.test.non-exhaustive enum.Enum(1234)\n", "enum: {x}\n", .{@as(Enum, @enumFromInt(0x1234))});
967 try expectFmt("enum: .One\n", "enum: {}\n", .{Enum.One});
968 try expectFmt("enum: .Two\n", "enum: {}\n", .{Enum.Two});
969 try expectFmt("enum: @enumFromInt(4660)\n", "enum: {}\n", .{@as(Enum, @enumFromInt(0x1234))});
970 try expectFmt("enum: f\n", "enum: {x}\n", .{Enum.One});
971 try expectFmt("enum: beef\n", "enum: {x}\n", .{Enum.Two});
972 try expectFmt("enum: BEEF\n", "enum: {X}\n", .{Enum.Two});
973 try expectFmt("enum: 1234\n", "enum: {x}\n", .{@as(Enum, @enumFromInt(0x1234))});
974
975 try expectFmt("enum: 15\n", "enum: {d}\n", .{Enum.One});
976 try expectFmt("enum: 48879\n", "enum: {d}\n", .{Enum.Two});
977 try expectFmt("enum: 4660\n", "enum: {d}\n", .{@as(Enum, @enumFromInt(0x1234))});
2223978}
2224979
2225980test "float.scientific" {
......@@ -2345,41 +1100,6 @@ test "float.libc.sanity" {
23451100 try expectFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @as(f32, @bitCast(@as(u32, 1518338049))))});
23461101}
23471102
2348test "custom" {
2349 const Vec2 = struct {
2350 const SelfType = @This();
2351 x: f32,
2352 y: f32,
2353
2354 pub fn format(
2355 self: SelfType,
2356 comptime fmt: []const u8,
2357 options: FormatOptions,
2358 writer: anytype,
2359 ) !void {
2360 _ = options;
2361 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
2362 return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y });
2363 } else if (comptime std.mem.eql(u8, fmt, "d")) {
2364 return std.fmt.format(writer, "{d:.3}x{d:.3}", .{ self.x, self.y });
2365 } else {
2366 @compileError("unknown format character: '" ++ fmt ++ "'");
2367 }
2368 }
2369 };
2370
2371 var value = Vec2{
2372 .x = 10.2,
2373 .y = 2.22,
2374 };
2375 try expectFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
2376 try expectFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
2377
2378 // same thing but not passing a pointer
2379 try expectFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
2380 try expectFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
2381}
2382
23831103test "union" {
23841104 const TU = union(enum) {
23851105 float: f32,
......@@ -2396,18 +1116,13 @@ test "union" {
23961116 int: u32,
23971117 };
23981118
2399 const tu_inst = TU{ .int = 123 };
2400 const uu_inst = UU{ .int = 456 };
2401 const eu_inst = EU{ .float = 321.123 };
2402
2403 try expectFmt("fmt.test.union.TU{ .int = 123 }", "{}", .{tu_inst});
1119 const tu_inst: TU = .{ .int = 123 };
1120 const uu_inst: UU = .{ .int = 456 };
1121 const eu_inst: EU = .{ .float = 321.123 };
24041122
2405 var buf: [100]u8 = undefined;
2406 const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
2407 try std.testing.expectEqualStrings("fmt.test.union.UU@", uu_result[0..18]);
2408
2409 const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
2410 try std.testing.expectEqualStrings("fmt.test.union.EU@", eu_result[0..18]);
1123 try expectFmt(".{ .int = 123 }", "{}", .{tu_inst});
1124 try expectFmt(".{ ... }", "{}", .{uu_inst});
1125 try expectFmt(".{ .float = 321.123, .int = 1134596030 }", "{}", .{eu_inst});
24111126}
24121127
24131128test "struct.self-referential" {
......@@ -2421,7 +1136,7 @@ test "struct.self-referential" {
24211136 };
24221137 inst.a = &inst;
24231138
2424 try expectFmt("fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ ... } } } }", "{}", .{inst});
1139 try expectFmt(".{ .a = .{ .a = .{ .a = .{ ... } } } }", "{}", .{inst});
24251140}
24261141
24271142test "struct.zero-size" {
......@@ -2436,18 +1151,7 @@ test "struct.zero-size" {
24361151 const a = A{};
24371152 const b = B{ .a = a, .c = 0 };
24381153
2439 try expectFmt("fmt.test.struct.zero-size.B{ .a = fmt.test.struct.zero-size.A{ }, .c = 0 }", "{}", .{b});
2440}
2441
2442test "bytes.hex" {
2443 const some_bytes = "\xCA\xFE\xBA\xBE";
2444 try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes)});
2445 try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes)});
2446 //Test Slices
2447 try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes[0..2])});
2448 try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes[2..])});
2449 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
2450 try expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(bytes_with_zeros)});
1154 try expectFmt(".{ .a = .{ }, .c = 0 }", "{}", .{b});
24511155}
24521156
24531157/// Encodes a sequence of bytes as hexadecimal digits.
......@@ -2494,110 +1198,14 @@ test bytesToHex {
24941198
24951199test hexToBytes {
24961200 var buf: [32]u8 = undefined;
2497 try expectFmt("90" ** 32, "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "90" ** 32))});
2498 try expectFmt("ABCD", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "ABCD"))});
2499 try expectFmt("", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, ""))});
1201 try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)});
1202 try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")});
1203 try expectFmt("", "{X}", .{try hexToBytes(&buf, "")});
25001204 try std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z"));
25011205 try std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA"));
25021206 try std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB"));
25031207}
25041208
2505test "formatIntValue with comptime_int" {
2506 const value: comptime_int = 123456789123456789;
2507
2508 var buf: [20]u8 = undefined;
2509 var fbs = std.io.fixedBufferStream(&buf);
2510 try formatIntValue(value, "", FormatOptions{}, fbs.writer());
2511 try std.testing.expectEqualStrings("123456789123456789", fbs.getWritten());
2512}
2513
2514test "formatFloatValue with comptime_float" {
2515 const value: comptime_float = 1.0;
2516
2517 var buf: [20]u8 = undefined;
2518 var fbs = std.io.fixedBufferStream(&buf);
2519 try formatFloatValue(value, "", FormatOptions{}, fbs.writer());
2520 try std.testing.expectEqualStrings(fbs.getWritten(), "1e0");
2521
2522 try expectFmt("1e0", "{}", .{value});
2523 try expectFmt("1e0", "{}", .{1.0});
2524}
2525
2526test "formatType max_depth" {
2527 const Vec2 = struct {
2528 const SelfType = @This();
2529 x: f32,
2530 y: f32,
2531
2532 pub fn format(
2533 self: SelfType,
2534 comptime fmt: []const u8,
2535 options: FormatOptions,
2536 writer: anytype,
2537 ) !void {
2538 _ = options;
2539 if (fmt.len == 0) {
2540 return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y });
2541 } else {
2542 @compileError("unknown format string: '" ++ fmt ++ "'");
2543 }
2544 }
2545 };
2546 const E = enum {
2547 One,
2548 Two,
2549 Three,
2550 };
2551 const TU = union(enum) {
2552 const SelfType = @This();
2553 float: f32,
2554 int: u32,
2555 ptr: ?*SelfType,
2556 };
2557 const S = struct {
2558 const SelfType = @This();
2559 a: ?*SelfType,
2560 tu: TU,
2561 e: E,
2562 vec: Vec2,
2563 };
2564
2565 var inst = S{
2566 .a = null,
2567 .tu = TU{ .ptr = null },
2568 .e = E.Two,
2569 .vec = Vec2{ .x = 10.2, .y = 2.22 },
2570 };
2571 inst.a = &inst;
2572 inst.tu.ptr = &inst.tu;
2573
2574 var buf: [1000]u8 = undefined;
2575 var fbs = std.io.fixedBufferStream(&buf);
2576 try formatType(inst, "", FormatOptions{}, fbs.writer(), 0);
2577 try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ ... }", fbs.getWritten());
2578
2579 fbs.reset();
2580 try formatType(inst, "", FormatOptions{}, fbs.writer(), 1);
2581 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());
2582
2583 fbs.reset();
2584 try formatType(inst, "", FormatOptions{}, fbs.writer(), 2);
2585 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());
2586
2587 fbs.reset();
2588 try formatType(inst, "", FormatOptions{}, fbs.writer(), 3);
2589 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());
2590
2591 const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 };
2592 fbs.reset();
2593 try formatType(vec, "", FormatOptions{}, fbs.writer(), 0);
2594 try std.testing.expectEqualStrings("{ ... }", fbs.getWritten());
2595
2596 fbs.reset();
2597 try formatType(vec, "", FormatOptions{}, fbs.writer(), 1);
2598 try std.testing.expectEqualStrings("{ 1, 2, 3, 4 }", fbs.getWritten());
2599}
2600
26011209test "positional" {
26021210 try expectFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
26031211 try expectFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
......@@ -2654,33 +1262,17 @@ test "enum-literal" {
26541262
26551263test "padding" {
26561264 try expectFmt("Simple", "{s}", .{"Simple"});
2657 try expectFmt(" true", "{:10}", .{true});
2658 try expectFmt(" true", "{:>10}", .{true});
2659 try expectFmt("======true", "{:=>10}", .{true});
2660 try expectFmt("true======", "{:=<10}", .{true});
2661 try expectFmt(" true ", "{:^10}", .{true});
2662 try expectFmt("===true===", "{:=^10}", .{true});
2663 try expectFmt(" Minimum width", "{s:18} width", .{"Minimum"});
2664 try expectFmt("==================Filled", "{s:=>24}", .{"Filled"});
2665 try expectFmt(" Centered ", "{s:^24}", .{"Centered"});
2666 try expectFmt("-", "{s:-^1}", .{""});
2667 try expectFmt("==crêpe===", "{s:=^10}", .{"crêpe"});
2668 try expectFmt("=====crêpe", "{s:=>10}", .{"crêpe"});
2669 try expectFmt("crêpe=====", "{s:=<10}", .{"crêpe"});
1265 try expectFmt(" 1234", "{:10}", .{1234});
1266 try expectFmt(" 1234", "{:>10}", .{1234});
1267 try expectFmt("======1234", "{:=>10}", .{1234});
1268 try expectFmt("1234======", "{:=<10}", .{1234});
1269 try expectFmt(" 1234 ", "{:^10}", .{1234});
1270 try expectFmt("===1234===", "{:=^10}", .{1234});
26701271 try expectFmt("====a", "{c:=>5}", .{'a'});
26711272 try expectFmt("==a==", "{c:=^5}", .{'a'});
26721273 try expectFmt("a====", "{c:=<5}", .{'a'});
26731274}
26741275
2675test "padding fill char utf" {
2676 try expectFmt("──crêpe───", "{s:─^10}", .{"crêpe"});
2677 try expectFmt("─────crêpe", "{s:─>10}", .{"crêpe"});
2678 try expectFmt("crêpe─────", "{s:─<10}", .{"crêpe"});
2679 try expectFmt("────a", "{c:─>5}", .{'a'});
2680 try expectFmt("──a──", "{c:─^5}", .{'a'});
2681 try expectFmt("a────", "{c:─<5}", .{'a'});
2682}
2683
26841276test "decimal float padding" {
26851277 const number: f32 = 3.1415;
26861278 try expectFmt("left-pad: **3.142\n", "left-pad: {d:*>7.3}\n", .{number});
......@@ -2723,17 +1315,17 @@ test "named arguments" {
27231315
27241316test "runtime width specifier" {
27251317 const width: usize = 9;
2726 try expectFmt("~~hello~~", "{s:~^[1]}", .{ "hello", width });
2727 try expectFmt("~~hello~~", "{s:~^[width]}", .{ .string = "hello", .width = width });
2728 try expectFmt(" hello", "{s:[1]}", .{ "hello", width });
2729 try expectFmt("42 hello", "{d} {s:[2]}", .{ 42, "hello", width });
1318 try expectFmt("~~12345~~", "{d:~^[1]}", .{ 12345, width });
1319 try expectFmt("~~12345~~", "{d:~^[width]}", .{ .string = 12345, .width = width });
1320 try expectFmt(" 12345", "{d:[1]}", .{ 12345, width });
1321 try expectFmt("42 12345", "{d} {d:[2]}", .{ 42, 12345, width });
27301322}
27311323
27321324test "runtime precision specifier" {
27331325 const number: f32 = 3.1415;
27341326 const precision: usize = 2;
2735 try expectFmt("3.14e0", "{:1.[1]}", .{ number, precision });
2736 try expectFmt("3.14e0", "{:1.[precision]}", .{ .number = number, .precision = precision });
1327 try expectFmt("3.14e0", "{e:1.[1]}", .{ number, precision });
1328 try expectFmt("3.14e0", "{e:1.[precision]}", .{ .number = number, .precision = precision });
27371329}
27381330
27391331test "recursive format function" {
......@@ -2742,16 +1334,16 @@ test "recursive format function" {
27421334 Leaf: i32,
27431335 Branch: struct { left: *const R, right: *const R },
27441336
2745 pub fn format(self: R, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
1337 pub fn format(self: R, writer: *Writer) Writer.Error!void {
27461338 return switch (self) {
2747 .Leaf => |n| std.fmt.format(writer, "Leaf({})", .{n}),
2748 .Branch => |b| std.fmt.format(writer, "Branch({}, {})", .{ b.left, b.right }),
1339 .Leaf => |n| writer.print("Leaf({})", .{n}),
1340 .Branch => |b| writer.print("Branch({f}, {f})", .{ b.left, b.right }),
27491341 };
27501342 }
27511343 };
27521344
2753 var r = R{ .Leaf = 1 };
2754 try expectFmt("Leaf(1)\n", "{}\n", .{&r});
1345 var r: R = .{ .Leaf = 1 };
1346 try expectFmt("Leaf(1)\n", "{f}\n", .{&r});
27551347}
27561348
27571349pub const hex_charset = "0123456789abcdef";
......@@ -2785,54 +1377,39 @@ test hex {
27851377
27861378test "parser until" {
27871379 { // return substring till ':'
2788 var parser: Parser = .{
2789 .iter = .{ .bytes = "abc:1234", .i = 0 },
2790 };
1380 var parser: Parser = .{ .bytes = "abc:1234", .i = 0 };
27911381 try testing.expectEqualStrings("abc", parser.until(':'));
27921382 }
27931383
27941384 { // return the entire string - `ch` not found
2795 var parser: Parser = .{
2796 .iter = .{ .bytes = "abc1234", .i = 0 },
2797 };
1385 var parser: Parser = .{ .bytes = "abc1234", .i = 0 };
27981386 try testing.expectEqualStrings("abc1234", parser.until(':'));
27991387 }
28001388
28011389 { // substring is empty - `ch` is the only character
2802 var parser: Parser = .{
2803 .iter = .{ .bytes = ":", .i = 0 },
2804 };
1390 var parser: Parser = .{ .bytes = ":", .i = 0 };
28051391 try testing.expectEqualStrings("", parser.until(':'));
28061392 }
28071393
28081394 { // empty string and `ch` not found
2809 var parser: Parser = .{
2810 .iter = .{ .bytes = "", .i = 0 },
2811 };
1395 var parser: Parser = .{ .bytes = "", .i = 0 };
28121396 try testing.expectEqualStrings("", parser.until(':'));
28131397 }
28141398
28151399 { // substring starts at index 2 and goes upto `ch`
2816 var parser: Parser = .{
2817 .iter = .{ .bytes = "abc:1234", .i = 2 },
2818 };
1400 var parser: Parser = .{ .bytes = "abc:1234", .i = 2 };
28191401 try testing.expectEqualStrings("c", parser.until(':'));
28201402 }
28211403
28221404 { // substring starts at index 4 and goes upto the end - `ch` not found
2823 var parser: Parser = .{
2824 .iter = .{ .bytes = "abc1234", .i = 4 },
2825 };
1405 var parser: Parser = .{ .bytes = "abc1234", .i = 4 };
28261406 try testing.expectEqualStrings("234", parser.until(':'));
28271407 }
28281408}
28291409
28301410test "parser peek" {
28311411 { // start iteration from the first index
2832 var parser: Parser = .{
2833 .iter = .{ .bytes = "hello world", .i = 0 },
2834 };
2835
1412 var parser: Parser = .{ .bytes = "hello world", .i = 0 };
28361413 try testing.expectEqual('h', parser.peek(0));
28371414 try testing.expectEqual('e', parser.peek(1));
28381415 try testing.expectEqual(' ', parser.peek(5));
......@@ -2841,9 +1418,7 @@ test "parser peek" {
28411418 }
28421419
28431420 { // start iteration from the second last index
2844 var parser: Parser = .{
2845 .iter = .{ .bytes = "hello world!", .i = 10 },
2846 };
1421 var parser: Parser = .{ .bytes = "hello world!", .i = 10 };
28471422
28481423 try testing.expectEqual('d', parser.peek(0));
28491424 try testing.expectEqual('!', parser.peek(1));
......@@ -2851,18 +1426,14 @@ test "parser peek" {
28511426 }
28521427
28531428 { // start iteration beyond the length of the string
2854 var parser: Parser = .{
2855 .iter = .{ .bytes = "hello", .i = 5 },
2856 };
1429 var parser: Parser = .{ .bytes = "hello", .i = 5 };
28571430
28581431 try testing.expectEqual(null, parser.peek(0));
28591432 try testing.expectEqual(null, parser.peek(1));
28601433 }
28611434
28621435 { // empty string
2863 var parser: Parser = .{
2864 .iter = .{ .bytes = "", .i = 0 },
2865 };
1436 var parser: Parser = .{ .bytes = "", .i = 0 };
28661437
28671438 try testing.expectEqual(null, parser.peek(0));
28681439 try testing.expectEqual(null, parser.peek(2));
......@@ -2871,78 +1442,78 @@ test "parser peek" {
28711442
28721443test "parser char" {
28731444 // character exists - iterator at 0
2874 var parser: Parser = .{ .iter = .{ .bytes = "~~hello", .i = 0 } };
1445 var parser: Parser = .{ .bytes = "~~hello", .i = 0 };
28751446 try testing.expectEqual('~', parser.char());
28761447
28771448 // character exists - iterator in the middle
2878 parser = .{ .iter = .{ .bytes = "~~hello", .i = 3 } };
1449 parser = .{ .bytes = "~~hello", .i = 3 };
28791450 try testing.expectEqual('e', parser.char());
28801451
28811452 // character exists - iterator at the end
2882 parser = .{ .iter = .{ .bytes = "~~hello", .i = 6 } };
1453 parser = .{ .bytes = "~~hello", .i = 6 };
28831454 try testing.expectEqual('o', parser.char());
28841455
28851456 // character doesn't exist - iterator beyond the length of the string
2886 parser = .{ .iter = .{ .bytes = "~~hello", .i = 7 } };
1457 parser = .{ .bytes = "~~hello", .i = 7 };
28871458 try testing.expectEqual(null, parser.char());
28881459}
28891460
28901461test "parser maybe" {
28911462 // character exists - iterator at 0
2892 var parser: Parser = .{ .iter = .{ .bytes = "hello world", .i = 0 } };
1463 var parser: Parser = .{ .bytes = "hello world", .i = 0 };
28931464 try testing.expect(parser.maybe('h'));
28941465
28951466 // character exists - iterator at space
2896 parser = .{ .iter = .{ .bytes = "hello world", .i = 5 } };
1467 parser = .{ .bytes = "hello world", .i = 5 };
28971468 try testing.expect(parser.maybe(' '));
28981469
28991470 // character exists - iterator at the end
2900 parser = .{ .iter = .{ .bytes = "hello world", .i = 10 } };
1471 parser = .{ .bytes = "hello world", .i = 10 };
29011472 try testing.expect(parser.maybe('d'));
29021473
29031474 // character doesn't exist - iterator beyond the length of the string
2904 parser = .{ .iter = .{ .bytes = "hello world", .i = 11 } };
1475 parser = .{ .bytes = "hello world", .i = 11 };
29051476 try testing.expect(!parser.maybe('e'));
29061477}
29071478
29081479test "parser number" {
29091480 // input is a single digit natural number - iterator at 0
2910 var parser: Parser = .{ .iter = .{ .bytes = "7", .i = 0 } };
1481 var parser: Parser = .{ .bytes = "7", .i = 0 };
29111482 try testing.expect(7 == parser.number());
29121483
29131484 // input is a two digit natural number - iterator at 1
2914 parser = .{ .iter = .{ .bytes = "29", .i = 1 } };
1485 parser = .{ .bytes = "29", .i = 1 };
29151486 try testing.expect(9 == parser.number());
29161487
29171488 // input is a two digit natural number - iterator beyond the length of the string
2918 parser = .{ .iter = .{ .bytes = "32", .i = 2 } };
1489 parser = .{ .bytes = "32", .i = 2 };
29191490 try testing.expectEqual(null, parser.number());
29201491
29211492 // input is an integer
2922 parser = .{ .iter = .{ .bytes = "0", .i = 0 } };
1493 parser = .{ .bytes = "0", .i = 0 };
29231494 try testing.expect(0 == parser.number());
29241495
29251496 // input is a negative integer
2926 parser = .{ .iter = .{ .bytes = "-2", .i = 0 } };
1497 parser = .{ .bytes = "-2", .i = 0 };
29271498 try testing.expectEqual(null, parser.number());
29281499
29291500 // input is a string
2930 parser = .{ .iter = .{ .bytes = "no_number", .i = 2 } };
1501 parser = .{ .bytes = "no_number", .i = 2 };
29311502 try testing.expectEqual(null, parser.number());
29321503
29331504 // input is a single character string
2934 parser = .{ .iter = .{ .bytes = "n", .i = 0 } };
1505 parser = .{ .bytes = "n", .i = 0 };
29351506 try testing.expectEqual(null, parser.number());
29361507
29371508 // input is an empty string
2938 parser = .{ .iter = .{ .bytes = "", .i = 0 } };
1509 parser = .{ .bytes = "", .i = 0 };
29391510 try testing.expectEqual(null, parser.number());
29401511}
29411512
29421513test "parser specifier" {
29431514 { // input string is a digit; iterator at 0
29441515 const expected: Specifier = Specifier{ .number = 1 };
2945 var parser: Parser = .{ .iter = .{ .bytes = "1", .i = 0 } };
1516 var parser: Parser = .{ .bytes = "1", .i = 0 };
29461517
29471518 const result = try parser.specifier();
29481519 try testing.expect(expected.number == result.number);
......@@ -2950,7 +1521,7 @@ test "parser specifier" {
29501521
29511522 { // input string is a two digit number; iterator at 0
29521523 const digit: Specifier = Specifier{ .number = 42 };
2953 var parser: Parser = .{ .iter = .{ .bytes = "42", .i = 0 } };
1524 var parser: Parser = .{ .bytes = "42", .i = 0 };
29541525
29551526 const result = try parser.specifier();
29561527 try testing.expect(digit.number == result.number);
......@@ -2958,7 +1529,7 @@ test "parser specifier" {
29581529
29591530 { // input string is a two digit number digit; iterator at 1
29601531 const digit: Specifier = Specifier{ .number = 8 };
2961 var parser: Parser = .{ .iter = .{ .bytes = "28", .i = 1 } };
1532 var parser: Parser = .{ .bytes = "28", .i = 1 };
29621533
29631534 const result = try parser.specifier();
29641535 try testing.expect(digit.number == result.number);
......@@ -2966,7 +1537,7 @@ test "parser specifier" {
29661537
29671538 { // input string is a two digit number with square brackets; iterator at 0
29681539 const digit: Specifier = Specifier{ .named = "15" };
2969 var parser: Parser = .{ .iter = .{ .bytes = "[15]", .i = 0 } };
1540 var parser: Parser = .{ .bytes = "[15]", .i = 0 };
29701541
29711542 const result = try parser.specifier();
29721543 try testing.expectEqualStrings(digit.named, result.named);
......@@ -2974,21 +1545,21 @@ test "parser specifier" {
29741545
29751546 { // input string is not a number and contains square brackets; iterator at 0
29761547 const digit: Specifier = Specifier{ .named = "hello" };
2977 var parser: Parser = .{ .iter = .{ .bytes = "[hello]", .i = 0 } };
1548 var parser: Parser = .{ .bytes = "[hello]", .i = 0 };
29781549
29791550 const result = try parser.specifier();
29801551 try testing.expectEqualStrings(digit.named, result.named);
29811552 }
29821553
29831554 { // input string is not a number and doesn't contain closing square bracket; iterator at 0
2984 var parser: Parser = .{ .iter = .{ .bytes = "[hello", .i = 0 } };
1555 var parser: Parser = .{ .bytes = "[hello", .i = 0 };
29851556
29861557 const result = parser.specifier();
29871558 try testing.expectError(@field(anyerror, "Expected closing ]"), result);
29881559 }
29891560
29901561 { // input string is not a number and doesn't contain closing square bracket; iterator at 2
2991 var parser: Parser = .{ .iter = .{ .bytes = "[[[[hello", .i = 2 } };
1562 var parser: Parser = .{ .bytes = "[[[[hello", .i = 2 };
29921563
29931564 const result = parser.specifier();
29941565 try testing.expectError(@field(anyerror, "Expected closing ]"), result);
......@@ -2996,7 +1567,7 @@ test "parser specifier" {
29961567
29971568 { // input string is not a number and contains unbalanced square brackets; iterator at 0
29981569 const digit: Specifier = Specifier{ .named = "[[hello" };
2999 var parser: Parser = .{ .iter = .{ .bytes = "[[[hello]", .i = 0 } };
1570 var parser: Parser = .{ .bytes = "[[[hello]", .i = 0 };
30001571
30011572 const result = try parser.specifier();
30021573 try testing.expectEqualStrings(digit.named, result.named);
......@@ -3004,7 +1575,7 @@ test "parser specifier" {
30041575
30051576 { // input string is not a number and contains unbalanced square brackets; iterator at 1
30061577 const digit: Specifier = Specifier{ .named = "[[hello" };
3007 var parser: Parser = .{ .iter = .{ .bytes = "[[[[hello]]]]]", .i = 1 } };
1578 var parser: Parser = .{ .bytes = "[[[[hello]]]]]", .i = 1 };
30081579
30091580 const result = try parser.specifier();
30101581 try testing.expectEqualStrings(digit.named, result.named);
......@@ -3012,9 +1583,13 @@ test "parser specifier" {
30121583
30131584 { // input string is neither a digit nor a named argument
30141585 const char: Specifier = Specifier{ .none = {} };
3015 var parser: Parser = .{ .iter = .{ .bytes = "hello", .i = 0 } };
1586 var parser: Parser = .{ .bytes = "hello", .i = 0 };
30161587
30171588 const result = try parser.specifier();
30181589 try testing.expectEqual(char.none, result.none);
30191590 }
30201591}
1592
1593test {
1594 _ = float;
1595}
lib/std/fmt/float.zig created+1695
......@@ -0,0 +1,1695 @@
1//! This file implements the ryu floating point conversion algorithm:
2//! https://dl.acm.org/doi/pdf/10.1145/3360595
3
4const std = @import("std");
5const expectFmt = std.testing.expectFmt;
6
7const special_exponent = 0x7fffffff;
8
9/// Any buffer used for `format` must be at least this large. This is asserted. A runtime check will
10/// additionally be performed if more bytes are required.
11pub const min_buffer_size = 53;
12
13/// Returns the minimum buffer size needed to print every float of a specific type and format.
14pub fn bufferSize(comptime mode: Mode, comptime T: type) comptime_int {
15 comptime std.debug.assert(@typeInfo(T) == .float);
16 return switch (mode) {
17 .scientific => 53,
18 // Based on minimum subnormal values.
19 .decimal => switch (@bitSizeOf(T)) {
20 16 => @max(15, min_buffer_size),
21 32 => 55,
22 64 => 347,
23 80 => 4996,
24 128 => 5011,
25 else => unreachable,
26 },
27 };
28}
29
30pub const Error = error{
31 BufferTooSmall,
32};
33
34pub const Mode = enum {
35 scientific,
36 decimal,
37};
38
39pub const Options = struct {
40 mode: Mode = .scientific,
41 precision: ?usize = null,
42};
43
44/// Format a floating-point value and write it to buffer. Returns a slice to the buffer containing
45/// the string representation.
46///
47/// Full precision is the default. Any full precision float can be reparsed with std.fmt.parseFloat
48/// unambiguously.
49///
50/// Scientific mode is recommended generally as the output is more compact and any type can be
51/// written in full precision using a buffer of only `min_buffer_size`.
52///
53/// When printing full precision decimals, use `bufferSize` to get the required space. It is
54/// recommended to bound decimal output with a fixed precision to reduce the required buffer size.
55pub fn render(buf: []u8, value: anytype, options: Options) Error![]const u8 {
56 const v = switch (@TypeOf(value)) {
57 // comptime_float internally is a f128; this preserves precision.
58 comptime_float => @as(f128, value),
59 else => value,
60 };
61
62 const T = @TypeOf(v);
63 comptime std.debug.assert(@typeInfo(T) == .float);
64 const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
65
66 const DT = if (@bitSizeOf(T) <= 64) u64 else u128;
67 const tables = switch (DT) {
68 u64 => if (@import("builtin").mode == .ReleaseSmall) &Backend64_TablesSmall else &Backend64_TablesFull,
69 u128 => &Backend128_Tables,
70 else => unreachable,
71 };
72
73 const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0;
74 const d = binaryToDecimal(DT, @as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit, tables);
75
76 return switch (options.mode) {
77 .scientific => formatScientific(DT, buf, d, options.precision),
78 .decimal => formatDecimal(DT, buf, d, options.precision),
79 };
80}
81
82pub fn FloatDecimal(comptime T: type) type {
83 comptime std.debug.assert(T == u64 or T == u128);
84 return struct {
85 mantissa: T,
86 exponent: i32,
87 sign: bool,
88 };
89}
90
91fn copySpecialStr(buf: []u8, f: anytype) []const u8 {
92 if (f.sign) {
93 buf[0] = '-';
94 }
95 const offset: usize = @intFromBool(f.sign);
96 if (f.mantissa != 0) {
97 @memcpy(buf[offset..][0..3], "nan");
98 return buf[0 .. 3 + offset];
99 }
100 @memcpy(buf[offset..][0..3], "inf");
101 return buf[0 .. 3 + offset];
102}
103
104fn writeDecimal(buf: []u8, value: anytype, count: usize) void {
105 var i: usize = 0;
106
107 while (i + 2 < count) : (i += 2) {
108 const c: u8 = @intCast(value.* % 100);
109 value.* /= 100;
110 const d = std.fmt.digits2(c);
111 buf[count - i - 1] = d[1];
112 buf[count - i - 2] = d[0];
113 }
114
115 while (i < count) : (i += 1) {
116 const c: u8 = @intCast(value.* % 10);
117 value.* /= 10;
118 buf[count - i - 1] = '0' + c;
119 }
120}
121
122fn isPowerOf10(n_: u128) bool {
123 var n = n_;
124 while (n != 0) : (n /= 10) {
125 if (n % 10 != 0) return false;
126 }
127 return true;
128}
129
130const RoundMode = enum {
131 /// 1234.56 = precision 2
132 decimal,
133 /// 1.23456e3 = precision 5
134 scientific,
135};
136
137fn round(comptime T: type, f: FloatDecimal(T), mode: RoundMode, precision: usize) FloatDecimal(T) {
138 var round_digit: usize = 0;
139 var output = f.mantissa;
140 var exp = f.exponent;
141 const olength = decimalLength(output);
142
143 switch (mode) {
144 .decimal => {
145 if (f.exponent > 0) {
146 round_digit = (olength - 1) + precision + @as(usize, @intCast(f.exponent));
147 } else {
148 const min_exp_required = @as(usize, @intCast(-f.exponent));
149 if (precision + olength > min_exp_required) {
150 round_digit = precision + olength - min_exp_required;
151 }
152 }
153 },
154 .scientific => {
155 round_digit = 1 + precision;
156 },
157 }
158
159 if (round_digit < olength) {
160 var nlength = olength;
161 for (round_digit + 1..olength) |_| {
162 output /= 10;
163 exp += 1;
164 nlength -= 1;
165 }
166
167 if (output % 10 >= 5) {
168 output /= 10;
169 output += 1;
170 exp += 1;
171
172 // e.g. 9999 -> 10000
173 if (isPowerOf10(output)) {
174 output /= 10;
175 exp += 1;
176 }
177 }
178 }
179
180 return .{
181 .mantissa = output,
182 .exponent = exp,
183 .sign = f.sign,
184 };
185}
186
187/// Write a FloatDecimal to a buffer in scientific form.
188///
189/// The buffer provided must be greater than `min_buffer_size` in length. If no precision is
190/// specified, this function will never return an error. If a precision is specified, up to
191/// `8 + precision` bytes will be written to the buffer. An error will be returned if the content
192/// will not fit.
193///
194/// It is recommended to bound decimal formatting with an exact precision.
195pub fn formatScientific(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) Error![]const u8 {
196 std.debug.assert(buf.len >= min_buffer_size);
197 var f = f_;
198
199 if (f.exponent == special_exponent) {
200 return copySpecialStr(buf, f);
201 }
202
203 if (precision) |prec| {
204 f = round(T, f, .scientific, prec);
205 }
206
207 var output = f.mantissa;
208 const olength = decimalLength(output);
209
210 if (precision) |prec| {
211 // fixed bound: sign(1) + leading_digit(1) + point(1) + exp_sign(1) + exp_max(4)
212 const req_bytes = 8 + prec;
213 if (buf.len < req_bytes) {
214 return error.BufferTooSmall;
215 }
216 }
217
218 // Step 5: Print the scientific representation
219 var index: usize = 0;
220 if (f.sign) {
221 buf[index] = '-';
222 index += 1;
223 }
224
225 // 1.12345
226 writeDecimal(buf[index + 2 ..], &output, olength - 1);
227 buf[index] = '0' + @as(u8, @intCast(output % 10));
228 buf[index + 1] = '.';
229 index += 2;
230 const dp_index = index;
231 if (olength > 1) index += olength - 1 else index -= 1;
232
233 if (precision) |prec| {
234 index += @intFromBool(olength == 1);
235 if (prec > olength - 1) {
236 const len = prec - (olength - 1);
237 @memset(buf[index..][0..len], '0');
238 index += len;
239 } else {
240 index = dp_index + prec - @intFromBool(prec == 0);
241 }
242 }
243
244 // e100
245 buf[index] = 'e';
246 index += 1;
247 var exp = f.exponent + @as(i32, @intCast(olength)) - 1;
248 if (exp < 0) {
249 buf[index] = '-';
250 index += 1;
251 exp = -exp;
252 }
253 var uexp: u32 = @intCast(exp);
254 const elength = decimalLength(uexp);
255 writeDecimal(buf[index..], &uexp, elength);
256 index += elength;
257
258 return buf[0..index];
259}
260
261/// Write a FloatDecimal to a buffer in decimal form.
262///
263/// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is
264/// specified, this may still return an error. If precision is specified, `2 + precision` bytes will
265/// always be written.
266pub fn formatDecimal(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) Error![]const u8 {
267 std.debug.assert(buf.len >= min_buffer_size);
268 var f = f_;
269
270 if (f.exponent == special_exponent) {
271 return copySpecialStr(buf, f);
272 }
273
274 if (precision) |prec| {
275 f = round(T, f, .decimal, prec);
276 }
277
278 var output = f.mantissa;
279 const olength = decimalLength(output);
280
281 // fixed bound: leading_digit(1) + point(1)
282 const req_bytes = if (f.exponent >= 0)
283 @as(usize, 2) + @abs(f.exponent) + olength + (precision orelse 0)
284 else
285 @as(usize, 2) + @max(@abs(f.exponent) + olength, precision orelse 0);
286 if (buf.len < req_bytes) {
287 return error.BufferTooSmall;
288 }
289
290 // Step 5: Print the decimal representation
291 var index: usize = 0;
292 if (f.sign) {
293 buf[index] = '-';
294 index += 1;
295 }
296
297 const dp_offset = f.exponent + cast_i32(olength);
298 if (dp_offset <= 0) {
299 // 0.000001234
300 buf[index] = '0';
301 buf[index + 1] = '.';
302 index += 2;
303 const dp_index = index;
304
305 const dp_poffset: u32 = @intCast(-dp_offset);
306 @memset(buf[index..][0..dp_poffset], '0');
307 index += dp_poffset;
308 writeDecimal(buf[index..], &output, olength);
309 index += olength;
310
311 if (precision) |prec| {
312 const dp_written = index - dp_index;
313 if (prec > dp_written) {
314 @memset(buf[index..][0 .. prec - dp_written], '0');
315 }
316 index = dp_index + prec - @intFromBool(prec == 0);
317 }
318 } else {
319 // 123456000
320 const dp_uoffset: usize = @intCast(dp_offset);
321 if (dp_uoffset >= olength) {
322 writeDecimal(buf[index..], &output, olength);
323 index += olength;
324 @memset(buf[index..][0 .. dp_uoffset - olength], '0');
325 index += dp_uoffset - olength;
326
327 if (precision) |prec| {
328 if (prec != 0) {
329 buf[index] = '.';
330 index += 1;
331 @memset(buf[index..][0..prec], '0');
332 index += prec;
333 }
334 }
335 } else {
336 // 12345.6789
337 writeDecimal(buf[index + dp_uoffset + 1 ..], &output, olength - dp_uoffset);
338 buf[index + dp_uoffset] = '.';
339 const dp_index = index + dp_uoffset + 1;
340 writeDecimal(buf[index..], &output, dp_uoffset);
341 index += olength + 1;
342
343 if (precision) |prec| {
344 const dp_written = olength - dp_uoffset;
345 if (prec > dp_written) {
346 @memset(buf[index..][0 .. prec - dp_written], '0');
347 }
348 index = dp_index + prec - @intFromBool(prec == 0);
349 }
350 }
351 }
352
353 return buf[0..index];
354}
355
356fn cast_i32(v: anytype) i32 {
357 return @intCast(v);
358}
359
360/// Convert a binary float representation to decimal.
361pub fn binaryToDecimal(comptime T: type, bits: T, mantissa_bits: std.math.Log2Int(T), exponent_bits: u5, explicit_leading_bit: bool, comptime tables: anytype) FloatDecimal(T) {
362 if (T != tables.T) {
363 @compileError("table type does not match backend type: " ++ @typeName(tables.T) ++ " != " ++ @typeName(T));
364 }
365
366 const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1;
367 const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
368 const ieee_mantissa = bits & ((@as(T, 1) << mantissa_bits) - 1);
369 const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(T, 1) << exponent_bits) - 1));
370
371 if (ieee_exponent == 0 and ieee_mantissa == 0) {
372 return .{
373 .mantissa = 0,
374 .exponent = 0,
375 .sign = ieee_sign,
376 };
377 }
378 if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) {
379 return .{
380 .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(T, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa,
381 .exponent = special_exponent,
382 .sign = ieee_sign,
383 };
384 }
385
386 var e2: i32 = undefined;
387 var m2: T = undefined;
388 if (explicit_leading_bit) {
389 if (ieee_exponent == 0) {
390 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
391 } else {
392 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
393 }
394 m2 = ieee_mantissa;
395 } else {
396 if (ieee_exponent == 0) {
397 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
398 m2 = ieee_mantissa;
399 } else {
400 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
401 m2 = (@as(T, 1) << mantissa_bits) | ieee_mantissa;
402 }
403 }
404 const even = (m2 & 1) == 0;
405 const accept_bounds = even;
406
407 // Step 2: Determine the interval of legal decimal representations.
408 const mv = 4 * m2;
409 const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(T, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0));
410
411 // Step 3: Convert to a decimal power base using 128-bit arithmetic.
412 var vr: T = undefined;
413 var vp: T = undefined;
414 var vm: T = undefined;
415 var e10: i32 = undefined;
416 var vm_is_trailing_zeros = false;
417 var vr_is_trailing_zeros = false;
418 if (e2 >= 0) {
419 const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3);
420 e10 = cast_i32(q);
421 const k: i32 = @intCast(tables.POW5_INV_BITCOUNT + pow5Bits(q) - 1);
422 const i: u32 = @intCast(-e2 + cast_i32(q) + k);
423
424 const pow5 = tables.computeInvPow5(q);
425 vr = tables.mulShift(4 * m2, &pow5, i);
426 vp = tables.mulShift(4 * m2 + 2, &pow5, i);
427 vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, i);
428
429 if (q <= tables.bound1) {
430 if (mv % 5 == 0) {
431 vr_is_trailing_zeros = multipleOfPowerOf5(mv, if (tables.adjust_q) q -% 1 else q);
432 } else if (accept_bounds) {
433 vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q);
434 } else {
435 vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q));
436 }
437 }
438 } else {
439 const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1);
440 e10 = cast_i32(q) + e2;
441 const i: i32 = -e2 - cast_i32(q);
442 const k: i32 = cast_i32(pow5Bits(@intCast(i))) - tables.POW5_BITCOUNT;
443 const j: u32 = @intCast(cast_i32(q) - k);
444
445 const pow5 = tables.computePow5(@intCast(i));
446 vr = tables.mulShift(4 * m2, &pow5, j);
447 vp = tables.mulShift(4 * m2 + 2, &pow5, j);
448 vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, j);
449
450 if (q <= 1) {
451 vr_is_trailing_zeros = true;
452 if (accept_bounds) {
453 vm_is_trailing_zeros = mm_shift == 1;
454 } else {
455 vp -= 1;
456 }
457 } else if (q < tables.bound2) {
458 vr_is_trailing_zeros = multipleOfPowerOf2(mv, if (tables.adjust_q) q - 1 else q);
459 }
460 }
461
462 // Step 4: Find the shortest decimal representation in the interval of legal representations.
463 var removed: u32 = 0;
464 var last_removed_digit: u8 = 0;
465
466 while (vp / 10 > vm / 10) {
467 vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0;
468 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
469 last_removed_digit = @intCast(vr % 10);
470 vr /= 10;
471 vp /= 10;
472 vm /= 10;
473 removed += 1;
474 }
475
476 if (vm_is_trailing_zeros) {
477 while (vm % 10 == 0) {
478 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
479 last_removed_digit = @intCast(vr % 10);
480 vr /= 10;
481 vp /= 10;
482 vm /= 10;
483 removed += 1;
484 }
485 }
486
487 if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) {
488 last_removed_digit = 4;
489 }
490
491 return .{
492 .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5),
493 .exponent = e10 + cast_i32(removed),
494 .sign = ieee_sign,
495 };
496}
497
498fn decimalLength(v: anytype) u32 {
499 switch (@TypeOf(v)) {
500 u32, u64 => {
501 std.debug.assert(v < 100000000000000000);
502 if (v >= 10000000000000000) return 17;
503 if (v >= 1000000000000000) return 16;
504 if (v >= 100000000000000) return 15;
505 if (v >= 10000000000000) return 14;
506 if (v >= 1000000000000) return 13;
507 if (v >= 100000000000) return 12;
508 if (v >= 10000000000) return 11;
509 if (v >= 1000000000) return 10;
510 if (v >= 100000000) return 9;
511 if (v >= 10000000) return 8;
512 if (v >= 1000000) return 7;
513 if (v >= 100000) return 6;
514 if (v >= 10000) return 5;
515 if (v >= 1000) return 4;
516 if (v >= 100) return 3;
517 if (v >= 10) return 2;
518 return 1;
519 },
520 u128 => {
521 const LARGEST_POW10 = (@as(u128, 5421010862427522170) << 64) | 687399551400673280;
522 var p10 = LARGEST_POW10;
523 var i: u32 = 39;
524 while (i > 0) : (i -= 1) {
525 if (v >= p10) return i;
526 p10 /= 10;
527 }
528 return 1;
529 },
530 else => unreachable,
531 }
532}
533
534// floor(log_10(2^e))
535fn log10Pow2(e: u32) u32 {
536 std.debug.assert(e <= 1 << 15);
537 return @intCast((@as(u64, @intCast(e)) * 169464822037455) >> 49);
538}
539
540// floor(log_10(5^e))
541fn log10Pow5(e: u32) u32 {
542 std.debug.assert(e <= 1 << 15);
543 return @intCast((@as(u64, @intCast(e)) * 196742565691928) >> 48);
544}
545
546// if (e == 0) 1 else ceil(log_2(5^e))
547fn pow5Bits(e: u32) u32 {
548 std.debug.assert(e <= 1 << 15);
549 return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1);
550}
551
552fn pow5Factor(value_: anytype) u32 {
553 var count: u32 = 0;
554 var value = value_;
555 while (value > 0) : ({
556 count += 1;
557 value /= 5;
558 }) {
559 if (value % 5 != 0) return count;
560 }
561 return 0;
562}
563
564fn multipleOfPowerOf5(value: anytype, p: u32) bool {
565 const T = @TypeOf(value);
566 std.debug.assert(@typeInfo(T) == .int);
567 return pow5Factor(value) >= p;
568}
569
570fn multipleOfPowerOf2(value: anytype, p: u32) bool {
571 const T = @TypeOf(value);
572 std.debug.assert(@typeInfo(T) == .int);
573 return (value & ((@as(T, 1) << @as(std.math.Log2Int(T), @intCast(p))) - 1)) == 0;
574}
575
576fn mulShift128(m: u128, mul: *const [4]u64, j: u32) u128 {
577 std.debug.assert(j > 128);
578 const a: [2]u64 = .{ @truncate(m), @truncate(m >> 64) };
579 const r = mul_128_256_shift(&a, mul, j, 0);
580 return (@as(u128, r[1]) << 64) | r[0];
581}
582
583fn mul_128_256_shift(a: *const [2]u64, b: *const [4]u64, shift: u32, corr: u32) [4]u64 {
584 std.debug.assert(shift > 0);
585 std.debug.assert(shift < 256);
586
587 const b00 = @as(u128, a[0]) * b[0];
588 const b01 = @as(u128, a[0]) * b[1];
589 const b02 = @as(u128, a[0]) * b[2];
590 const b03 = @as(u128, a[0]) * b[3];
591 const b10 = @as(u128, a[1]) * b[0];
592 const b11 = @as(u128, a[1]) * b[1];
593 const b12 = @as(u128, a[1]) * b[2];
594 const b13 = @as(u128, a[1]) * b[3];
595
596 const s0 = b00;
597 const s1 = b01 +% b10;
598 const c1: u128 = @intFromBool(s1 < b01);
599 const s2 = b02 +% b11;
600 const c2: u128 = @intFromBool(s2 < b02);
601 const s3 = b03 +% b12;
602 const c3: u128 = @intFromBool(s3 < b03);
603
604 const p0 = s0 +% (s1 << 64);
605 const d0: u128 = @intFromBool(p0 < b00);
606 const q1 = s2 +% (s1 >> 64) +% (s3 << 64);
607 const d1: u128 = @intFromBool(q1 < s2);
608 const p1 = q1 +% (c1 << 64) +% d0;
609 const d2: u128 = @intFromBool(p1 < q1);
610 const p2 = b13 +% (s3 >> 64) +% c2 +% (c3 << 64) +% d1 +% d2;
611
612 var r0: u128 = undefined;
613 var r1: u128 = undefined;
614 if (shift < 128) {
615 const cshift: u7 = @intCast(shift);
616 const sshift: u7 = @intCast(128 - shift);
617 r0 = corr +% ((p0 >> cshift) | (p1 << sshift));
618 r1 = ((p1 >> cshift) | (p2 << sshift)) +% @intFromBool(r0 < corr);
619 } else if (shift == 128) {
620 r0 = corr +% p1;
621 r1 = p2 +% @intFromBool(r0 < corr);
622 } else {
623 const ashift: u7 = @intCast(shift - 128);
624 const sshift: u7 = @intCast(256 - shift);
625 r0 = corr +% ((p1 >> ashift) | (p2 << sshift));
626 r1 = (p2 >> ashift) +% @intFromBool(r0 < corr);
627 }
628
629 return .{ @truncate(r0), @truncate(r0 >> 64), @truncate(r1), @truncate(r1 >> 64) };
630}
631
632pub const Backend128_Tables = struct {
633 const T = u128;
634 const mulShift = mulShift128;
635 const POW5_INV_BITCOUNT = FLOAT128_POW5_INV_BITCOUNT;
636 const POW5_BITCOUNT = FLOAT128_POW5_BITCOUNT;
637
638 const bound1 = 55;
639 const bound2 = 127;
640 const adjust_q = true;
641
642 fn computePow5(i: u32) [4]u64 {
643 const base = i / FLOAT128_POW5_TABLE_SIZE;
644 const base2 = base * FLOAT128_POW5_TABLE_SIZE;
645 const mul = &FLOAT128_POW5_SPLIT[base];
646 if (i == base2) {
647 return mul.*;
648 } else {
649 const offset = i - base2;
650 const m = &FLOAT128_POW5_TABLE[offset];
651 const delta = pow5Bits(i) - pow5Bits(base2);
652
653 const shift: u6 = @intCast(2 * (i % 32));
654 const corr: u32 = @intCast((FLOAT128_POW5_ERRORS[i / 32] >> shift) & 3);
655 return mul_128_256_shift(m, mul, delta, corr);
656 }
657 }
658
659 fn computeInvPow5(i: u32) [4]u64 {
660 const base = (i + FLOAT128_POW5_TABLE_SIZE - 1) / FLOAT128_POW5_TABLE_SIZE;
661 const base2 = base * FLOAT128_POW5_TABLE_SIZE;
662 const mul = &FLOAT128_POW5_INV_SPLIT[base]; // 1 / 5^base2
663 if (i == base2) {
664 return .{ mul[0] + 1, mul[1], mul[2], mul[3] };
665 } else {
666 const offset = base2 - i;
667 const m = &FLOAT128_POW5_TABLE[offset]; // 5^offset
668 const delta = pow5Bits(base2) - pow5Bits(i);
669
670 const shift: u6 = @intCast(2 * (i % 32));
671 const corr: u32 = @intCast(((FLOAT128_POW5_INV_ERRORS[i / 32] >> shift) & 3) + 1);
672 return mul_128_256_shift(m, mul, delta, corr);
673 }
674 }
675};
676
677fn mulShift64(m: u64, mul: *const [2]u64, j: u32) u64 {
678 std.debug.assert(j > 64);
679 const b0 = @as(u128, m) * mul[0];
680 const b2 = @as(u128, m) * mul[1];
681
682 if (j < 128) {
683 const shift: u6 = @intCast(j - 64);
684 return @intCast(((b0 >> 64) + b2) >> shift);
685 } else {
686 return 0;
687 }
688}
689
690pub const Backend64_TablesFull = struct {
691 const T = u64;
692 const mulShift = mulShift64;
693 const POW5_INV_BITCOUNT = FLOAT64_POW5_INV_BITCOUNT;
694 const POW5_BITCOUNT = FLOAT64_POW5_BITCOUNT;
695
696 const bound1 = 21;
697 const bound2 = 63;
698 const adjust_q = false;
699
700 fn computePow5(i: u32) [2]u64 {
701 return FLOAT64_POW5_SPLIT[i];
702 }
703
704 fn computeInvPow5(i: u32) [2]u64 {
705 return FLOAT64_POW5_INV_SPLIT[i];
706 }
707};
708
709pub const Backend64_TablesSmall = struct {
710 const T = u64;
711 const mulShift = mulShift64;
712 const POW5_INV_BITCOUNT = FLOAT64_POW5_INV_BITCOUNT;
713 const POW5_BITCOUNT = FLOAT64_POW5_BITCOUNT;
714
715 const bound1 = 21;
716 const bound2 = 63;
717 const adjust_q = false;
718
719 fn computePow5(i: u32) [2]u64 {
720 const base = i / FLOAT64_POW5_TABLE_SIZE;
721 const base2 = base * FLOAT64_POW5_TABLE_SIZE;
722 const mul = &FLOAT64_POW5_SPLIT2[base];
723 if (i == base2) {
724 return .{ mul[0], mul[1] };
725 } else {
726 const offset = i - base2;
727 const m = FLOAT64_POW5_TABLE[offset];
728 const b0 = @as(u128, m) * mul[0];
729 const b2 = @as(u128, m) * mul[1];
730 const delta: u7 = @intCast(pow5Bits(i) - pow5Bits(base2));
731 const shift: u5 = @intCast((i % 16) << 1);
732 const shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((FLOAT64_POW5_OFFSETS[i / 16] >> shift) & 3);
733 return .{ @truncate(shifted_sum), @truncate(shifted_sum >> 64) };
734 }
735 }
736
737 fn computeInvPow5(i: u32) [2]u64 {
738 const base = (i + FLOAT64_POW5_TABLE_SIZE - 1) / FLOAT64_POW5_TABLE_SIZE;
739 const base2 = base * FLOAT64_POW5_TABLE_SIZE;
740 const mul = &FLOAT64_POW5_INV_SPLIT2[base]; // 1 / 5^base2
741 if (i == base2) {
742 return .{ mul[0], mul[1] };
743 } else {
744 const offset = base2 - i;
745 const m = FLOAT64_POW5_TABLE[offset]; // 5^offset
746 const b0 = @as(u128, m) * (mul[0] - 1);
747 const b2 = @as(u128, m) * mul[1]; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i
748 const delta: u7 = @intCast(pow5Bits(base2) - pow5Bits(i));
749 const shift: u5 = @intCast((i % 16) << 1);
750 const shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((FLOAT64_POW5_INV_OFFSETS[i / 16] >> shift) & 3);
751 return .{ @truncate(shifted_sum), @truncate(shifted_sum >> 64) };
752 }
753 }
754};
755
756const FLOAT64_POW5_INV_BITCOUNT = 125;
757const FLOAT64_POW5_BITCOUNT = 125;
758
759// zig fmt: off
760//
761// f64 small tables: 816 bytes
762
763const FLOAT64_POW5_TABLE_SIZE: comptime_int = FLOAT64_POW5_TABLE.len;
764
765const FLOAT64_POW5_TABLE: [26]u64 = .{
766 1, 5,
767 25, 125,
768 625, 3125,
769 15625, 78125,
770 390625, 1953125,
771 9765625, 48828125,
772 244140625, 1220703125,
773 6103515625, 30517578125,
774 152587890625, 762939453125,
775 3814697265625, 19073486328125,
776 95367431640625, 476837158203125,
777 2384185791015625, 11920928955078125,
778 59604644775390625, 298023223876953125,
779};
780
781const FLOAT64_POW5_SPLIT2: [13][2]u64 = .{
782 .{ 0, 1152921504606846976 },
783 .{ 0, 1490116119384765625 },
784 .{ 1032610780636961552, 1925929944387235853 },
785 .{ 7910200175544436838, 1244603055572228341 },
786 .{ 16941905809032713930, 1608611746708759036 },
787 .{ 13024893955298202172, 2079081953128979843 },
788 .{ 6607496772837067824, 1343575221513417750 },
789 .{ 17332926989895652603, 1736530273035216783 },
790 .{ 13037379183483547984, 2244412773384604712 },
791 .{ 1605989338741628675, 1450417759929778918 },
792 .{ 9630225068416591280, 1874621017369538693 },
793 .{ 665883850346957067, 1211445438634777304 },
794 .{ 14931890668723713708, 1565756531257009982 }
795};
796
797const FLOAT64_POW5_OFFSETS: [21]u32 = .{
798 0x00000000, 0x00000000, 0x00000000, 0x00000000,
799 0x40000000, 0x59695995, 0x55545555, 0x56555515,
800 0x41150504, 0x40555410, 0x44555145, 0x44504540,
801 0x45555550, 0x40004000, 0x96440440, 0x55565565,
802 0x54454045, 0x40154151, 0x55559155, 0x51405555,
803 0x00000105,
804};
805
806const FLOAT64_POW5_INV_SPLIT2: [15][2]u64 = .{
807 .{ 1, 2305843009213693952 },
808 .{ 5955668970331000884, 1784059615882449851 },
809 .{ 8982663654677661702, 1380349269358112757 },
810 .{ 7286864317269821294, 2135987035920910082 },
811 .{ 7005857020398200553, 1652639921975621497 },
812 .{ 17965325103354776697, 1278668206209430417 },
813 .{ 8928596168509315048, 1978643211784836272 },
814 .{ 10075671573058298858, 1530901034580419511 },
815 .{ 597001226353042382, 1184477304306571148 },
816 .{ 1527430471115325346, 1832889850782397517 },
817 .{ 12533209867169019542, 1418129833677084982 },
818 .{ 5577825024675947042, 2194449627517475473 },
819 .{ 11006974540203867551, 1697873161311732311 },
820 .{ 10313493231639821582, 1313665730009899186 },
821 .{ 12701016819766672773, 2032799256770390445 }
822};
823
824const FLOAT64_POW5_INV_OFFSETS: [19]u32 = .{
825 0x54544554, 0x04055545, 0x10041000, 0x00400414,
826 0x40010000, 0x41155555, 0x00000454, 0x00010044,
827 0x40000000, 0x44000041, 0x50454450, 0x55550054,
828 0x51655554, 0x40004000, 0x01000001, 0x00010500,
829 0x51515411, 0x05555554, 0x00000000,
830};
831
832
833// zig fmt: off
834
835// f64 full tables: 10688 bytes
836
837const FLOAT64_POW5_SPLIT: [326][2]u64 = .{
838 .{ 0, 1152921504606846976 }, .{ 0, 1441151880758558720 },
839 .{ 0, 1801439850948198400 }, .{ 0, 2251799813685248000 },
840 .{ 0, 1407374883553280000 }, .{ 0, 1759218604441600000 },
841 .{ 0, 2199023255552000000 }, .{ 0, 1374389534720000000 },
842 .{ 0, 1717986918400000000 }, .{ 0, 2147483648000000000 },
843 .{ 0, 1342177280000000000 }, .{ 0, 1677721600000000000 },
844 .{ 0, 2097152000000000000 }, .{ 0, 1310720000000000000 },
845 .{ 0, 1638400000000000000 }, .{ 0, 2048000000000000000 },
846 .{ 0, 1280000000000000000 }, .{ 0, 1600000000000000000 },
847 .{ 0, 2000000000000000000 }, .{ 0, 1250000000000000000 },
848 .{ 0, 1562500000000000000 }, .{ 0, 1953125000000000000 },
849 .{ 0, 1220703125000000000 }, .{ 0, 1525878906250000000 },
850 .{ 0, 1907348632812500000 }, .{ 0, 1192092895507812500 },
851 .{ 0, 1490116119384765625 }, .{ 4611686018427387904, 1862645149230957031 },
852 .{ 9799832789158199296, 1164153218269348144 }, .{ 12249790986447749120, 1455191522836685180 },
853 .{ 15312238733059686400, 1818989403545856475 }, .{ 14528612397897220096, 2273736754432320594 },
854 .{ 13692068767113150464, 1421085471520200371 }, .{ 12503399940464050176, 1776356839400250464 },
855 .{ 15629249925580062720, 2220446049250313080 }, .{ 9768281203487539200, 1387778780781445675 },
856 .{ 7598665485932036096, 1734723475976807094 }, .{ 274959820560269312, 2168404344971008868 },
857 .{ 9395221924704944128, 1355252715606880542 }, .{ 2520655369026404352, 1694065894508600678 },
858 .{ 12374191248137781248, 2117582368135750847 }, .{ 14651398557727195136, 1323488980084844279 },
859 .{ 13702562178731606016, 1654361225106055349 }, .{ 3293144668132343808, 2067951531382569187 },
860 .{ 18199116482078572544, 1292469707114105741 }, .{ 8913837547316051968, 1615587133892632177 },
861 .{ 15753982952572452864, 2019483917365790221 }, .{ 12152082354571476992, 1262177448353618888 },
862 .{ 15190102943214346240, 1577721810442023610 }, .{ 9764256642163156992, 1972152263052529513 },
863 .{ 17631875447420442880, 1232595164407830945 }, .{ 8204786253993389888, 1540743955509788682 },
864 .{ 1032610780636961552, 1925929944387235853 }, .{ 2951224747111794922, 1203706215242022408 },
865 .{ 3689030933889743652, 1504632769052528010 }, .{ 13834660704216955373, 1880790961315660012 },
866 .{ 17870034976990372916, 1175494350822287507 }, .{ 17725857702810578241, 1469367938527859384 },
867 .{ 3710578054803671186, 1836709923159824231 }, .{ 26536550077201078, 2295887403949780289 },
868 .{ 11545800389866720434, 1434929627468612680 }, .{ 14432250487333400542, 1793662034335765850 },
869 .{ 8816941072311974870, 2242077542919707313 }, .{ 17039803216263454053, 1401298464324817070 },
870 .{ 12076381983474541759, 1751623080406021338 }, .{ 5872105442488401391, 2189528850507526673 },
871 .{ 15199280947623720629, 1368455531567204170 }, .{ 9775729147674874978, 1710569414459005213 },
872 .{ 16831347453020981627, 2138211768073756516 }, .{ 1296220121283337709, 1336382355046097823 },
873 .{ 15455333206886335848, 1670477943807622278 }, .{ 10095794471753144002, 2088097429759527848 },
874 .{ 6309871544845715001, 1305060893599704905 }, .{ 12499025449484531656, 1631326116999631131 },
875 .{ 11012095793428276666, 2039157646249538914 }, .{ 11494245889320060820, 1274473528905961821 },
876 .{ 532749306367912313, 1593091911132452277 }, .{ 5277622651387278295, 1991364888915565346 },
877 .{ 7910200175544436838, 1244603055572228341 }, .{ 14499436237857933952, 1555753819465285426 },
878 .{ 8900923260467641632, 1944692274331606783 }, .{ 12480606065433357876, 1215432671457254239 },
879 .{ 10989071563364309441, 1519290839321567799 }, .{ 9124653435777998898, 1899113549151959749 },
880 .{ 8008751406574943263, 1186945968219974843 }, .{ 5399253239791291175, 1483682460274968554 },
881 .{ 15972438586593889776, 1854603075343710692 }, .{ 759402079766405302, 1159126922089819183 },
882 .{ 14784310654990170340, 1448908652612273978 }, .{ 9257016281882937117, 1811135815765342473 },
883 .{ 16182956370781059300, 2263919769706678091 }, .{ 7808504722524468110, 1414949856066673807 },
884 .{ 5148944884728197234, 1768687320083342259 }, .{ 1824495087482858639, 2210859150104177824 },
885 .{ 1140309429676786649, 1381786968815111140 }, .{ 1425386787095983311, 1727233711018888925 },
886 .{ 6393419502297367043, 2159042138773611156 }, .{ 13219259225790630210, 1349401336733506972 },
887 .{ 16524074032238287762, 1686751670916883715 }, .{ 16043406521870471799, 2108439588646104644 },
888 .{ 803757039314269066, 1317774742903815403 }, .{ 14839754354425000045, 1647218428629769253 },
889 .{ 4714634887749086344, 2059023035787211567 }, .{ 9864175832484260821, 1286889397367007229 },
890 .{ 16941905809032713930, 1608611746708759036 }, .{ 2730638187581340797, 2010764683385948796 },
891 .{ 10930020904093113806, 1256727927116217997 }, .{ 18274212148543780162, 1570909908895272496 },
892 .{ 4396021111970173586, 1963637386119090621 }, .{ 5053356204195052443, 1227273366324431638 },
893 .{ 15540067292098591362, 1534091707905539547 }, .{ 14813398096695851299, 1917614634881924434 },
894 .{ 13870059828862294966, 1198509146801202771 }, .{ 12725888767650480803, 1498136433501503464 },
895 .{ 15907360959563101004, 1872670541876879330 }, .{ 14553786618154326031, 1170419088673049581 },
896 .{ 4357175217410743827, 1463023860841311977 }, .{ 10058155040190817688, 1828779826051639971 },
897 .{ 7961007781811134206, 2285974782564549964 }, .{ 14199001900486734687, 1428734239102843727 },
898 .{ 13137066357181030455, 1785917798878554659 }, .{ 11809646928048900164, 2232397248598193324 },
899 .{ 16604401366885338411, 1395248280373870827 }, .{ 16143815690179285109, 1744060350467338534 },
900 .{ 10956397575869330579, 2180075438084173168 }, .{ 6847748484918331612, 1362547148802608230 },
901 .{ 17783057643002690323, 1703183936003260287 }, .{ 17617136035325974999, 2128979920004075359 },
902 .{ 17928239049719816230, 1330612450002547099 }, .{ 17798612793722382384, 1663265562503183874 },
903 .{ 13024893955298202172, 2079081953128979843 }, .{ 5834715712847682405, 1299426220705612402 },
904 .{ 16516766677914378815, 1624282775882015502 }, .{ 11422586310538197711, 2030353469852519378 },
905 .{ 11750802462513761473, 1268970918657824611 }, .{ 10076817059714813937, 1586213648322280764 },
906 .{ 12596021324643517422, 1982767060402850955 }, .{ 5566670318688504437, 1239229412751781847 },
907 .{ 2346651879933242642, 1549036765939727309 }, .{ 7545000868343941206, 1936295957424659136 },
908 .{ 4715625542714963254, 1210184973390411960 }, .{ 5894531928393704067, 1512731216738014950 },
909 .{ 16591536947346905892, 1890914020922518687 }, .{ 17287239619732898039, 1181821263076574179 },
910 .{ 16997363506238734644, 1477276578845717724 }, .{ 2799960309088866689, 1846595723557147156 },
911 .{ 10973347230035317489, 1154122327223216972 }, .{ 13716684037544146861, 1442652909029021215 },
912 .{ 12534169028502795672, 1803316136286276519 }, .{ 11056025267201106687, 2254145170357845649 },
913 .{ 18439230838069161439, 1408840731473653530 }, .{ 13825666510731675991, 1761050914342066913 },
914 .{ 3447025083132431277, 2201313642927583642 }, .{ 6766076695385157452, 1375821026829739776 },
915 .{ 8457595869231446815, 1719776283537174720 }, .{ 10571994836539308519, 2149720354421468400 },
916 .{ 6607496772837067824, 1343575221513417750 }, .{ 17482743002901110588, 1679469026891772187 },
917 .{ 17241742735199000331, 2099336283614715234 }, .{ 15387775227926763111, 1312085177259197021 },
918 .{ 5399660979626290177, 1640106471573996277 }, .{ 11361262242960250625, 2050133089467495346 },
919 .{ 11712474920277544544, 1281333180917184591 }, .{ 10028907631919542777, 1601666476146480739 },
920 .{ 7924448521472040567, 2002083095183100924 }, .{ 14176152362774801162, 1251301934489438077 },
921 .{ 3885132398186337741, 1564127418111797597 }, .{ 9468101516160310080, 1955159272639746996 },
922 .{ 15140935484454969608, 1221974545399841872 }, .{ 479425281859160394, 1527468181749802341 },
923 .{ 5210967620751338397, 1909335227187252926 }, .{ 17091912818251750210, 1193334516992033078 },
924 .{ 12141518985959911954, 1491668146240041348 }, .{ 15176898732449889943, 1864585182800051685 },
925 .{ 11791404716994875166, 1165365739250032303 }, .{ 10127569877816206054, 1456707174062540379 },
926 .{ 8047776328842869663, 1820883967578175474 }, .{ 836348374198811271, 2276104959472719343 },
927 .{ 7440246761515338900, 1422565599670449589 }, .{ 13911994470321561530, 1778206999588061986 },
928 .{ 8166621051047176104, 2222758749485077483 }, .{ 2798295147690791113, 1389224218428173427 },
929 .{ 17332926989895652603, 1736530273035216783 }, .{ 17054472718942177850, 2170662841294020979 },
930 .{ 8353202440125167204, 1356664275808763112 }, .{ 10441503050156459005, 1695830344760953890 },
931 .{ 3828506775840797949, 2119787930951192363 }, .{ 86973725686804766, 1324867456844495227 },
932 .{ 13943775212390669669, 1656084321055619033 }, .{ 3594660960206173375, 2070105401319523792 },
933 .{ 2246663100128858359, 1293815875824702370 }, .{ 12031700912015848757, 1617269844780877962 },
934 .{ 5816254103165035138, 2021587305976097453 }, .{ 5941001823691840913, 1263492066235060908 },
935 .{ 7426252279614801142, 1579365082793826135 }, .{ 4671129331091113523, 1974206353492282669 },
936 .{ 5225298841145639904, 1233878970932676668 }, .{ 6531623551432049880, 1542348713665845835 },
937 .{ 3552843420862674446, 1927935892082307294 }, .{ 16055585193321335241, 1204959932551442058 },
938 .{ 10846109454796893243, 1506199915689302573 }, .{ 18169322836923504458, 1882749894611628216 },
939 .{ 11355826773077190286, 1176718684132267635 }, .{ 9583097447919099954, 1470898355165334544 },
940 .{ 11978871809898874942, 1838622943956668180 }, .{ 14973589762373593678, 2298278679945835225 },
941 .{ 2440964573842414192, 1436424174966147016 }, .{ 3051205717303017741, 1795530218707683770 },
942 .{ 13037379183483547984, 2244412773384604712 }, .{ 8148361989677217490, 1402757983365377945 },
943 .{ 14797138505523909766, 1753447479206722431 }, .{ 13884737113477499304, 2191809349008403039 },
944 .{ 15595489723564518921, 1369880843130251899 }, .{ 14882676136028260747, 1712351053912814874 },
945 .{ 9379973133180550126, 2140438817391018593 }, .{ 17391698254306313589, 1337774260869386620 },
946 .{ 3292878744173340370, 1672217826086733276 }, .{ 4116098430216675462, 2090272282608416595 },
947 .{ 266718509671728212, 1306420176630260372 }, .{ 333398137089660265, 1633025220787825465 },
948 .{ 5028433689789463235, 2041281525984781831 }, .{ 10060300083759496378, 1275800953740488644 },
949 .{ 12575375104699370472, 1594751192175610805 }, .{ 1884160825592049379, 1993438990219513507 },
950 .{ 17318501580490888525, 1245899368887195941 }, .{ 7813068920331446945, 1557374211108994927 },
951 .{ 5154650131986920777, 1946717763886243659 }, .{ 915813323278131534, 1216698602428902287 },
952 .{ 14979824709379828129, 1520873253036127858 }, .{ 9501408849870009354, 1901091566295159823 },
953 .{ 12855909558809837702, 1188182228934474889 }, .{ 2234828893230133415, 1485227786168093612 },
954 .{ 2793536116537666769, 1856534732710117015 }, .{ 8663489100477123587, 1160334207943823134 },
955 .{ 1605989338741628675, 1450417759929778918 }, .{ 11230858710281811652, 1813022199912223647 },
956 .{ 9426887369424876662, 2266277749890279559 }, .{ 12809333633531629769, 1416423593681424724 },
957 .{ 16011667041914537212, 1770529492101780905 }, .{ 6179525747111007803, 2213161865127226132 },
958 .{ 13085575628799155685, 1383226165704516332 }, .{ 16356969535998944606, 1729032707130645415 },
959 .{ 15834525901571292854, 2161290883913306769 }, .{ 2979049660840976177, 1350806802445816731 },
960 .{ 17558870131333383934, 1688508503057270913 }, .{ 8113529608884566205, 2110635628821588642 },
961 .{ 9682642023980241782, 1319147268013492901 }, .{ 16714988548402690132, 1648934085016866126 },
962 .{ 11670363648648586857, 2061167606271082658 }, .{ 11905663298832754689, 1288229753919426661 },
963 .{ 1047021068258779650, 1610287192399283327 }, .{ 15143834390605638274, 2012858990499104158 },
964 .{ 4853210475701136017, 1258036869061940099 }, .{ 1454827076199032118, 1572546086327425124 },
965 .{ 1818533845248790147, 1965682607909281405 }, .{ 3442426662494187794, 1228551629943300878 },
966 .{ 13526405364972510550, 1535689537429126097 }, .{ 3072948650933474476, 1919611921786407622 },
967 .{ 15755650962115585259, 1199757451116504763 }, .{ 15082877684217093670, 1499696813895630954 },
968 .{ 9630225068416591280, 1874621017369538693 }, .{ 8324733676974063502, 1171638135855961683 },
969 .{ 5794231077790191473, 1464547669819952104 }, .{ 7242788847237739342, 1830684587274940130 },
970 .{ 18276858095901949986, 2288355734093675162 }, .{ 16034722328366106645, 1430222333808546976 },
971 .{ 1596658836748081690, 1787777917260683721 }, .{ 6607509564362490017, 2234722396575854651 },
972 .{ 1823850468512862308, 1396701497859909157 }, .{ 6891499104068465790, 1745876872324886446 },
973 .{ 17837745916940358045, 2182346090406108057 }, .{ 4231062170446641922, 1363966306503817536 },
974 .{ 5288827713058302403, 1704957883129771920 }, .{ 6611034641322878003, 2131197353912214900 },
975 .{ 13355268687681574560, 1331998346195134312 }, .{ 16694085859601968200, 1664997932743917890 },
976 .{ 11644235287647684442, 2081247415929897363 }, .{ 4971804045566108824, 1300779634956185852 },
977 .{ 6214755056957636030, 1625974543695232315 }, .{ 3156757802769657134, 2032468179619040394 },
978 .{ 6584659645158423613, 1270292612261900246 }, .{ 17454196593302805324, 1587865765327375307 },
979 .{ 17206059723201118751, 1984832206659219134 }, .{ 6142101308573311315, 1240520129162011959 },
980 .{ 3065940617289251240, 1550650161452514949 }, .{ 8444111790038951954, 1938312701815643686 },
981 .{ 665883850346957067, 1211445438634777304 }, .{ 832354812933696334, 1514306798293471630 },
982 .{ 10263815553021896226, 1892883497866839537 }, .{ 17944099766707154901, 1183052186166774710 },
983 .{ 13206752671529167818, 1478815232708468388 }, .{ 16508440839411459773, 1848519040885585485 },
984 .{ 12623618533845856310, 1155324400553490928 }, .{ 15779523167307320387, 1444155500691863660 },
985 .{ 1277659885424598868, 1805194375864829576 }, .{ 1597074856780748586, 2256492969831036970 },
986 .{ 5609857803915355770, 1410308106144398106 }, .{ 16235694291748970521, 1762885132680497632 },
987 .{ 1847873790976661535, 2203606415850622041 }, .{ 12684136165428883219, 1377254009906638775 },
988 .{ 11243484188358716120, 1721567512383298469 }, .{ 219297180166231438, 2151959390479123087 },
989 .{ 7054589765244976505, 1344974619049451929 }, .{ 13429923224983608535, 1681218273811814911 },
990 .{ 12175718012802122765, 2101522842264768639 }, .{ 14527352785642408584, 1313451776415480399 },
991 .{ 13547504963625622826, 1641814720519350499 }, .{ 12322695186104640628, 2052268400649188124 },
992 .{ 16925056528170176201, 1282667750405742577 }, .{ 7321262604930556539, 1603334688007178222 },
993 .{ 18374950293017971482, 2004168360008972777 }, .{ 4566814905495150320, 1252605225005607986 },
994 .{ 14931890668723713708, 1565756531257009982 }, .{ 9441491299049866327, 1957195664071262478 },
995 .{ 1289246043478778550, 1223247290044539049 }, .{ 6223243572775861092, 1529059112555673811 },
996 .{ 3167368447542438461, 1911323890694592264 }, .{ 1979605279714024038, 1194577431684120165 },
997 .{ 7086192618069917952, 1493221789605150206 }, .{ 18081112809442173248, 1866527237006437757 },
998 .{ 13606538515115052232, 1166579523129023598 }, .{ 7784801107039039482, 1458224403911279498 },
999 .{ 507629346944023544, 1822780504889099373 }, .{ 5246222702107417334, 2278475631111374216 },
1000 .{ 3278889188817135834, 1424047269444608885 }, .{ 8710297504448807696, 1780059086805761106 }
1001};
1002
1003const FLOAT64_POW5_INV_SPLIT: [342][2]u64 = .{
1004 .{ 1, 2305843009213693952 }, .{ 11068046444225730970, 1844674407370955161 },
1005 .{ 5165088340638674453, 1475739525896764129 }, .{ 7821419487252849886, 1180591620717411303 },
1006 .{ 8824922364862649494, 1888946593147858085 }, .{ 7059937891890119595, 1511157274518286468 },
1007 .{ 13026647942995916322, 1208925819614629174 }, .{ 9774590264567735146, 1934281311383406679 },
1008 .{ 11509021026396098440, 1547425049106725343 }, .{ 16585914450600699399, 1237940039285380274 },
1009 .{ 15469416676735388068, 1980704062856608439 }, .{ 16064882156130220778, 1584563250285286751 },
1010 .{ 9162556910162266299, 1267650600228229401 }, .{ 7281393426775805432, 2028240960365167042 },
1011 .{ 16893161185646375315, 1622592768292133633 }, .{ 2446482504291369283, 1298074214633706907 },
1012 .{ 7603720821608101175, 2076918743413931051 }, .{ 2393627842544570617, 1661534994731144841 },
1013 .{ 16672297533003297786, 1329227995784915872 }, .{ 11918280793837635165, 2126764793255865396 },
1014 .{ 5845275820328197809, 1701411834604692317 }, .{ 15744267100488289217, 1361129467683753853 },
1015 .{ 3054734472329800808, 2177807148294006166 }, .{ 17201182836831481939, 1742245718635204932 },
1016 .{ 6382248639981364905, 1393796574908163946 }, .{ 2832900194486363201, 2230074519853062314 },
1017 .{ 5955668970331000884, 1784059615882449851 }, .{ 1075186361522890384, 1427247692705959881 },
1018 .{ 12788344622662355584, 2283596308329535809 }, .{ 13920024512871794791, 1826877046663628647 },
1019 .{ 3757321980813615186, 1461501637330902918 }, .{ 10384555214134712795, 1169201309864722334 },
1020 .{ 5547241898389809503, 1870722095783555735 }, .{ 4437793518711847602, 1496577676626844588 },
1021 .{ 10928932444453298728, 1197262141301475670 }, .{ 17486291911125277965, 1915619426082361072 },
1022 .{ 6610335899416401726, 1532495540865888858 }, .{ 12666966349016942027, 1225996432692711086 },
1023 .{ 12888448528943286597, 1961594292308337738 }, .{ 17689456452638449924, 1569275433846670190 },
1024 .{ 14151565162110759939, 1255420347077336152 }, .{ 7885109000409574610, 2008672555323737844 },
1025 .{ 9997436015069570011, 1606938044258990275 }, .{ 7997948812055656009, 1285550435407192220 },
1026 .{ 12796718099289049614, 2056880696651507552 }, .{ 2858676849947419045, 1645504557321206042 },
1027 .{ 13354987924183666206, 1316403645856964833 }, .{ 17678631863951955605, 2106245833371143733 },
1028 .{ 3074859046935833515, 1684996666696914987 }, .{ 13527933681774397782, 1347997333357531989 },
1029 .{ 10576647446613305481, 2156795733372051183 }, .{ 15840015586774465031, 1725436586697640946 },
1030 .{ 8982663654677661702, 1380349269358112757 }, .{ 18061610662226169046, 2208558830972980411 },
1031 .{ 10759939715039024913, 1766847064778384329 }, .{ 12297300586773130254, 1413477651822707463 },
1032 .{ 15986332124095098083, 2261564242916331941 }, .{ 9099716884534168143, 1809251394333065553 },
1033 .{ 14658471137111155161, 1447401115466452442 }, .{ 4348079280205103483, 1157920892373161954 },
1034 .{ 14335624477811986218, 1852673427797059126 }, .{ 7779150767507678651, 1482138742237647301 },
1035 .{ 2533971799264232598, 1185710993790117841 }, .{ 15122401323048503126, 1897137590064188545 },
1036 .{ 12097921058438802501, 1517710072051350836 }, .{ 5988988032009131678, 1214168057641080669 },
1037 .{ 16961078480698431330, 1942668892225729070 }, .{ 13568862784558745064, 1554135113780583256 },
1038 .{ 7165741412905085728, 1243308091024466605 }, .{ 11465186260648137165, 1989292945639146568 },
1039 .{ 16550846638002330379, 1591434356511317254 }, .{ 16930026125143774626, 1273147485209053803 },
1040 .{ 4951948911778577463, 2037035976334486086 }, .{ 272210314680951647, 1629628781067588869 },
1041 .{ 3907117066486671641, 1303703024854071095 }, .{ 6251387306378674625, 2085924839766513752 },
1042 .{ 16069156289328670670, 1668739871813211001 }, .{ 9165976216721026213, 1334991897450568801 },
1043 .{ 7286864317269821294, 2135987035920910082 }, .{ 16897537898041588005, 1708789628736728065 },
1044 .{ 13518030318433270404, 1367031702989382452 }, .{ 6871453250525591353, 2187250724783011924 },
1045 .{ 9186511415162383406, 1749800579826409539 }, .{ 11038557946871817048, 1399840463861127631 },
1046 .{ 10282995085511086630, 2239744742177804210 }, .{ 8226396068408869304, 1791795793742243368 },
1047 .{ 13959814484210916090, 1433436634993794694 }, .{ 11267656730511734774, 2293498615990071511 },
1048 .{ 5324776569667477496, 1834798892792057209 }, .{ 7949170070475892320, 1467839114233645767 },
1049 .{ 17427382500606444826, 1174271291386916613 }, .{ 5747719112518849781, 1878834066219066582 },
1050 .{ 15666221734240810795, 1503067252975253265 }, .{ 12532977387392648636, 1202453802380202612 },
1051 .{ 5295368560860596524, 1923926083808324180 }, .{ 4236294848688477220, 1539140867046659344 },
1052 .{ 7078384693692692099, 1231312693637327475 }, .{ 11325415509908307358, 1970100309819723960 },
1053 .{ 9060332407926645887, 1576080247855779168 }, .{ 14626963555825137356, 1260864198284623334 },
1054 .{ 12335095245094488799, 2017382717255397335 }, .{ 9868076196075591040, 1613906173804317868 },
1055 .{ 15273158586344293478, 1291124939043454294 }, .{ 13369007293925138595, 2065799902469526871 },
1056 .{ 7005857020398200553, 1652639921975621497 }, .{ 16672732060544291412, 1322111937580497197 },
1057 .{ 11918976037903224966, 2115379100128795516 }, .{ 5845832015580669650, 1692303280103036413 },
1058 .{ 12055363241948356366, 1353842624082429130 }, .{ 841837113407818570, 2166148198531886609 },
1059 .{ 4362818505468165179, 1732918558825509287 }, .{ 14558301248600263113, 1386334847060407429 },
1060 .{ 12225235553534690011, 2218135755296651887 }, .{ 2401490813343931363, 1774508604237321510 },
1061 .{ 1921192650675145090, 1419606883389857208 }, .{ 17831303500047873437, 2271371013423771532 },
1062 .{ 6886345170554478103, 1817096810739017226 }, .{ 1819727321701672159, 1453677448591213781 },
1063 .{ 16213177116328979020, 1162941958872971024 }, .{ 14873036941900635463, 1860707134196753639 },
1064 .{ 15587778368262418694, 1488565707357402911 }, .{ 8780873879868024632, 1190852565885922329 },
1065 .{ 2981351763563108441, 1905364105417475727 }, .{ 13453127855076217722, 1524291284333980581 },
1066 .{ 7073153469319063855, 1219433027467184465 }, .{ 11317045550910502167, 1951092843947495144 },
1067 .{ 12742985255470312057, 1560874275157996115 }, .{ 10194388204376249646, 1248699420126396892 },
1068 .{ 1553625868034358140, 1997919072202235028 }, .{ 8621598323911307159, 1598335257761788022 },
1069 .{ 17965325103354776697, 1278668206209430417 }, .{ 13987124906400001422, 2045869129935088668 },
1070 .{ 121653480894270168, 1636695303948070935 }, .{ 97322784715416134, 1309356243158456748 },
1071 .{ 14913111714512307107, 2094969989053530796 }, .{ 8241140556867935363, 1675975991242824637 },
1072 .{ 17660958889720079260, 1340780792994259709 }, .{ 17189487779326395846, 2145249268790815535 },
1073 .{ 13751590223461116677, 1716199415032652428 }, .{ 18379969808252713988, 1372959532026121942 },
1074 .{ 14650556434236701088, 2196735251241795108 }, .{ 652398703163629901, 1757388200993436087 },
1075 .{ 11589965406756634890, 1405910560794748869 }, .{ 7475898206584884855, 2249456897271598191 },
1076 .{ 2291369750525997561, 1799565517817278553 }, .{ 9211793429904618695, 1439652414253822842 },
1077 .{ 18428218302589300235, 2303443862806116547 }, .{ 7363877012587619542, 1842755090244893238 },
1078 .{ 13269799239553916280, 1474204072195914590 }, .{ 10615839391643133024, 1179363257756731672 },
1079 .{ 2227947767661371545, 1886981212410770676 }, .{ 16539753473096738529, 1509584969928616540 },
1080 .{ 13231802778477390823, 1207667975942893232 }, .{ 6413489186596184024, 1932268761508629172 },
1081 .{ 16198837793502678189, 1545815009206903337 }, .{ 5580372605318321905, 1236652007365522670 },
1082 .{ 8928596168509315048, 1978643211784836272 }, .{ 18210923379033183008, 1582914569427869017 },
1083 .{ 7190041073742725760, 1266331655542295214 }, .{ 436019273762630246, 2026130648867672343 },
1084 .{ 7727513048493924843, 1620904519094137874 }, .{ 9871359253537050198, 1296723615275310299 },
1085 .{ 4726128361433549347, 2074757784440496479 }, .{ 7470251503888749801, 1659806227552397183 },
1086 .{ 13354898832594820487, 1327844982041917746 }, .{ 13989140502667892133, 2124551971267068394 },
1087 .{ 14880661216876224029, 1699641577013654715 }, .{ 11904528973500979224, 1359713261610923772 },
1088 .{ 4289851098633925465, 2175541218577478036 }, .{ 18189276137874781665, 1740432974861982428 },
1089 .{ 3483374466074094362, 1392346379889585943 }, .{ 1884050330976640656, 2227754207823337509 },
1090 .{ 5196589079523222848, 1782203366258670007 }, .{ 15225317707844309248, 1425762693006936005 },
1091 .{ 5913764258841343181, 2281220308811097609 }, .{ 8420360221814984868, 1824976247048878087 },
1092 .{ 17804334621677718864, 1459980997639102469 }, .{ 17932816512084085415, 1167984798111281975 },
1093 .{ 10245762345624985047, 1868775676978051161 }, .{ 4507261061758077715, 1495020541582440929 },
1094 .{ 7295157664148372495, 1196016433265952743 }, .{ 7982903447895485668, 1913626293225524389 },
1095 .{ 10075671573058298858, 1530901034580419511 }, .{ 4371188443704728763, 1224720827664335609 },
1096 .{ 14372599139411386667, 1959553324262936974 }, .{ 15187428126271019657, 1567642659410349579 },
1097 .{ 15839291315758726049, 1254114127528279663 }, .{ 3206773216762499739, 2006582604045247462 },
1098 .{ 13633465017635730761, 1605266083236197969 }, .{ 14596120828850494932, 1284212866588958375 },
1099 .{ 4907049252451240275, 2054740586542333401 }, .{ 236290587219081897, 1643792469233866721 },
1100 .{ 14946427728742906810, 1315033975387093376 }, .{ 16535586736504830250, 2104054360619349402 },
1101 .{ 5849771759720043554, 1683243488495479522 }, .{ 15747863852001765813, 1346594790796383617 },
1102 .{ 10439186904235184007, 2154551665274213788 }, .{ 15730047152871967852, 1723641332219371030 },
1103 .{ 12584037722297574282, 1378913065775496824 }, .{ 9066413911450387881, 2206260905240794919 },
1104 .{ 10942479943902220628, 1765008724192635935 }, .{ 8753983955121776503, 1412006979354108748 },
1105 .{ 10317025513452932081, 2259211166966573997 }, .{ 874922781278525018, 1807368933573259198 },
1106 .{ 8078635854506640661, 1445895146858607358 }, .{ 13841606313089133175, 1156716117486885886 },
1107 .{ 14767872471458792434, 1850745787979017418 }, .{ 746251532941302978, 1480596630383213935 },
1108 .{ 597001226353042382, 1184477304306571148 }, .{ 15712597221132509104, 1895163686890513836 },
1109 .{ 8880728962164096960, 1516130949512411069 }, .{ 10793931984473187891, 1212904759609928855 },
1110 .{ 17270291175157100626, 1940647615375886168 }, .{ 2748186495899949531, 1552518092300708935 },
1111 .{ 2198549196719959625, 1242014473840567148 }, .{ 18275073973719576693, 1987223158144907436 },
1112 .{ 10930710364233751031, 1589778526515925949 }, .{ 12433917106128911148, 1271822821212740759 },
1113 .{ 8826220925580526867, 2034916513940385215 }, .{ 7060976740464421494, 1627933211152308172 },
1114 .{ 16716827836597268165, 1302346568921846537 }, .{ 11989529279587987770, 2083754510274954460 },
1115 .{ 9591623423670390216, 1667003608219963568 }, .{ 15051996368420132820, 1333602886575970854 },
1116 .{ 13015147745246481542, 2133764618521553367 }, .{ 3033420566713364587, 1707011694817242694 },
1117 .{ 6116085268112601993, 1365609355853794155 }, .{ 9785736428980163188, 2184974969366070648 },
1118 .{ 15207286772667951197, 1747979975492856518 }, .{ 1097782973908629988, 1398383980394285215 },
1119 .{ 1756452758253807981, 2237414368630856344 }, .{ 5094511021344956708, 1789931494904685075 },
1120 .{ 4075608817075965366, 1431945195923748060 }, .{ 6520974107321544586, 2291112313477996896 },
1121 .{ 1527430471115325346, 1832889850782397517 }, .{ 12289990821117991246, 1466311880625918013 },
1122 .{ 17210690286378213644, 1173049504500734410 }, .{ 9090360384495590213, 1876879207201175057 },
1123 .{ 18340334751822203140, 1501503365760940045 }, .{ 14672267801457762512, 1201202692608752036 },
1124 .{ 16096930852848599373, 1921924308174003258 }, .{ 1809498238053148529, 1537539446539202607 },
1125 .{ 12515645034668249793, 1230031557231362085 }, .{ 1578287981759648052, 1968050491570179337 },
1126 .{ 12330676829633449412, 1574440393256143469 }, .{ 13553890278448669853, 1259552314604914775 },
1127 .{ 3239480371808320148, 2015283703367863641 }, .{ 17348979556414297411, 1612226962694290912 },
1128 .{ 6500486015647617283, 1289781570155432730 }, .{ 10400777625036187652, 2063650512248692368 },
1129 .{ 15699319729512770768, 1650920409798953894 }, .{ 16248804598352126938, 1320736327839163115 },
1130 .{ 7551343283653851484, 2113178124542660985 }, .{ 6041074626923081187, 1690542499634128788 },
1131 .{ 12211557331022285596, 1352433999707303030 }, .{ 1091747655926105338, 2163894399531684849 },
1132 .{ 4562746939482794594, 1731115519625347879 }, .{ 7339546366328145998, 1384892415700278303 },
1133 .{ 8053925371383123274, 2215827865120445285 }, .{ 6443140297106498619, 1772662292096356228 },
1134 .{ 12533209867169019542, 1418129833677084982 }, .{ 5295740528502789974, 2269007733883335972 },
1135 .{ 15304638867027962949, 1815206187106668777 }, .{ 4865013464138549713, 1452164949685335022 },
1136 .{ 14960057215536570740, 1161731959748268017 }, .{ 9178696285890871890, 1858771135597228828 },
1137 .{ 14721654658196518159, 1487016908477783062 }, .{ 4398626097073393881, 1189613526782226450 },
1138 .{ 7037801755317430209, 1903381642851562320 }, .{ 5630241404253944167, 1522705314281249856 },
1139 .{ 814844308661245011, 1218164251424999885 }, .{ 1303750893857992017, 1949062802279999816 },
1140 .{ 15800395974054034906, 1559250241823999852 }, .{ 5261619149759407279, 1247400193459199882 },
1141 .{ 12107939454356961969, 1995840309534719811 }, .{ 5997002748743659252, 1596672247627775849 },
1142 .{ 8486951013736837725, 1277337798102220679 }, .{ 2511075177753209390, 2043740476963553087 },
1143 .{ 13076906586428298482, 1634992381570842469 }, .{ 14150874083884549109, 1307993905256673975 },
1144 .{ 4194654460505726958, 2092790248410678361 }, .{ 18113118827372222859, 1674232198728542688 },
1145 .{ 3422448617672047318, 1339385758982834151 }, .{ 16543964232501006678, 2143017214372534641 },
1146 .{ 9545822571258895019, 1714413771498027713 }, .{ 15015355686490936662, 1371531017198422170 },
1147 .{ 5577825024675947042, 2194449627517475473 }, .{ 11840957649224578280, 1755559702013980378 },
1148 .{ 16851463748863483271, 1404447761611184302 }, .{ 12204946739213931940, 2247116418577894884 },
1149 .{ 13453306206113055875, 1797693134862315907 }, .{ 3383947335406624054, 1438154507889852726 },
1150 .{ 16482362180876329456, 2301047212623764361 }, .{ 9496540929959153242, 1840837770099011489 },
1151 .{ 11286581558709232917, 1472670216079209191 }, .{ 5339916432225476010, 1178136172863367353 },
1152 .{ 4854517476818851293, 1885017876581387765 }, .{ 3883613981455081034, 1508014301265110212 },
1153 .{ 14174937629389795797, 1206411441012088169 }, .{ 11611853762797942306, 1930258305619341071 },
1154 .{ 5600134195496443521, 1544206644495472857 }, .{ 15548153800622885787, 1235365315596378285 },
1155 .{ 6430302007287065643, 1976584504954205257 }, .{ 16212288050055383484, 1581267603963364205 },
1156 .{ 12969830440044306787, 1265014083170691364 }, .{ 9683682259845159889, 2024022533073106183 },
1157 .{ 15125643437359948558, 1619218026458484946 }, .{ 8411165935146048523, 1295374421166787957 },
1158 .{ 17147214310975587960, 2072599073866860731 }, .{ 10028422634038560045, 1658079259093488585 },
1159 .{ 8022738107230848036, 1326463407274790868 }, .{ 9147032156827446534, 2122341451639665389 },
1160 .{ 11006974540203867551, 1697873161311732311 }, .{ 5116230817421183718, 1358298529049385849 },
1161 .{ 15564666937357714594, 2173277646479017358 }, .{ 1383687105660440706, 1738622117183213887 },
1162 .{ 12174996128754083534, 1390897693746571109 }, .{ 8411947361780802685, 2225436309994513775 },
1163 .{ 6729557889424642148, 1780349047995611020 }, .{ 5383646311539713719, 1424279238396488816 },
1164 .{ 1235136468979721303, 2278846781434382106 }, .{ 15745504434151418335, 1823077425147505684 },
1165 .{ 16285752362063044992, 1458461940118004547 }, .{ 5649904260166615347, 1166769552094403638 },
1166 .{ 5350498001524674232, 1866831283351045821 }, .{ 591049586477829062, 1493465026680836657 },
1167 .{ 11540886113407994219, 1194772021344669325 }, .{ 18673707743239135, 1911635234151470921 },
1168 .{ 14772334225162232601, 1529308187321176736 }, .{ 8128518565387875758, 1223446549856941389 },
1169 .{ 1937583260394870242, 1957514479771106223 }, .{ 8928764237799716840, 1566011583816884978 },
1170 .{ 14521709019723594119, 1252809267053507982 }, .{ 8477339172590109297, 2004494827285612772 },
1171 .{ 17849917782297818407, 1603595861828490217 }, .{ 6901236596354434079, 1282876689462792174 },
1172 .{ 18420676183650915173, 2052602703140467478 }, .{ 3668494502695001169, 1642082162512373983 },
1173 .{ 10313493231639821582, 1313665730009899186 }, .{ 9122891541139893884, 2101865168015838698 },
1174 .{ 14677010862395735754, 1681492134412670958 }, .{ 673562245690857633, 1345193707530136767 }
1175};
1176
1177// zig fmt: off
1178//
1179// f128 small tables: 9072 bytes
1180
1181const FLOAT128_POW5_INV_BITCOUNT = 249;
1182const FLOAT128_POW5_BITCOUNT = 249;
1183const FLOAT128_POW5_TABLE_SIZE: comptime_int = FLOAT128_POW5_TABLE.len;
1184
1185const FLOAT128_POW5_TABLE: [56][2]u64 = .{
1186 .{ 1, 0 },
1187 .{ 5, 0 },
1188 .{ 25, 0 },
1189 .{ 125, 0 },
1190 .{ 625, 0 },
1191 .{ 3125, 0 },
1192 .{ 15625, 0 },
1193 .{ 78125, 0 },
1194 .{ 390625, 0 },
1195 .{ 1953125, 0 },
1196 .{ 9765625, 0 },
1197 .{ 48828125, 0 },
1198 .{ 244140625, 0 },
1199 .{ 1220703125, 0 },
1200 .{ 6103515625, 0 },
1201 .{ 30517578125, 0 },
1202 .{ 152587890625, 0 },
1203 .{ 762939453125, 0 },
1204 .{ 3814697265625, 0 },
1205 .{ 19073486328125, 0 },
1206 .{ 95367431640625, 0 },
1207 .{ 476837158203125, 0 },
1208 .{ 2384185791015625, 0 },
1209 .{ 11920928955078125, 0 },
1210 .{ 59604644775390625, 0 },
1211 .{ 298023223876953125, 0 },
1212 .{ 1490116119384765625, 0 },
1213 .{ 7450580596923828125, 0 },
1214 .{ 359414837200037393, 2 },
1215 .{ 1797074186000186965, 10 },
1216 .{ 8985370930000934825, 50 },
1217 .{ 8033366502585570893, 252 },
1218 .{ 3273344365508751233, 1262 },
1219 .{ 16366721827543756165, 6310 },
1220 .{ 8046632842880574361, 31554 },
1221 .{ 3339676066983768573, 157772 },
1222 .{ 16698380334918842865, 788860 },
1223 .{ 9704925379756007861, 3944304 },
1224 .{ 11631138751360936073, 19721522 },
1225 .{ 2815461535676025517, 98607613 },
1226 .{ 14077307678380127585, 493038065 },
1227 .{ 15046306170771983077, 2465190328 },
1228 .{ 1444554559021708921, 12325951644 },
1229 .{ 7222772795108544605, 61629758220 },
1230 .{ 17667119901833171409, 308148791101 },
1231 .{ 14548623214327650581, 1540743955509 },
1232 .{ 17402883850509598057, 7703719777548 },
1233 .{ 13227442957709783821, 38518598887744 },
1234 .{ 10796982567420264257, 192592994438723 },
1235 .{ 17091424689682218053, 962964972193617 },
1236 .{ 11670147153572883801, 4814824860968089 },
1237 .{ 3010503546735764157, 24074124304840448 },
1238 .{ 15052517733678820785, 120370621524202240 },
1239 .{ 1475612373555897461, 601853107621011204 },
1240 .{ 7378061867779487305, 3009265538105056020 },
1241 .{ 18443565265187884909, 15046327690525280101 },
1242};
1243
1244const FLOAT128_POW5_SPLIT: [89][4]u64 = .{
1245 .{ 0, 0, 0, 72057594037927936 },
1246 .{ 0, 5206161169240293376, 4575641699882439235, 73468396926392969 },
1247 .{ 3360510775605221349, 6983200512169538081, 4325643253124434363, 74906821675075173 },
1248 .{ 11917660854915489451, 9652941469841108803, 946308467778435600, 76373409087490117 },
1249 .{ 1994853395185689235, 16102657350889591545, 6847013871814915412, 77868710555449746 },
1250 .{ 958415760277438274, 15059347134713823592, 7329070255463483331, 79393288266368765 },
1251 .{ 2065144883315240188, 7145278325844925976, 14718454754511147343, 80947715414629833 },
1252 .{ 8980391188862868935, 13709057401304208685, 8230434828742694591, 82532576417087045 },
1253 .{ 432148644612782575, 7960151582448466064, 12056089168559840552, 84148467132788711 },
1254 .{ 484109300864744403, 15010663910730448582, 16824949663447227068, 85795995087002057 },
1255 .{ 14793711725276144220, 16494403799991899904, 10145107106505865967, 87475779699624060 },
1256 .{ 15427548291869817042, 12330588654550505203, 13980791795114552342, 89188452518064298 },
1257 .{ 9979404135116626552, 13477446383271537499, 14459862802511591337, 90934657454687378 },
1258 .{ 12385121150303452775, 9097130814231585614, 6523855782339765207, 92715051028904201 },
1259 .{ 1822931022538209743, 16062974719797586441, 3619180286173516788, 94530302614003091 },
1260 .{ 12318611738248470829, 13330752208259324507, 10986694768744162601, 96381094688813589 },
1261 .{ 13684493829640282333, 7674802078297225834, 15208116197624593182, 98268123094297527 },
1262 .{ 5408877057066295332, 6470124174091971006, 15112713923117703147, 100192097295163851 },
1263 .{ 11407083166564425062, 18189998238742408185, 4337638702446708282, 102153740646605557 },
1264 .{ 4112405898036935485, 924624216579956435, 14251108172073737125, 104153790666259019 },
1265 .{ 16996739107011444789, 10015944118339042475, 2395188869672266257, 106192999311487969 },
1266 .{ 4588314690421337879, 5339991768263654604, 15441007590670620066, 108272133262096356 },
1267 .{ 2286159977890359825, 14329706763185060248, 5980012964059367667, 110391974208576409 },
1268 .{ 9654767503237031099, 11293544302844823188, 11739932712678287805, 112553319146000238 },
1269 .{ 11362964448496095896, 7990659682315657680, 251480263940996374, 114756980673665505 },
1270 .{ 1423410421096377129, 14274395557581462179, 16553482793602208894, 117003787300607788 },
1271 .{ 2070444190619093137, 11517140404712147401, 11657844572835578076, 119294583757094535 },
1272 .{ 7648316884775828921, 15264332483297977688, 247182277434709002, 121630231312217685 },
1273 .{ 17410896758132241352, 10923914482914417070, 13976383996795783649, 124011608097704390 },
1274 .{ 9542674537907272703, 3079432708831728956, 14235189590642919676, 126439609438067572 },
1275 .{ 10364666969937261816, 8464573184892924210, 12758646866025101190, 128915148187220428 },
1276 .{ 14720354822146013883, 11480204489231511423, 7449876034836187038, 131439155071681461 },
1277 .{ 1692907053653558553, 17835392458598425233, 1754856712536736598, 134012579040499057 },
1278 .{ 5620591334531458755, 11361776175667106627, 13350215315297937856, 136636387622027174 },
1279 .{ 17455759733928092601, 10362573084069962561, 11246018728801810510, 139311567287686283 },
1280 .{ 2465404073814044982, 17694822665274381860, 1509954037718722697, 142039123822846312 },
1281 .{ 2152236053329638369, 11202280800589637091, 16388426812920420176, 72410041352485523 },
1282 .{ 17319024055671609028, 10944982848661280484, 2457150158022562661, 73827744744583080 },
1283 .{ 17511219308535248024, 5122059497846768077, 2089605804219668451, 75273205100637900 },
1284 .{ 10082673333144031533, 14429008783411894887, 12842832230171903890, 76746965869337783 },
1285 .{ 16196653406315961184, 10260180891682904501, 10537411930446752461, 78249581139456266 },
1286 .{ 15084422041749743389, 234835370106753111, 16662517110286225617, 79781615848172976 },
1287 .{ 8199644021067702606, 3787318116274991885, 7438130039325743106, 81343645993472659 },
1288 .{ 12039493937039359765, 9773822153580393709, 5945428874398357806, 82936258850702722 },
1289 .{ 984543865091303961, 7975107621689454830, 6556665988501773347, 84560053193370726 },
1290 .{ 9633317878125234244, 16099592426808915028, 9706674539190598200, 86215639518264828 },
1291 .{ 6860695058870476186, 4471839111886709592, 7828342285492709568, 87903640274981819 },
1292 .{ 14583324717644598331, 4496120889473451238, 5290040788305728466, 89624690099949049 },
1293 .{ 18093669366515003715, 12879506572606942994, 18005739787089675377, 91379436055028227 },
1294 .{ 17997493966862379937, 14646222655265145582, 10265023312844161858, 93168537870790806 },
1295 .{ 12283848109039722318, 11290258077250314935, 9878160025624946825, 94992668194556404 },
1296 .{ 8087752761883078164, 5262596608437575693, 11093553063763274413, 96852512843287537 },
1297 .{ 15027787746776840781, 12250273651168257752, 9290470558712181914, 98748771061435726 },
1298 .{ 15003915578366724489, 2937334162439764327, 5404085603526796602, 100682155783835929 },
1299 .{ 5225610465224746757, 14932114897406142027, 2774647558180708010, 102653393903748137 },
1300 .{ 17112957703385190360, 12069082008339002412, 3901112447086388439, 104663226546146909 },
1301 .{ 4062324464323300238, 3992768146772240329, 15757196565593695724, 106712409346361594 },
1302 .{ 5525364615810306701, 11855206026704935156, 11344868740897365300, 108801712734172003 },
1303 .{ 9274143661888462646, 4478365862348432381, 18010077872551661771, 110931922223466333 },
1304 .{ 12604141221930060148, 8930937759942591500, 9382183116147201338, 113103838707570263 },
1305 .{ 14513929377491886653, 1410646149696279084, 587092196850797612, 115318278760358235 },
1306 .{ 2226851524999454362, 7717102471110805679, 7187441550995571734, 117576074943260147 },
1307 .{ 5527526061344932763, 2347100676188369132, 16976241418824030445, 119878076118278875 },
1308 .{ 6088479778147221611, 17669593130014777580, 10991124207197663546, 122225147767136307 },
1309 .{ 11107734086759692041, 3391795220306863431, 17233960908859089158, 124618172316667879 },
1310 .{ 7913172514655155198, 17726879005381242552, 641069866244011540, 127058049470587962 },
1311 .{ 12596991768458713949, 15714785522479904446, 6035972567136116512, 129545696547750811 },
1312 .{ 16901996933781815980, 4275085211437148707, 14091642539965169063, 132082048827034281 },
1313 .{ 7524574627987869240, 15661204384239316051, 2444526454225712267, 134668059898975949 },
1314 .{ 8199251625090479942, 6803282222165044067, 16064817666437851504, 137304702024293857 },
1315 .{ 4453256673338111920, 15269922543084434181, 3139961729834750852, 139992966499426682 },
1316 .{ 15841763546372731299, 3013174075437671812, 4383755396295695606, 142733864029230733 },
1317 .{ 9771896230907310329, 4900659362437687569, 12386126719044266361, 72764212553486967 },
1318 .{ 9420455527449565190, 1859606122611023693, 6555040298902684281, 74188850200884818 },
1319 .{ 5146105983135678095, 2287300449992174951, 4325371679080264751, 75641380576797959 },
1320 .{ 11019359372592553360, 8422686425957443718, 7175176077944048210, 77122349788024458 },
1321 .{ 11005742969399620716, 4132174559240043701, 9372258443096612118, 78632314633490790 },
1322 .{ 8887589641394725840, 8029899502466543662, 14582206497241572853, 80171842813591127 },
1323 .{ 360247523705545899, 12568341805293354211, 14653258284762517866, 81741513143625247 },
1324 .{ 12314272731984275834, 4740745023227177044, 6141631472368337539, 83341915771415304 },
1325 .{ 441052047733984759, 7940090120939869826, 11750200619921094248, 84973652399183278 },
1326 .{ 3436657868127012749, 9187006432149937667, 16389726097323041290, 86637336509772529 },
1327 .{ 13490220260784534044, 15339072891382896702, 8846102360835316895, 88333593597298497 },
1328 .{ 4125672032094859833, 158347675704003277, 10592598512749774447, 90063061402315272 },
1329 .{ 12189928252974395775, 2386931199439295891, 7009030566469913276, 91826390151586454 },
1330 .{ 9256479608339282969, 2844900158963599229, 11148388908923225596, 93624242802550437 },
1331 .{ 11584393507658707408, 2863659090805147914, 9873421561981063551, 95457295292572042 },
1332 .{ 13984297296943171390, 1931468383973130608, 12905719743235082319, 97326236793074198 },
1333 .{ 5837045222254987499, 10213498696735864176, 14893951506257020749, 99231769968645227 },
1334};
1335
1336// Unfortunately, the results are sometimes off by one or two. We use an additional
1337// lookup table to store those cases and adjust the result.
1338const FLOAT128_POW5_ERRORS: [156]u64 = .{
1339 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x9555596400000000,
1340 0x65a6569525565555, 0x4415551445449655, 0x5105015504144541, 0x65a69969a6965964,
1341 0x5054955969959656, 0x5105154515554145, 0x4055511051591555, 0x5500514455550115,
1342 0x0041140014145515, 0x1005440545511051, 0x0014405450411004, 0x0414440010500000,
1343 0x0044000440010040, 0x5551155000004001, 0x4554555454544114, 0x5150045544005441,
1344 0x0001111400054501, 0x6550955555554554, 0x1504159645559559, 0x4105055141454545,
1345 0x1411541410405454, 0x0415555044545555, 0x0014154115405550, 0x1540055040411445,
1346 0x0000000500000000, 0x5644000000000000, 0x1155555591596555, 0x0410440054569565,
1347 0x5145100010010005, 0x0555041405500150, 0x4141450455140450, 0x0000000144000140,
1348 0x5114004001105410, 0x4444100404005504, 0x0414014410001015, 0x5145055155555015,
1349 0x0141041444445540, 0x0000100451541414, 0x4105041104155550, 0x0500501150451145,
1350 0x1001050000004114, 0x5551504400141045, 0x5110545410151454, 0x0100001400004040,
1351 0x5040010111040000, 0x0140000150541100, 0x4400140400104110, 0x5011014405545004,
1352 0x0000000044155440, 0x0000000010000000, 0x1100401444440001, 0x0040401010055111,
1353 0x5155155551405454, 0x0444440015514411, 0x0054505054014101, 0x0451015441115511,
1354 0x1541411401140551, 0x4155104514445110, 0x4141145450145515, 0x5451445055155050,
1355 0x4400515554110054, 0x5111145104501151, 0x565a655455500501, 0x5565555555525955,
1356 0x0550511500405695, 0x4415504051054544, 0x6555595965555554, 0x0100915915555655,
1357 0x5540001510001001, 0x5450051414000544, 0x1405010555555551, 0x5555515555644155,
1358 0x5555055595496555, 0x5451045004415000, 0x5450510144040144, 0x5554155555556455,
1359 0x5051555495415555, 0x5555554555555545, 0x0000000010005455, 0x4000005000040000,
1360 0x5565555555555954, 0x5554559555555505, 0x9645545495552555, 0x4000400055955564,
1361 0x0040000000000001, 0x4004100100000000, 0x5540040440000411, 0x4565555955545644,
1362 0x1140659549651556, 0x0100000410010000, 0x5555515400004001, 0x5955545555155255,
1363 0x5151055545505556, 0x5051454510554515, 0x0501500050415554, 0x5044154005441005,
1364 0x1455445450550455, 0x0010144055144545, 0x0000401100000004, 0x1050145050000010,
1365 0x0415004554011540, 0x1000510100151150, 0x0100040400001144, 0x0000000000000000,
1366 0x0550004400000100, 0x0151145041451151, 0x0000400400005450, 0x0000100044010004,
1367 0x0100054100050040, 0x0504400005410010, 0x4011410445500105, 0x0000404000144411,
1368 0x0101504404500000, 0x0000005044400400, 0x0000000014000100, 0x0404440414000000,
1369 0x5554100410000140, 0x4555455544505555, 0x5454105055455455, 0x0115454155454015,
1370 0x4404110000045100, 0x4400001100101501, 0x6596955956966a94, 0x0040655955665965,
1371 0x5554144400100155, 0xa549495401011041, 0x5596555565955555, 0x5569965959549555,
1372 0x969565a655555456, 0x0000001000000000, 0x0000000040000140, 0x0000040100000000,
1373 0x1415454400000000, 0x5410415411454114, 0x0400040104000154, 0x0504045000000411,
1374 0x0000001000000010, 0x5554000000001040, 0x5549155551556595, 0x1455541055515555,
1375 0x0510555454554541, 0x9555555555540455, 0x6455456555556465, 0x4524565555654514,
1376 0x5554655255559545, 0x9555455441155556, 0x0000000051515555, 0x0010005040000550,
1377 0x5044044040000000, 0x1045040440010500, 0x0000400000040000, 0x0000000000000000,
1378};
1379
1380const FLOAT128_POW5_INV_SPLIT: [89][4]u64 = .{
1381 .{ 0, 0, 0, 144115188075855872 },
1382 .{ 1573859546583440065, 2691002611772552616, 6763753280790178510, 141347765182270746 },
1383 .{ 12960290449513840412, 12345512957918226762, 18057899791198622765, 138633484706040742 },
1384 .{ 7615871757716765416, 9507132263365501332, 4879801712092008245, 135971326161092377 },
1385 .{ 7869961150745287587, 5804035291554591636, 8883897266325833928, 133360288657597085 },
1386 .{ 2942118023529634767, 15128191429820565086, 10638459445243230718, 130799390525667397 },
1387 .{ 14188759758411913794, 5362791266439207815, 8068821289119264054, 128287668946279217 },
1388 .{ 7183196927902545212, 1952291723540117099, 12075928209936341512, 125824179589281448 },
1389 .{ 5672588001402349748, 17892323620748423487, 9874578446960390364, 123407996258356868 },
1390 .{ 4442590541217566325, 4558254706293456445, 10343828952663182727, 121038210542800766 },
1391 .{ 3005560928406962566, 2082271027139057888, 13961184524927245081, 118713931475986426 },
1392 .{ 13299058168408384786, 17834349496131278595, 9029906103900731664, 116434285200389047 },
1393 .{ 5414878118283973035, 13079825470227392078, 17897304791683760280, 114198414639042157 },
1394 .{ 14609755883382484834, 14991702445765844156, 3269802549772755411, 112005479173303009 },
1395 .{ 15967774957605076027, 2511532636717499923, 16221038267832563171, 109854654326805788 },
1396 .{ 9269330061621627145, 3332501053426257392, 16223281189403734630, 107745131455483836 },
1397 .{ 16739559299223642282, 1873986623300664530, 6546709159471442872, 105676117443544318 },
1398 .{ 17116435360051202055, 1359075105581853924, 2038341371621886470, 103646834405281051 },
1399 .{ 17144715798009627550, 3201623802661132408, 9757551605154622431, 101656519392613377 },
1400 .{ 17580479792687825857, 6546633380567327312, 15099972427870912398, 99704424108241124 },
1401 .{ 9726477118325522902, 14578369026754005435, 11728055595254428803, 97789814624307808 },
1402 .{ 134593949518343635, 5715151379816901985, 1660163707976377376, 95911971106466306 },
1403 .{ 5515914027713859358, 7124354893273815720, 5548463282858794077, 94070187543243255 },
1404 .{ 6188403395862945512, 5681264392632320838, 15417410852121406654, 92263771480600430 },
1405 .{ 15908890877468271457, 10398888261125597540, 4817794962769172309, 90492043761593298 },
1406 .{ 1413077535082201005, 12675058125384151580, 7731426132303759597, 88754338271028867 },
1407 .{ 1486733163972670293, 11369385300195092554, 11610016711694864110, 87050001685026843 },
1408 .{ 8788596583757589684, 3978580923851924802, 9255162428306775812, 85378393225389919 },
1409 .{ 7203518319660962120, 15044736224407683725, 2488132019818199792, 83738884418690858 },
1410 .{ 4004175967662388707, 18236988667757575407, 15613100370957482671, 82130858859985791 },
1411 .{ 18371903370586036463, 53497579022921640, 16465963977267203307, 80553711981064899 },
1412 .{ 10170778323887491315, 1999668801648976001, 10209763593579456445, 79006850823153334 },
1413 .{ 17108131712433974546, 16825784443029944237, 2078700786753338945, 77489693813976938 },
1414 .{ 17221789422665858532, 12145427517550446164, 5391414622238668005, 76001670549108934 },
1415 .{ 4859588996898795878, 1715798948121313204, 3950858167455137171, 74542221577515387 },
1416 .{ 13513469241795711526, 631367850494860526, 10517278915021816160, 73110798191218799 },
1417 .{ 11757513142672073111, 2581974932255022228, 17498959383193606459, 143413724438001539 },
1418 .{ 14524355192525042817, 5640643347559376447, 1309659274756813016, 140659771648132296 },
1419 .{ 2765095348461978538, 11021111021896007722, 3224303603779962366, 137958702611185230 },
1420 .{ 12373410389187981037, 13679193545685856195, 11644609038462631561, 135309501808182158 },
1421 .{ 12813176257562780151, 3754199046160268020, 9954691079802960722, 132711173221007413 },
1422 .{ 17557452279667723458, 3237799193992485824, 17893947919029030695, 130162739957935629 },
1423 .{ 14634200999559435155, 4123869946105211004, 6955301747350769239, 127663243886350468 },
1424 .{ 2185352760627740240, 2864813346878886844, 13049218671329690184, 125211745272516185 },
1425 .{ 6143438674322183002, 10464733336980678750, 6982925169933978309, 122807322428266620 },
1426 .{ 1099509117817174576, 10202656147550524081, 754997032816608484, 120449071364478757 },
1427 .{ 2410631293559367023, 17407273750261453804, 15307291918933463037, 118136105451200587 },
1428 .{ 12224968375134586697, 1664436604907828062, 11506086230137787358, 115867555084305488 },
1429 .{ 3495926216898000888, 18392536965197424288, 10992889188570643156, 113642567358547782 },
1430 .{ 8744506286256259680, 3966568369496879937, 18342264969761820037, 111460305746896569 },
1431 .{ 7689600520560455039, 5254331190877624630, 9628558080573245556, 109319949786027263 },
1432 .{ 11862637625618819436, 3456120362318976488, 14690471063106001082, 107220694767852583 },
1433 .{ 5697330450030126444, 12424082405392918899, 358204170751754904, 105161751436977040 },
1434 .{ 11257457505097373622, 15373192700214208870, 671619062372033814, 103142345693961148 },
1435 .{ 16850355018477166700, 1913910419361963966, 4550257919755970531, 101161718304283822 },
1436 .{ 9670835567561997011, 10584031339132130638, 3060560222974851757, 99219124612893520 },
1437 .{ 7698686577353054710, 11689292838639130817, 11806331021588878241, 97313834264240819 },
1438 .{ 12233569599615692137, 3347791226108469959, 10333904326094451110, 95445130927687169 },
1439 .{ 13049400362825383933, 17142621313007799680, 3790542585289224168, 93612312028186576 },
1440 .{ 12430457242474442072, 5625077542189557960, 14765055286236672238, 91814688482138969 },
1441 .{ 4759444137752473128, 2230562561567025078, 4954443037339580076, 90051584438315940 },
1442 .{ 7246913525170274758, 8910297835195760709, 4015904029508858381, 88322337023761438 },
1443 .{ 12854430245836432067, 8135139748065431455, 11548083631386317976, 86626296094571907 },
1444 .{ 4848827254502687803, 4789491250196085625, 3988192420450664125, 84962823991462151 },
1445 .{ 7435538409611286684, 904061756819742353, 14598026519493048444, 83331295300025028 },
1446 .{ 11042616160352530997, 8948390828345326218, 10052651191118271927, 81731096615594853 },
1447 .{ 11059348291563778943, 11696515766184685544, 3783210511290897367, 80161626312626082 },
1448 .{ 7020010856491885826, 5025093219346041680, 8960210401638911765, 78622294318500592 },
1449 .{ 17732844474490699984, 7820866704994446502, 6088373186798844243, 77112521891678506 },
1450 .{ 688278527545590501, 3045610706602776618, 8684243536999567610, 75631741404109150 },
1451 .{ 2734573255120657297, 3903146411440697663, 9470794821691856713, 74179396127820347 },
1452 .{ 15996457521023071259, 4776627823451271680, 12394856457265744744, 72754940025605801 },
1453 .{ 13492065758834518331, 7390517611012222399, 1630485387832860230, 142715675091463768 },
1454 .{ 13665021627282055864, 9897834675523659302, 17907668136755296849, 139975126841173266 },
1455 .{ 9603773719399446181, 10771916301484339398, 10672699855989487527, 137287204938390542 },
1456 .{ 3630218541553511265, 8139010004241080614, 2876479648932814543, 134650898807055963 },
1457 .{ 8318835909686377084, 9525369258927993371, 2796120270400437057, 132065217277054270 },
1458 .{ 11190003059043290163, 12424345635599592110, 12539346395388933763, 129529188211565064 },
1459 .{ 8701968833973242276, 820569587086330727, 2315591597351480110, 127041858141569228 },
1460 .{ 5115113890115690487, 16906305245394587826, 9899749468931071388, 124602291907373862 },
1461 .{ 15543535488939245974, 10945189844466391399, 3553863472349432246, 122209572307020975 },
1462 .{ 7709257252608325038, 1191832167690640880, 15077137020234258537, 119862799751447719 },
1463 .{ 7541333244210021737, 9790054727902174575, 5160944773155322014, 117561091926268545 },
1464 .{ 12297384708782857832, 1281328873123467374, 4827925254630475769, 115303583460052092 },
1465 .{ 13243237906232367265, 15873887428139547641, 3607993172301799599, 113089425598968120 },
1466 .{ 11384616453739611114, 15184114243769211033, 13148448124803481057, 110917785887682141 },
1467 .{ 17727970963596660683, 1196965221832671990, 14537830463956404138, 108787847856377790 },
1468 .{ 17241367586707330931, 8880584684128262874, 11173506540726547818, 106698810713789254 },
1469 .{ 7184427196661305643, 14332510582433188173, 14230167953789677901, 104649889046128358 },
1470};
1471
1472const FLOAT128_POW5_INV_ERRORS: [154]u64 = .{
1473 0x1144155514145504, 0x0000541555401141, 0x0000000000000000, 0x0154454000000000,
1474 0x4114105515544440, 0x0001001111500415, 0x4041411410011000, 0x5550114515155014,
1475 0x1404100041554551, 0x0515000450404410, 0x5054544401140004, 0x5155501005555105,
1476 0x1144141000105515, 0x0541500000500000, 0x1104105540444140, 0x4000015055514110,
1477 0x0054010450004005, 0x4155515404100005, 0x5155145045155555, 0x1511555515440558,
1478 0x5558544555515555, 0x0000000000000010, 0x5004000000000050, 0x1415510100000010,
1479 0x4545555444514500, 0x5155151555555551, 0x1441540144044554, 0x5150104045544400,
1480 0x5450545401444040, 0x5554455045501400, 0x4655155555555145, 0x1000010055455055,
1481 0x1000004000055004, 0x4455405104000005, 0x4500114504150545, 0x0000000014000000,
1482 0x5450000000000000, 0x5514551511445555, 0x4111501040555451, 0x4515445500054444,
1483 0x5101500104100441, 0x1545115155545055, 0x0000000000000000, 0x1554000000100000,
1484 0x5555545595551555, 0x5555051851455955, 0x5555555555555559, 0x0000400011001555,
1485 0x0000004400040000, 0x5455511555554554, 0x5614555544115445, 0x6455156145555155,
1486 0x5455855455415455, 0x5515555144555545, 0x0114400000145155, 0x0000051000450511,
1487 0x4455154554445100, 0x4554150141544455, 0x65955555559a5965, 0x5555555854559559,
1488 0x9569654559616595, 0x1040044040005565, 0x1010010500011044, 0x1554015545154540,
1489 0x4440555401545441, 0x1014441450550105, 0x4545400410504145, 0x5015111541040151,
1490 0x5145051154000410, 0x1040001044545044, 0x4001400000151410, 0x0540000044040000,
1491 0x0510555454411544, 0x0400054054141550, 0x1001041145001100, 0x0000000140000000,
1492 0x0000000014100000, 0x1544005454000140, 0x4050055505445145, 0x0011511104504155,
1493 0x5505544415045055, 0x1155154445515554, 0x0000000000004555, 0x0000000000000000,
1494 0x5101010510400004, 0x1514045044440400, 0x5515519555515555, 0x4554545441555545,
1495 0x1551055955551515, 0x0150000011505515, 0x0044005040400000, 0x0004001004010050,
1496 0x0000051004450414, 0x0114001101001144, 0x0401000001000001, 0x4500010001000401,
1497 0x0004100000005000, 0x0105000441101100, 0x0455455550454540, 0x5404050144105505,
1498 0x4101510540555455, 0x1055541411451555, 0x5451445110115505, 0x1154110010101545,
1499 0x1145140450054055, 0x5555565415551554, 0x1550559555555555, 0x5555541545045141,
1500 0x4555455450500100, 0x5510454545554555, 0x1510140115045455, 0x1001050040111510,
1501 0x5555454555555504, 0x9954155545515554, 0x6596656555555555, 0x0140410051555559,
1502 0x0011104010001544, 0x965669659a680501, 0x5655a55955556955, 0x4015111014404514,
1503 0x1414155554505145, 0x0540040011051404, 0x1010000000015005, 0x0010054050004410,
1504 0x5041104014000100, 0x4440010500100001, 0x1155510504545554, 0x0450151545115541,
1505 0x4000100400110440, 0x1004440010514440, 0x0000115050450000, 0x0545404455541500,
1506 0x1051051555505101, 0x5505144554544144, 0x4550545555515550, 0x0015400450045445,
1507 0x4514155400554415, 0x4555055051050151, 0x1511441450001014, 0x4544554510404414,
1508 0x4115115545545450, 0x5500541555551555, 0x5550010544155015, 0x0144414045545500,
1509 0x4154050001050150, 0x5550511111000145, 0x1114504055000151, 0x5104041101451040,
1510 0x0010501401051441, 0x0010501450504401, 0x4554585440044444, 0x5155555951450455,
1511 0x0040000400105555, 0x0000000000000001,
1512};
1513
1514// zig fmt: on
1515
1516const builtin = @import("builtin");
1517
1518fn check(comptime T: type, value: T, comptime expected: []const u8) !void {
1519 const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
1520
1521 var buf: [6000]u8 = undefined;
1522 const value_bits: I = @bitCast(value);
1523 const s = try render(&buf, value, .{});
1524 try std.testing.expectEqualStrings(expected, s);
1525
1526 if (T == f80 and builtin.target.os.tag == .windows and builtin.target.cpu.arch == .x86_64) return;
1527
1528 const o = try std.fmt.parseFloat(T, s);
1529 const o_bits: I = @bitCast(o);
1530
1531 if (std.math.isNan(value)) {
1532 try std.testing.expect(std.math.isNan(o));
1533 } else {
1534 try std.testing.expectEqual(value_bits, o_bits);
1535 }
1536}
1537
1538test "format f32" {
1539 try check(f32, 0.0, "0e0");
1540 try check(f32, -0.0, "-0e0");
1541 try check(f32, 1.0, "1e0");
1542 try check(f32, -1.0, "-1e0");
1543 try check(f32, std.math.nan(f32), "nan");
1544 try check(f32, std.math.inf(f32), "inf");
1545 try check(f32, -std.math.inf(f32), "-inf");
1546 try check(f32, 1.1754944e-38, "1.1754944e-38");
1547 try check(f32, @bitCast(@as(u32, 0x7f7fffff)), "3.4028235e38");
1548 try check(f32, @bitCast(@as(u32, 1)), "1e-45");
1549 try check(f32, 3.355445E7, "3.355445e7");
1550 try check(f32, 8.999999e9, "9e9");
1551 try check(f32, 3.4366717e10, "3.436672e10");
1552 try check(f32, 3.0540412e5, "3.0540412e5");
1553 try check(f32, 8.0990312e3, "8.0990312e3");
1554 try check(f32, 2.4414062e-4, "2.4414062e-4");
1555 try check(f32, 2.4414062e-3, "2.4414062e-3");
1556 try check(f32, 4.3945312e-3, "4.3945312e-3");
1557 try check(f32, 6.3476562e-3, "6.3476562e-3");
1558 try check(f32, 4.7223665e21, "4.7223665e21");
1559 try check(f32, 8388608.0, "8.388608e6");
1560 try check(f32, 1.6777216e7, "1.6777216e7");
1561 try check(f32, 3.3554436e7, "3.3554436e7");
1562 try check(f32, 6.7131496e7, "6.7131496e7");
1563 try check(f32, 1.9310392e-38, "1.9310392e-38");
1564 try check(f32, -2.47e-43, "-2.47e-43");
1565 try check(f32, 1.993244e-38, "1.993244e-38");
1566 try check(f32, 4103.9003, "4.1039004e3");
1567 try check(f32, 5.3399997e9, "5.3399997e9");
1568 try check(f32, 6.0898e-39, "6.0898e-39");
1569 try check(f32, 0.0010310042, "1.0310042e-3");
1570 try check(f32, 2.8823261e17, "2.882326e17");
1571 try check(f32, 7.038531e-26, "7.038531e-26");
1572 try check(f32, 9.2234038e17, "9.223404e17");
1573 try check(f32, 6.7108872e7, "6.710887e7");
1574 try check(f32, 1.0e-44, "1e-44");
1575 try check(f32, 2.816025e14, "2.816025e14");
1576 try check(f32, 9.223372e18, "9.223372e18");
1577 try check(f32, 1.5846085e29, "1.5846086e29");
1578 try check(f32, 1.1811161e19, "1.1811161e19");
1579 try check(f32, 5.368709e18, "5.368709e18");
1580 try check(f32, 4.6143165e18, "4.6143166e18");
1581 try check(f32, 0.007812537, "7.812537e-3");
1582 try check(f32, 1.4e-45, "1e-45");
1583 try check(f32, 1.18697724e20, "1.18697725e20");
1584 try check(f32, 1.00014165e-36, "1.00014165e-36");
1585 try check(f32, 200.0, "2e2");
1586 try check(f32, 3.3554432e7, "3.3554432e7");
1587
1588 try check(f32, 1.0, "1e0");
1589 try check(f32, 1.2, "1.2e0");
1590 try check(f32, 1.23, "1.23e0");
1591 try check(f32, 1.234, "1.234e0");
1592 try check(f32, 1.2345, "1.2345e0");
1593 try check(f32, 1.23456, "1.23456e0");
1594 try check(f32, 1.234567, "1.234567e0");
1595 try check(f32, 1.2345678, "1.2345678e0");
1596 try check(f32, 1.23456735e-36, "1.23456735e-36");
1597}
1598
1599test "format f64" {
1600 try check(f64, 0.0, "0e0");
1601 try check(f64, -0.0, "-0e0");
1602 try check(f64, 1.0, "1e0");
1603 try check(f64, -1.0, "-1e0");
1604 try check(f64, std.math.nan(f64), "nan");
1605 try check(f64, std.math.inf(f64), "inf");
1606 try check(f64, -std.math.inf(f64), "-inf");
1607 try check(f64, 2.2250738585072014e-308, "2.2250738585072014e-308");
1608 try check(f64, @bitCast(@as(u64, 0x7fefffffffffffff)), "1.7976931348623157e308");
1609 try check(f64, @bitCast(@as(u64, 1)), "5e-324");
1610 try check(f64, 2.98023223876953125e-8, "2.9802322387695312e-8");
1611 try check(f64, -2.109808898695963e16, "-2.109808898695963e16");
1612 try check(f64, 4.940656e-318, "4.940656e-318");
1613 try check(f64, 1.18575755e-316, "1.18575755e-316");
1614 try check(f64, 2.989102097996e-312, "2.989102097996e-312");
1615 try check(f64, 9.0608011534336e15, "9.0608011534336e15");
1616 try check(f64, 4.708356024711512e18, "4.708356024711512e18");
1617 try check(f64, 9.409340012568248e18, "9.409340012568248e18");
1618 try check(f64, 1.2345678, "1.2345678e0");
1619 try check(f64, @bitCast(@as(u64, 0x4830f0cf064dd592)), "5.764607523034235e39");
1620 try check(f64, @bitCast(@as(u64, 0x4840f0cf064dd592)), "1.152921504606847e40");
1621 try check(f64, @bitCast(@as(u64, 0x4850f0cf064dd592)), "2.305843009213694e40");
1622
1623 try check(f64, 1, "1e0");
1624 try check(f64, 1.2, "1.2e0");
1625 try check(f64, 1.23, "1.23e0");
1626 try check(f64, 1.234, "1.234e0");
1627 try check(f64, 1.2345, "1.2345e0");
1628 try check(f64, 1.23456, "1.23456e0");
1629 try check(f64, 1.234567, "1.234567e0");
1630 try check(f64, 1.2345678, "1.2345678e0");
1631 try check(f64, 1.23456789, "1.23456789e0");
1632 try check(f64, 1.234567895, "1.234567895e0");
1633 try check(f64, 1.2345678901, "1.2345678901e0");
1634 try check(f64, 1.23456789012, "1.23456789012e0");
1635 try check(f64, 1.234567890123, "1.234567890123e0");
1636 try check(f64, 1.2345678901234, "1.2345678901234e0");
1637 try check(f64, 1.23456789012345, "1.23456789012345e0");
1638 try check(f64, 1.234567890123456, "1.234567890123456e0");
1639 try check(f64, 1.2345678901234567, "1.2345678901234567e0");
1640
1641 try check(f64, 4.294967294, "4.294967294e0");
1642 try check(f64, 4.294967295, "4.294967295e0");
1643 try check(f64, 4.294967296, "4.294967296e0");
1644 try check(f64, 4.294967297, "4.294967297e0");
1645 try check(f64, 4.294967298, "4.294967298e0");
1646}
1647
1648test "format f80" {
1649 try check(f80, 0.0, "0e0");
1650 try check(f80, -0.0, "-0e0");
1651 try check(f80, 1.0, "1e0");
1652 try check(f80, -1.0, "-1e0");
1653 try check(f80, std.math.nan(f80), "nan");
1654 try check(f80, std.math.inf(f80), "inf");
1655 try check(f80, -std.math.inf(f80), "-inf");
1656
1657 try check(f80, 2.2250738585072014e-308, "2.2250738585072014e-308");
1658 try check(f80, 2.98023223876953125e-8, "2.98023223876953125e-8");
1659 try check(f80, -2.109808898695963e16, "-2.109808898695963e16");
1660 try check(f80, 4.940656e-318, "4.940656e-318");
1661 try check(f80, 1.18575755e-316, "1.18575755e-316");
1662 try check(f80, 2.989102097996e-312, "2.989102097996e-312");
1663 try check(f80, 9.0608011534336e15, "9.0608011534336e15");
1664 try check(f80, 4.708356024711512e18, "4.708356024711512e18");
1665 try check(f80, 9.409340012568248e18, "9.409340012568248e18");
1666 try check(f80, 1.2345678, "1.2345678e0");
1667}
1668
1669test "format f128" {
1670 try check(f128, 0.0, "0e0");
1671 try check(f128, -0.0, "-0e0");
1672 try check(f128, 1.0, "1e0");
1673 try check(f128, -1.0, "-1e0");
1674 try check(f128, std.math.nan(f128), "nan");
1675 try check(f128, std.math.inf(f128), "inf");
1676 try check(f128, -std.math.inf(f128), "-inf");
1677
1678 try check(f128, 2.2250738585072014e-308, "2.2250738585072014e-308");
1679 try check(f128, 2.98023223876953125e-8, "2.98023223876953125e-8");
1680 try check(f128, -2.109808898695963e16, "-2.109808898695963e16");
1681 try check(f128, 4.940656e-318, "4.940656e-318");
1682 try check(f128, 1.18575755e-316, "1.18575755e-316");
1683 try check(f128, 2.989102097996e-312, "2.989102097996e-312");
1684 try check(f128, 9.0608011534336e15, "9.0608011534336e15");
1685 try check(f128, 4.708356024711512e18, "4.708356024711512e18");
1686 try check(f128, 9.409340012568248e18, "9.409340012568248e18");
1687 try check(f128, 1.2345678, "1.2345678e0");
1688}
1689
1690test "format float to decimal with zero precision" {
1691 try expectFmt("5", "{d:.0}", .{5});
1692 try expectFmt("6", "{d:.0}", .{6});
1693 try expectFmt("7", "{d:.0}", .{7});
1694 try expectFmt("8", "{d:.0}", .{8});
1695}
lib/std/fmt/format_float.zig deleted-1695
......@@ -1,1695 +0,0 @@
1//! This file implements the ryu floating point conversion algorithm:
2//! https://dl.acm.org/doi/pdf/10.1145/3360595
3
4const std = @import("std");
5const expectFmt = std.testing.expectFmt;
6
7const special_exponent = 0x7fffffff;
8
9/// Any buffer used for `format` must be at least this large. This is asserted. A runtime check will
10/// additionally be performed if more bytes are required.
11pub const min_buffer_size = 53;
12
13/// Returns the minimum buffer size needed to print every float of a specific type and format.
14pub fn bufferSize(comptime mode: Format, comptime T: type) comptime_int {
15 comptime std.debug.assert(@typeInfo(T) == .float);
16 return switch (mode) {
17 .scientific => 53,
18 // Based on minimum subnormal values.
19 .decimal => switch (@bitSizeOf(T)) {
20 16 => @max(15, min_buffer_size),
21 32 => 55,
22 64 => 347,
23 80 => 4996,
24 128 => 5011,
25 else => unreachable,
26 },
27 };
28}
29
30pub const FormatError = error{
31 BufferTooSmall,
32};
33
34pub const Format = enum {
35 scientific,
36 decimal,
37};
38
39pub const FormatOptions = struct {
40 mode: Format = .scientific,
41 precision: ?usize = null,
42};
43
44/// Format a floating-point value and write it to buffer. Returns a slice to the buffer containing
45/// the string representation.
46///
47/// Full precision is the default. Any full precision float can be reparsed with std.fmt.parseFloat
48/// unambiguously.
49///
50/// Scientific mode is recommended generally as the output is more compact and any type can be
51/// written in full precision using a buffer of only `min_buffer_size`.
52///
53/// When printing full precision decimals, use `bufferSize` to get the required space. It is
54/// recommended to bound decimal output with a fixed precision to reduce the required buffer size.
55pub fn formatFloat(buf: []u8, v_: anytype, options: FormatOptions) FormatError![]const u8 {
56 const v = switch (@TypeOf(v_)) {
57 // comptime_float internally is a f128; this preserves precision.
58 comptime_float => @as(f128, v_),
59 else => v_,
60 };
61
62 const T = @TypeOf(v);
63 comptime std.debug.assert(@typeInfo(T) == .float);
64 const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
65
66 const DT = if (@bitSizeOf(T) <= 64) u64 else u128;
67 const tables = switch (DT) {
68 u64 => if (@import("builtin").mode == .ReleaseSmall) &Backend64_TablesSmall else &Backend64_TablesFull,
69 u128 => &Backend128_Tables,
70 else => unreachable,
71 };
72
73 const has_explicit_leading_bit = std.math.floatMantissaBits(T) - std.math.floatFractionalBits(T) != 0;
74 const d = binaryToDecimal(DT, @as(I, @bitCast(v)), std.math.floatMantissaBits(T), std.math.floatExponentBits(T), has_explicit_leading_bit, tables);
75
76 return switch (options.mode) {
77 .scientific => formatScientific(DT, buf, d, options.precision),
78 .decimal => formatDecimal(DT, buf, d, options.precision),
79 };
80}
81
82pub fn FloatDecimal(comptime T: type) type {
83 comptime std.debug.assert(T == u64 or T == u128);
84 return struct {
85 mantissa: T,
86 exponent: i32,
87 sign: bool,
88 };
89}
90
91fn copySpecialStr(buf: []u8, f: anytype) []const u8 {
92 if (f.sign) {
93 buf[0] = '-';
94 }
95 const offset: usize = @intFromBool(f.sign);
96 if (f.mantissa != 0) {
97 @memcpy(buf[offset..][0..3], "nan");
98 return buf[0 .. 3 + offset];
99 }
100 @memcpy(buf[offset..][0..3], "inf");
101 return buf[0 .. 3 + offset];
102}
103
104fn writeDecimal(buf: []u8, value: anytype, count: usize) void {
105 var i: usize = 0;
106
107 while (i + 2 < count) : (i += 2) {
108 const c: u8 = @intCast(value.* % 100);
109 value.* /= 100;
110 const d = std.fmt.digits2(c);
111 buf[count - i - 1] = d[1];
112 buf[count - i - 2] = d[0];
113 }
114
115 while (i < count) : (i += 1) {
116 const c: u8 = @intCast(value.* % 10);
117 value.* /= 10;
118 buf[count - i - 1] = '0' + c;
119 }
120}
121
122fn isPowerOf10(n_: u128) bool {
123 var n = n_;
124 while (n != 0) : (n /= 10) {
125 if (n % 10 != 0) return false;
126 }
127 return true;
128}
129
130const RoundMode = enum {
131 /// 1234.56 = precision 2
132 decimal,
133 /// 1.23456e3 = precision 5
134 scientific,
135};
136
137fn round(comptime T: type, f: FloatDecimal(T), mode: RoundMode, precision: usize) FloatDecimal(T) {
138 var round_digit: usize = 0;
139 var output = f.mantissa;
140 var exp = f.exponent;
141 const olength = decimalLength(output);
142
143 switch (mode) {
144 .decimal => {
145 if (f.exponent > 0) {
146 round_digit = (olength - 1) + precision + @as(usize, @intCast(f.exponent));
147 } else {
148 const min_exp_required = @as(usize, @intCast(-f.exponent));
149 if (precision + olength > min_exp_required) {
150 round_digit = precision + olength - min_exp_required;
151 }
152 }
153 },
154 .scientific => {
155 round_digit = 1 + precision;
156 },
157 }
158
159 if (round_digit < olength) {
160 var nlength = olength;
161 for (round_digit + 1..olength) |_| {
162 output /= 10;
163 exp += 1;
164 nlength -= 1;
165 }
166
167 if (output % 10 >= 5) {
168 output /= 10;
169 output += 1;
170 exp += 1;
171
172 // e.g. 9999 -> 10000
173 if (isPowerOf10(output)) {
174 output /= 10;
175 exp += 1;
176 }
177 }
178 }
179
180 return .{
181 .mantissa = output,
182 .exponent = exp,
183 .sign = f.sign,
184 };
185}
186
187/// Write a FloatDecimal to a buffer in scientific form.
188///
189/// The buffer provided must be greater than `min_buffer_size` in length. If no precision is
190/// specified, this function will never return an error. If a precision is specified, up to
191/// `8 + precision` bytes will be written to the buffer. An error will be returned if the content
192/// will not fit.
193///
194/// It is recommended to bound decimal formatting with an exact precision.
195pub fn formatScientific(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) FormatError![]const u8 {
196 std.debug.assert(buf.len >= min_buffer_size);
197 var f = f_;
198
199 if (f.exponent == special_exponent) {
200 return copySpecialStr(buf, f);
201 }
202
203 if (precision) |prec| {
204 f = round(T, f, .scientific, prec);
205 }
206
207 var output = f.mantissa;
208 const olength = decimalLength(output);
209
210 if (precision) |prec| {
211 // fixed bound: sign(1) + leading_digit(1) + point(1) + exp_sign(1) + exp_max(4)
212 const req_bytes = 8 + prec;
213 if (buf.len < req_bytes) {
214 return error.BufferTooSmall;
215 }
216 }
217
218 // Step 5: Print the scientific representation
219 var index: usize = 0;
220 if (f.sign) {
221 buf[index] = '-';
222 index += 1;
223 }
224
225 // 1.12345
226 writeDecimal(buf[index + 2 ..], &output, olength - 1);
227 buf[index] = '0' + @as(u8, @intCast(output % 10));
228 buf[index + 1] = '.';
229 index += 2;
230 const dp_index = index;
231 if (olength > 1) index += olength - 1 else index -= 1;
232
233 if (precision) |prec| {
234 index += @intFromBool(olength == 1);
235 if (prec > olength - 1) {
236 const len = prec - (olength - 1);
237 @memset(buf[index..][0..len], '0');
238 index += len;
239 } else {
240 index = dp_index + prec - @intFromBool(prec == 0);
241 }
242 }
243
244 // e100
245 buf[index] = 'e';
246 index += 1;
247 var exp = f.exponent + @as(i32, @intCast(olength)) - 1;
248 if (exp < 0) {
249 buf[index] = '-';
250 index += 1;
251 exp = -exp;
252 }
253 var uexp: u32 = @intCast(exp);
254 const elength = decimalLength(uexp);
255 writeDecimal(buf[index..], &uexp, elength);
256 index += elength;
257
258 return buf[0..index];
259}
260
261/// Write a FloatDecimal to a buffer in decimal form.
262///
263/// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is
264/// specified, this may still return an error. If precision is specified, `2 + precision` bytes will
265/// always be written.
266pub fn formatDecimal(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) FormatError![]const u8 {
267 std.debug.assert(buf.len >= min_buffer_size);
268 var f = f_;
269
270 if (f.exponent == special_exponent) {
271 return copySpecialStr(buf, f);
272 }
273
274 if (precision) |prec| {
275 f = round(T, f, .decimal, prec);
276 }
277
278 var output = f.mantissa;
279 const olength = decimalLength(output);
280
281 // fixed bound: leading_digit(1) + point(1)
282 const req_bytes = if (f.exponent >= 0)
283 @as(usize, 2) + @abs(f.exponent) + olength + (precision orelse 0)
284 else
285 @as(usize, 2) + @max(@abs(f.exponent) + olength, precision orelse 0);
286 if (buf.len < req_bytes) {
287 return error.BufferTooSmall;
288 }
289
290 // Step 5: Print the decimal representation
291 var index: usize = 0;
292 if (f.sign) {
293 buf[index] = '-';
294 index += 1;
295 }
296
297 const dp_offset = f.exponent + cast_i32(olength);
298 if (dp_offset <= 0) {
299 // 0.000001234
300 buf[index] = '0';
301 buf[index + 1] = '.';
302 index += 2;
303 const dp_index = index;
304
305 const dp_poffset: u32 = @intCast(-dp_offset);
306 @memset(buf[index..][0..dp_poffset], '0');
307 index += dp_poffset;
308 writeDecimal(buf[index..], &output, olength);
309 index += olength;
310
311 if (precision) |prec| {
312 const dp_written = index - dp_index;
313 if (prec > dp_written) {
314 @memset(buf[index..][0 .. prec - dp_written], '0');
315 }
316 index = dp_index + prec - @intFromBool(prec == 0);
317 }
318 } else {
319 // 123456000
320 const dp_uoffset: usize = @intCast(dp_offset);
321 if (dp_uoffset >= olength) {
322 writeDecimal(buf[index..], &output, olength);
323 index += olength;
324 @memset(buf[index..][0 .. dp_uoffset - olength], '0');
325 index += dp_uoffset - olength;
326
327 if (precision) |prec| {
328 if (prec != 0) {
329 buf[index] = '.';
330 index += 1;
331 @memset(buf[index..][0..prec], '0');
332 index += prec;
333 }
334 }
335 } else {
336 // 12345.6789
337 writeDecimal(buf[index + dp_uoffset + 1 ..], &output, olength - dp_uoffset);
338 buf[index + dp_uoffset] = '.';
339 const dp_index = index + dp_uoffset + 1;
340 writeDecimal(buf[index..], &output, dp_uoffset);
341 index += olength + 1;
342
343 if (precision) |prec| {
344 const dp_written = olength - dp_uoffset;
345 if (prec > dp_written) {
346 @memset(buf[index..][0 .. prec - dp_written], '0');
347 }
348 index = dp_index + prec - @intFromBool(prec == 0);
349 }
350 }
351 }
352
353 return buf[0..index];
354}
355
356fn cast_i32(v: anytype) i32 {
357 return @intCast(v);
358}
359
360/// Convert a binary float representation to decimal.
361pub fn binaryToDecimal(comptime T: type, bits: T, mantissa_bits: std.math.Log2Int(T), exponent_bits: u5, explicit_leading_bit: bool, comptime tables: anytype) FloatDecimal(T) {
362 if (T != tables.T) {
363 @compileError("table type does not match backend type: " ++ @typeName(tables.T) ++ " != " ++ @typeName(T));
364 }
365
366 const bias = (@as(u32, 1) << (exponent_bits - 1)) - 1;
367 const ieee_sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
368 const ieee_mantissa = bits & ((@as(T, 1) << mantissa_bits) - 1);
369 const ieee_exponent: u32 = @intCast((bits >> mantissa_bits) & ((@as(T, 1) << exponent_bits) - 1));
370
371 if (ieee_exponent == 0 and ieee_mantissa == 0) {
372 return .{
373 .mantissa = 0,
374 .exponent = 0,
375 .sign = ieee_sign,
376 };
377 }
378 if (ieee_exponent == ((@as(u32, 1) << exponent_bits) - 1)) {
379 return .{
380 .mantissa = if (explicit_leading_bit) ieee_mantissa & ((@as(T, 1) << (mantissa_bits - 1)) - 1) else ieee_mantissa,
381 .exponent = special_exponent,
382 .sign = ieee_sign,
383 };
384 }
385
386 var e2: i32 = undefined;
387 var m2: T = undefined;
388 if (explicit_leading_bit) {
389 if (ieee_exponent == 0) {
390 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
391 } else {
392 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) + 1 - 2;
393 }
394 m2 = ieee_mantissa;
395 } else {
396 if (ieee_exponent == 0) {
397 e2 = 1 - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
398 m2 = ieee_mantissa;
399 } else {
400 e2 = cast_i32(ieee_exponent) - cast_i32(bias) - cast_i32(mantissa_bits) - 2;
401 m2 = (@as(T, 1) << mantissa_bits) | ieee_mantissa;
402 }
403 }
404 const even = (m2 & 1) == 0;
405 const accept_bounds = even;
406
407 // Step 2: Determine the interval of legal decimal representations.
408 const mv = 4 * m2;
409 const mm_shift: u1 = @intFromBool((ieee_mantissa != if (explicit_leading_bit) (@as(T, 1) << (mantissa_bits - 1)) else 0) or (ieee_exponent == 0));
410
411 // Step 3: Convert to a decimal power base using 128-bit arithmetic.
412 var vr: T = undefined;
413 var vp: T = undefined;
414 var vm: T = undefined;
415 var e10: i32 = undefined;
416 var vm_is_trailing_zeros = false;
417 var vr_is_trailing_zeros = false;
418 if (e2 >= 0) {
419 const q: u32 = log10Pow2(@intCast(e2)) - @intFromBool(e2 > 3);
420 e10 = cast_i32(q);
421 const k: i32 = @intCast(tables.POW5_INV_BITCOUNT + pow5Bits(q) - 1);
422 const i: u32 = @intCast(-e2 + cast_i32(q) + k);
423
424 const pow5 = tables.computeInvPow5(q);
425 vr = tables.mulShift(4 * m2, &pow5, i);
426 vp = tables.mulShift(4 * m2 + 2, &pow5, i);
427 vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, i);
428
429 if (q <= tables.bound1) {
430 if (mv % 5 == 0) {
431 vr_is_trailing_zeros = multipleOfPowerOf5(mv, if (tables.adjust_q) q -% 1 else q);
432 } else if (accept_bounds) {
433 vm_is_trailing_zeros = multipleOfPowerOf5(mv - 1 - mm_shift, q);
434 } else {
435 vp -= @intFromBool(multipleOfPowerOf5(mv + 2, q));
436 }
437 }
438 } else {
439 const q: u32 = log10Pow5(@intCast(-e2)) - @intFromBool(-e2 > 1);
440 e10 = cast_i32(q) + e2;
441 const i: i32 = -e2 - cast_i32(q);
442 const k: i32 = cast_i32(pow5Bits(@intCast(i))) - tables.POW5_BITCOUNT;
443 const j: u32 = @intCast(cast_i32(q) - k);
444
445 const pow5 = tables.computePow5(@intCast(i));
446 vr = tables.mulShift(4 * m2, &pow5, j);
447 vp = tables.mulShift(4 * m2 + 2, &pow5, j);
448 vm = tables.mulShift(4 * m2 - 1 - mm_shift, &pow5, j);
449
450 if (q <= 1) {
451 vr_is_trailing_zeros = true;
452 if (accept_bounds) {
453 vm_is_trailing_zeros = mm_shift == 1;
454 } else {
455 vp -= 1;
456 }
457 } else if (q < tables.bound2) {
458 vr_is_trailing_zeros = multipleOfPowerOf2(mv, if (tables.adjust_q) q - 1 else q);
459 }
460 }
461
462 // Step 4: Find the shortest decimal representation in the interval of legal representations.
463 var removed: u32 = 0;
464 var last_removed_digit: u8 = 0;
465
466 while (vp / 10 > vm / 10) {
467 vm_is_trailing_zeros = vm_is_trailing_zeros and vm % 10 == 0;
468 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
469 last_removed_digit = @intCast(vr % 10);
470 vr /= 10;
471 vp /= 10;
472 vm /= 10;
473 removed += 1;
474 }
475
476 if (vm_is_trailing_zeros) {
477 while (vm % 10 == 0) {
478 vr_is_trailing_zeros = vr_is_trailing_zeros and last_removed_digit == 0;
479 last_removed_digit = @intCast(vr % 10);
480 vr /= 10;
481 vp /= 10;
482 vm /= 10;
483 removed += 1;
484 }
485 }
486
487 if (vr_is_trailing_zeros and (last_removed_digit == 5) and (vr % 2 == 0)) {
488 last_removed_digit = 4;
489 }
490
491 return .{
492 .mantissa = vr + @intFromBool((vr == vm and (!accept_bounds or !vm_is_trailing_zeros)) or last_removed_digit >= 5),
493 .exponent = e10 + cast_i32(removed),
494 .sign = ieee_sign,
495 };
496}
497
498fn decimalLength(v: anytype) u32 {
499 switch (@TypeOf(v)) {
500 u32, u64 => {
501 std.debug.assert(v < 100000000000000000);
502 if (v >= 10000000000000000) return 17;
503 if (v >= 1000000000000000) return 16;
504 if (v >= 100000000000000) return 15;
505 if (v >= 10000000000000) return 14;
506 if (v >= 1000000000000) return 13;
507 if (v >= 100000000000) return 12;
508 if (v >= 10000000000) return 11;
509 if (v >= 1000000000) return 10;
510 if (v >= 100000000) return 9;
511 if (v >= 10000000) return 8;
512 if (v >= 1000000) return 7;
513 if (v >= 100000) return 6;
514 if (v >= 10000) return 5;
515 if (v >= 1000) return 4;
516 if (v >= 100) return 3;
517 if (v >= 10) return 2;
518 return 1;
519 },
520 u128 => {
521 const LARGEST_POW10 = (@as(u128, 5421010862427522170) << 64) | 687399551400673280;
522 var p10 = LARGEST_POW10;
523 var i: u32 = 39;
524 while (i > 0) : (i -= 1) {
525 if (v >= p10) return i;
526 p10 /= 10;
527 }
528 return 1;
529 },
530 else => unreachable,
531 }
532}
533
534// floor(log_10(2^e))
535fn log10Pow2(e: u32) u32 {
536 std.debug.assert(e <= 1 << 15);
537 return @intCast((@as(u64, @intCast(e)) * 169464822037455) >> 49);
538}
539
540// floor(log_10(5^e))
541fn log10Pow5(e: u32) u32 {
542 std.debug.assert(e <= 1 << 15);
543 return @intCast((@as(u64, @intCast(e)) * 196742565691928) >> 48);
544}
545
546// if (e == 0) 1 else ceil(log_2(5^e))
547fn pow5Bits(e: u32) u32 {
548 std.debug.assert(e <= 1 << 15);
549 return @intCast(((@as(u64, @intCast(e)) * 163391164108059) >> 46) + 1);
550}
551
552fn pow5Factor(value_: anytype) u32 {
553 var count: u32 = 0;
554 var value = value_;
555 while (value > 0) : ({
556 count += 1;
557 value /= 5;
558 }) {
559 if (value % 5 != 0) return count;
560 }
561 return 0;
562}
563
564fn multipleOfPowerOf5(value: anytype, p: u32) bool {
565 const T = @TypeOf(value);
566 std.debug.assert(@typeInfo(T) == .int);
567 return pow5Factor(value) >= p;
568}
569
570fn multipleOfPowerOf2(value: anytype, p: u32) bool {
571 const T = @TypeOf(value);
572 std.debug.assert(@typeInfo(T) == .int);
573 return (value & ((@as(T, 1) << @as(std.math.Log2Int(T), @intCast(p))) - 1)) == 0;
574}
575
576fn mulShift128(m: u128, mul: *const [4]u64, j: u32) u128 {
577 std.debug.assert(j > 128);
578 const a: [2]u64 = .{ @truncate(m), @truncate(m >> 64) };
579 const r = mul_128_256_shift(&a, mul, j, 0);
580 return (@as(u128, r[1]) << 64) | r[0];
581}
582
583fn mul_128_256_shift(a: *const [2]u64, b: *const [4]u64, shift: u32, corr: u32) [4]u64 {
584 std.debug.assert(shift > 0);
585 std.debug.assert(shift < 256);
586
587 const b00 = @as(u128, a[0]) * b[0];
588 const b01 = @as(u128, a[0]) * b[1];
589 const b02 = @as(u128, a[0]) * b[2];
590 const b03 = @as(u128, a[0]) * b[3];
591 const b10 = @as(u128, a[1]) * b[0];
592 const b11 = @as(u128, a[1]) * b[1];
593 const b12 = @as(u128, a[1]) * b[2];
594 const b13 = @as(u128, a[1]) * b[3];
595
596 const s0 = b00;
597 const s1 = b01 +% b10;
598 const c1: u128 = @intFromBool(s1 < b01);
599 const s2 = b02 +% b11;
600 const c2: u128 = @intFromBool(s2 < b02);
601 const s3 = b03 +% b12;
602 const c3: u128 = @intFromBool(s3 < b03);
603
604 const p0 = s0 +% (s1 << 64);
605 const d0: u128 = @intFromBool(p0 < b00);
606 const q1 = s2 +% (s1 >> 64) +% (s3 << 64);
607 const d1: u128 = @intFromBool(q1 < s2);
608 const p1 = q1 +% (c1 << 64) +% d0;
609 const d2: u128 = @intFromBool(p1 < q1);
610 const p2 = b13 +% (s3 >> 64) +% c2 +% (c3 << 64) +% d1 +% d2;
611
612 var r0: u128 = undefined;
613 var r1: u128 = undefined;
614 if (shift < 128) {
615 const cshift: u7 = @intCast(shift);
616 const sshift: u7 = @intCast(128 - shift);
617 r0 = corr +% ((p0 >> cshift) | (p1 << sshift));
618 r1 = ((p1 >> cshift) | (p2 << sshift)) +% @intFromBool(r0 < corr);
619 } else if (shift == 128) {
620 r0 = corr +% p1;
621 r1 = p2 +% @intFromBool(r0 < corr);
622 } else {
623 const ashift: u7 = @intCast(shift - 128);
624 const sshift: u7 = @intCast(256 - shift);
625 r0 = corr +% ((p1 >> ashift) | (p2 << sshift));
626 r1 = (p2 >> ashift) +% @intFromBool(r0 < corr);
627 }
628
629 return .{ @truncate(r0), @truncate(r0 >> 64), @truncate(r1), @truncate(r1 >> 64) };
630}
631
632pub const Backend128_Tables = struct {
633 const T = u128;
634 const mulShift = mulShift128;
635 const POW5_INV_BITCOUNT = FLOAT128_POW5_INV_BITCOUNT;
636 const POW5_BITCOUNT = FLOAT128_POW5_BITCOUNT;
637
638 const bound1 = 55;
639 const bound2 = 127;
640 const adjust_q = true;
641
642 fn computePow5(i: u32) [4]u64 {
643 const base = i / FLOAT128_POW5_TABLE_SIZE;
644 const base2 = base * FLOAT128_POW5_TABLE_SIZE;
645 const mul = &FLOAT128_POW5_SPLIT[base];
646 if (i == base2) {
647 return mul.*;
648 } else {
649 const offset = i - base2;
650 const m = &FLOAT128_POW5_TABLE[offset];
651 const delta = pow5Bits(i) - pow5Bits(base2);
652
653 const shift: u6 = @intCast(2 * (i % 32));
654 const corr: u32 = @intCast((FLOAT128_POW5_ERRORS[i / 32] >> shift) & 3);
655 return mul_128_256_shift(m, mul, delta, corr);
656 }
657 }
658
659 fn computeInvPow5(i: u32) [4]u64 {
660 const base = (i + FLOAT128_POW5_TABLE_SIZE - 1) / FLOAT128_POW5_TABLE_SIZE;
661 const base2 = base * FLOAT128_POW5_TABLE_SIZE;
662 const mul = &FLOAT128_POW5_INV_SPLIT[base]; // 1 / 5^base2
663 if (i == base2) {
664 return .{ mul[0] + 1, mul[1], mul[2], mul[3] };
665 } else {
666 const offset = base2 - i;
667 const m = &FLOAT128_POW5_TABLE[offset]; // 5^offset
668 const delta = pow5Bits(base2) - pow5Bits(i);
669
670 const shift: u6 = @intCast(2 * (i % 32));
671 const corr: u32 = @intCast(((FLOAT128_POW5_INV_ERRORS[i / 32] >> shift) & 3) + 1);
672 return mul_128_256_shift(m, mul, delta, corr);
673 }
674 }
675};
676
677fn mulShift64(m: u64, mul: *const [2]u64, j: u32) u64 {
678 std.debug.assert(j > 64);
679 const b0 = @as(u128, m) * mul[0];
680 const b2 = @as(u128, m) * mul[1];
681
682 if (j < 128) {
683 const shift: u6 = @intCast(j - 64);
684 return @intCast(((b0 >> 64) + b2) >> shift);
685 } else {
686 return 0;
687 }
688}
689
690pub const Backend64_TablesFull = struct {
691 const T = u64;
692 const mulShift = mulShift64;
693 const POW5_INV_BITCOUNT = FLOAT64_POW5_INV_BITCOUNT;
694 const POW5_BITCOUNT = FLOAT64_POW5_BITCOUNT;
695
696 const bound1 = 21;
697 const bound2 = 63;
698 const adjust_q = false;
699
700 fn computePow5(i: u32) [2]u64 {
701 return FLOAT64_POW5_SPLIT[i];
702 }
703
704 fn computeInvPow5(i: u32) [2]u64 {
705 return FLOAT64_POW5_INV_SPLIT[i];
706 }
707};
708
709pub const Backend64_TablesSmall = struct {
710 const T = u64;
711 const mulShift = mulShift64;
712 const POW5_INV_BITCOUNT = FLOAT64_POW5_INV_BITCOUNT;
713 const POW5_BITCOUNT = FLOAT64_POW5_BITCOUNT;
714
715 const bound1 = 21;
716 const bound2 = 63;
717 const adjust_q = false;
718
719 fn computePow5(i: u32) [2]u64 {
720 const base = i / FLOAT64_POW5_TABLE_SIZE;
721 const base2 = base * FLOAT64_POW5_TABLE_SIZE;
722 const mul = &FLOAT64_POW5_SPLIT2[base];
723 if (i == base2) {
724 return .{ mul[0], mul[1] };
725 } else {
726 const offset = i - base2;
727 const m = FLOAT64_POW5_TABLE[offset];
728 const b0 = @as(u128, m) * mul[0];
729 const b2 = @as(u128, m) * mul[1];
730 const delta: u7 = @intCast(pow5Bits(i) - pow5Bits(base2));
731 const shift: u5 = @intCast((i % 16) << 1);
732 const shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((FLOAT64_POW5_OFFSETS[i / 16] >> shift) & 3);
733 return .{ @truncate(shifted_sum), @truncate(shifted_sum >> 64) };
734 }
735 }
736
737 fn computeInvPow5(i: u32) [2]u64 {
738 const base = (i + FLOAT64_POW5_TABLE_SIZE - 1) / FLOAT64_POW5_TABLE_SIZE;
739 const base2 = base * FLOAT64_POW5_TABLE_SIZE;
740 const mul = &FLOAT64_POW5_INV_SPLIT2[base]; // 1 / 5^base2
741 if (i == base2) {
742 return .{ mul[0], mul[1] };
743 } else {
744 const offset = base2 - i;
745 const m = FLOAT64_POW5_TABLE[offset]; // 5^offset
746 const b0 = @as(u128, m) * (mul[0] - 1);
747 const b2 = @as(u128, m) * mul[1]; // 1/5^base2 * 5^offset = 1/5^(base2-offset) = 1/5^i
748 const delta: u7 = @intCast(pow5Bits(base2) - pow5Bits(i));
749 const shift: u5 = @intCast((i % 16) << 1);
750 const shifted_sum = ((b0 >> delta) + (b2 << (64 - delta))) + 1 + ((FLOAT64_POW5_INV_OFFSETS[i / 16] >> shift) & 3);
751 return .{ @truncate(shifted_sum), @truncate(shifted_sum >> 64) };
752 }
753 }
754};
755
756const FLOAT64_POW5_INV_BITCOUNT = 125;
757const FLOAT64_POW5_BITCOUNT = 125;
758
759// zig fmt: off
760//
761// f64 small tables: 816 bytes
762
763const FLOAT64_POW5_TABLE_SIZE: comptime_int = FLOAT64_POW5_TABLE.len;
764
765const FLOAT64_POW5_TABLE: [26]u64 = .{
766 1, 5,
767 25, 125,
768 625, 3125,
769 15625, 78125,
770 390625, 1953125,
771 9765625, 48828125,
772 244140625, 1220703125,
773 6103515625, 30517578125,
774 152587890625, 762939453125,
775 3814697265625, 19073486328125,
776 95367431640625, 476837158203125,
777 2384185791015625, 11920928955078125,
778 59604644775390625, 298023223876953125,
779};
780
781const FLOAT64_POW5_SPLIT2: [13][2]u64 = .{
782 .{ 0, 1152921504606846976 },
783 .{ 0, 1490116119384765625 },
784 .{ 1032610780636961552, 1925929944387235853 },
785 .{ 7910200175544436838, 1244603055572228341 },
786 .{ 16941905809032713930, 1608611746708759036 },
787 .{ 13024893955298202172, 2079081953128979843 },
788 .{ 6607496772837067824, 1343575221513417750 },
789 .{ 17332926989895652603, 1736530273035216783 },
790 .{ 13037379183483547984, 2244412773384604712 },
791 .{ 1605989338741628675, 1450417759929778918 },
792 .{ 9630225068416591280, 1874621017369538693 },
793 .{ 665883850346957067, 1211445438634777304 },
794 .{ 14931890668723713708, 1565756531257009982 }
795};
796
797const FLOAT64_POW5_OFFSETS: [21]u32 = .{
798 0x00000000, 0x00000000, 0x00000000, 0x00000000,
799 0x40000000, 0x59695995, 0x55545555, 0x56555515,
800 0x41150504, 0x40555410, 0x44555145, 0x44504540,
801 0x45555550, 0x40004000, 0x96440440, 0x55565565,
802 0x54454045, 0x40154151, 0x55559155, 0x51405555,
803 0x00000105,
804};
805
806const FLOAT64_POW5_INV_SPLIT2: [15][2]u64 = .{
807 .{ 1, 2305843009213693952 },
808 .{ 5955668970331000884, 1784059615882449851 },
809 .{ 8982663654677661702, 1380349269358112757 },
810 .{ 7286864317269821294, 2135987035920910082 },
811 .{ 7005857020398200553, 1652639921975621497 },
812 .{ 17965325103354776697, 1278668206209430417 },
813 .{ 8928596168509315048, 1978643211784836272 },
814 .{ 10075671573058298858, 1530901034580419511 },
815 .{ 597001226353042382, 1184477304306571148 },
816 .{ 1527430471115325346, 1832889850782397517 },
817 .{ 12533209867169019542, 1418129833677084982 },
818 .{ 5577825024675947042, 2194449627517475473 },
819 .{ 11006974540203867551, 1697873161311732311 },
820 .{ 10313493231639821582, 1313665730009899186 },
821 .{ 12701016819766672773, 2032799256770390445 }
822};
823
824const FLOAT64_POW5_INV_OFFSETS: [19]u32 = .{
825 0x54544554, 0x04055545, 0x10041000, 0x00400414,
826 0x40010000, 0x41155555, 0x00000454, 0x00010044,
827 0x40000000, 0x44000041, 0x50454450, 0x55550054,
828 0x51655554, 0x40004000, 0x01000001, 0x00010500,
829 0x51515411, 0x05555554, 0x00000000,
830};
831
832
833// zig fmt: off
834
835// f64 full tables: 10688 bytes
836
837const FLOAT64_POW5_SPLIT: [326][2]u64 = .{
838 .{ 0, 1152921504606846976 }, .{ 0, 1441151880758558720 },
839 .{ 0, 1801439850948198400 }, .{ 0, 2251799813685248000 },
840 .{ 0, 1407374883553280000 }, .{ 0, 1759218604441600000 },
841 .{ 0, 2199023255552000000 }, .{ 0, 1374389534720000000 },
842 .{ 0, 1717986918400000000 }, .{ 0, 2147483648000000000 },
843 .{ 0, 1342177280000000000 }, .{ 0, 1677721600000000000 },
844 .{ 0, 2097152000000000000 }, .{ 0, 1310720000000000000 },
845 .{ 0, 1638400000000000000 }, .{ 0, 2048000000000000000 },
846 .{ 0, 1280000000000000000 }, .{ 0, 1600000000000000000 },
847 .{ 0, 2000000000000000000 }, .{ 0, 1250000000000000000 },
848 .{ 0, 1562500000000000000 }, .{ 0, 1953125000000000000 },
849 .{ 0, 1220703125000000000 }, .{ 0, 1525878906250000000 },
850 .{ 0, 1907348632812500000 }, .{ 0, 1192092895507812500 },
851 .{ 0, 1490116119384765625 }, .{ 4611686018427387904, 1862645149230957031 },
852 .{ 9799832789158199296, 1164153218269348144 }, .{ 12249790986447749120, 1455191522836685180 },
853 .{ 15312238733059686400, 1818989403545856475 }, .{ 14528612397897220096, 2273736754432320594 },
854 .{ 13692068767113150464, 1421085471520200371 }, .{ 12503399940464050176, 1776356839400250464 },
855 .{ 15629249925580062720, 2220446049250313080 }, .{ 9768281203487539200, 1387778780781445675 },
856 .{ 7598665485932036096, 1734723475976807094 }, .{ 274959820560269312, 2168404344971008868 },
857 .{ 9395221924704944128, 1355252715606880542 }, .{ 2520655369026404352, 1694065894508600678 },
858 .{ 12374191248137781248, 2117582368135750847 }, .{ 14651398557727195136, 1323488980084844279 },
859 .{ 13702562178731606016, 1654361225106055349 }, .{ 3293144668132343808, 2067951531382569187 },
860 .{ 18199116482078572544, 1292469707114105741 }, .{ 8913837547316051968, 1615587133892632177 },
861 .{ 15753982952572452864, 2019483917365790221 }, .{ 12152082354571476992, 1262177448353618888 },
862 .{ 15190102943214346240, 1577721810442023610 }, .{ 9764256642163156992, 1972152263052529513 },
863 .{ 17631875447420442880, 1232595164407830945 }, .{ 8204786253993389888, 1540743955509788682 },
864 .{ 1032610780636961552, 1925929944387235853 }, .{ 2951224747111794922, 1203706215242022408 },
865 .{ 3689030933889743652, 1504632769052528010 }, .{ 13834660704216955373, 1880790961315660012 },
866 .{ 17870034976990372916, 1175494350822287507 }, .{ 17725857702810578241, 1469367938527859384 },
867 .{ 3710578054803671186, 1836709923159824231 }, .{ 26536550077201078, 2295887403949780289 },
868 .{ 11545800389866720434, 1434929627468612680 }, .{ 14432250487333400542, 1793662034335765850 },
869 .{ 8816941072311974870, 2242077542919707313 }, .{ 17039803216263454053, 1401298464324817070 },
870 .{ 12076381983474541759, 1751623080406021338 }, .{ 5872105442488401391, 2189528850507526673 },
871 .{ 15199280947623720629, 1368455531567204170 }, .{ 9775729147674874978, 1710569414459005213 },
872 .{ 16831347453020981627, 2138211768073756516 }, .{ 1296220121283337709, 1336382355046097823 },
873 .{ 15455333206886335848, 1670477943807622278 }, .{ 10095794471753144002, 2088097429759527848 },
874 .{ 6309871544845715001, 1305060893599704905 }, .{ 12499025449484531656, 1631326116999631131 },
875 .{ 11012095793428276666, 2039157646249538914 }, .{ 11494245889320060820, 1274473528905961821 },
876 .{ 532749306367912313, 1593091911132452277 }, .{ 5277622651387278295, 1991364888915565346 },
877 .{ 7910200175544436838, 1244603055572228341 }, .{ 14499436237857933952, 1555753819465285426 },
878 .{ 8900923260467641632, 1944692274331606783 }, .{ 12480606065433357876, 1215432671457254239 },
879 .{ 10989071563364309441, 1519290839321567799 }, .{ 9124653435777998898, 1899113549151959749 },
880 .{ 8008751406574943263, 1186945968219974843 }, .{ 5399253239791291175, 1483682460274968554 },
881 .{ 15972438586593889776, 1854603075343710692 }, .{ 759402079766405302, 1159126922089819183 },
882 .{ 14784310654990170340, 1448908652612273978 }, .{ 9257016281882937117, 1811135815765342473 },
883 .{ 16182956370781059300, 2263919769706678091 }, .{ 7808504722524468110, 1414949856066673807 },
884 .{ 5148944884728197234, 1768687320083342259 }, .{ 1824495087482858639, 2210859150104177824 },
885 .{ 1140309429676786649, 1381786968815111140 }, .{ 1425386787095983311, 1727233711018888925 },
886 .{ 6393419502297367043, 2159042138773611156 }, .{ 13219259225790630210, 1349401336733506972 },
887 .{ 16524074032238287762, 1686751670916883715 }, .{ 16043406521870471799, 2108439588646104644 },
888 .{ 803757039314269066, 1317774742903815403 }, .{ 14839754354425000045, 1647218428629769253 },
889 .{ 4714634887749086344, 2059023035787211567 }, .{ 9864175832484260821, 1286889397367007229 },
890 .{ 16941905809032713930, 1608611746708759036 }, .{ 2730638187581340797, 2010764683385948796 },
891 .{ 10930020904093113806, 1256727927116217997 }, .{ 18274212148543780162, 1570909908895272496 },
892 .{ 4396021111970173586, 1963637386119090621 }, .{ 5053356204195052443, 1227273366324431638 },
893 .{ 15540067292098591362, 1534091707905539547 }, .{ 14813398096695851299, 1917614634881924434 },
894 .{ 13870059828862294966, 1198509146801202771 }, .{ 12725888767650480803, 1498136433501503464 },
895 .{ 15907360959563101004, 1872670541876879330 }, .{ 14553786618154326031, 1170419088673049581 },
896 .{ 4357175217410743827, 1463023860841311977 }, .{ 10058155040190817688, 1828779826051639971 },
897 .{ 7961007781811134206, 2285974782564549964 }, .{ 14199001900486734687, 1428734239102843727 },
898 .{ 13137066357181030455, 1785917798878554659 }, .{ 11809646928048900164, 2232397248598193324 },
899 .{ 16604401366885338411, 1395248280373870827 }, .{ 16143815690179285109, 1744060350467338534 },
900 .{ 10956397575869330579, 2180075438084173168 }, .{ 6847748484918331612, 1362547148802608230 },
901 .{ 17783057643002690323, 1703183936003260287 }, .{ 17617136035325974999, 2128979920004075359 },
902 .{ 17928239049719816230, 1330612450002547099 }, .{ 17798612793722382384, 1663265562503183874 },
903 .{ 13024893955298202172, 2079081953128979843 }, .{ 5834715712847682405, 1299426220705612402 },
904 .{ 16516766677914378815, 1624282775882015502 }, .{ 11422586310538197711, 2030353469852519378 },
905 .{ 11750802462513761473, 1268970918657824611 }, .{ 10076817059714813937, 1586213648322280764 },
906 .{ 12596021324643517422, 1982767060402850955 }, .{ 5566670318688504437, 1239229412751781847 },
907 .{ 2346651879933242642, 1549036765939727309 }, .{ 7545000868343941206, 1936295957424659136 },
908 .{ 4715625542714963254, 1210184973390411960 }, .{ 5894531928393704067, 1512731216738014950 },
909 .{ 16591536947346905892, 1890914020922518687 }, .{ 17287239619732898039, 1181821263076574179 },
910 .{ 16997363506238734644, 1477276578845717724 }, .{ 2799960309088866689, 1846595723557147156 },
911 .{ 10973347230035317489, 1154122327223216972 }, .{ 13716684037544146861, 1442652909029021215 },
912 .{ 12534169028502795672, 1803316136286276519 }, .{ 11056025267201106687, 2254145170357845649 },
913 .{ 18439230838069161439, 1408840731473653530 }, .{ 13825666510731675991, 1761050914342066913 },
914 .{ 3447025083132431277, 2201313642927583642 }, .{ 6766076695385157452, 1375821026829739776 },
915 .{ 8457595869231446815, 1719776283537174720 }, .{ 10571994836539308519, 2149720354421468400 },
916 .{ 6607496772837067824, 1343575221513417750 }, .{ 17482743002901110588, 1679469026891772187 },
917 .{ 17241742735199000331, 2099336283614715234 }, .{ 15387775227926763111, 1312085177259197021 },
918 .{ 5399660979626290177, 1640106471573996277 }, .{ 11361262242960250625, 2050133089467495346 },
919 .{ 11712474920277544544, 1281333180917184591 }, .{ 10028907631919542777, 1601666476146480739 },
920 .{ 7924448521472040567, 2002083095183100924 }, .{ 14176152362774801162, 1251301934489438077 },
921 .{ 3885132398186337741, 1564127418111797597 }, .{ 9468101516160310080, 1955159272639746996 },
922 .{ 15140935484454969608, 1221974545399841872 }, .{ 479425281859160394, 1527468181749802341 },
923 .{ 5210967620751338397, 1909335227187252926 }, .{ 17091912818251750210, 1193334516992033078 },
924 .{ 12141518985959911954, 1491668146240041348 }, .{ 15176898732449889943, 1864585182800051685 },
925 .{ 11791404716994875166, 1165365739250032303 }, .{ 10127569877816206054, 1456707174062540379 },
926 .{ 8047776328842869663, 1820883967578175474 }, .{ 836348374198811271, 2276104959472719343 },
927 .{ 7440246761515338900, 1422565599670449589 }, .{ 13911994470321561530, 1778206999588061986 },
928 .{ 8166621051047176104, 2222758749485077483 }, .{ 2798295147690791113, 1389224218428173427 },
929 .{ 17332926989895652603, 1736530273035216783 }, .{ 17054472718942177850, 2170662841294020979 },
930 .{ 8353202440125167204, 1356664275808763112 }, .{ 10441503050156459005, 1695830344760953890 },
931 .{ 3828506775840797949, 2119787930951192363 }, .{ 86973725686804766, 1324867456844495227 },
932 .{ 13943775212390669669, 1656084321055619033 }, .{ 3594660960206173375, 2070105401319523792 },
933 .{ 2246663100128858359, 1293815875824702370 }, .{ 12031700912015848757, 1617269844780877962 },
934 .{ 5816254103165035138, 2021587305976097453 }, .{ 5941001823691840913, 1263492066235060908 },
935 .{ 7426252279614801142, 1579365082793826135 }, .{ 4671129331091113523, 1974206353492282669 },
936 .{ 5225298841145639904, 1233878970932676668 }, .{ 6531623551432049880, 1542348713665845835 },
937 .{ 3552843420862674446, 1927935892082307294 }, .{ 16055585193321335241, 1204959932551442058 },
938 .{ 10846109454796893243, 1506199915689302573 }, .{ 18169322836923504458, 1882749894611628216 },
939 .{ 11355826773077190286, 1176718684132267635 }, .{ 9583097447919099954, 1470898355165334544 },
940 .{ 11978871809898874942, 1838622943956668180 }, .{ 14973589762373593678, 2298278679945835225 },
941 .{ 2440964573842414192, 1436424174966147016 }, .{ 3051205717303017741, 1795530218707683770 },
942 .{ 13037379183483547984, 2244412773384604712 }, .{ 8148361989677217490, 1402757983365377945 },
943 .{ 14797138505523909766, 1753447479206722431 }, .{ 13884737113477499304, 2191809349008403039 },
944 .{ 15595489723564518921, 1369880843130251899 }, .{ 14882676136028260747, 1712351053912814874 },
945 .{ 9379973133180550126, 2140438817391018593 }, .{ 17391698254306313589, 1337774260869386620 },
946 .{ 3292878744173340370, 1672217826086733276 }, .{ 4116098430216675462, 2090272282608416595 },
947 .{ 266718509671728212, 1306420176630260372 }, .{ 333398137089660265, 1633025220787825465 },
948 .{ 5028433689789463235, 2041281525984781831 }, .{ 10060300083759496378, 1275800953740488644 },
949 .{ 12575375104699370472, 1594751192175610805 }, .{ 1884160825592049379, 1993438990219513507 },
950 .{ 17318501580490888525, 1245899368887195941 }, .{ 7813068920331446945, 1557374211108994927 },
951 .{ 5154650131986920777, 1946717763886243659 }, .{ 915813323278131534, 1216698602428902287 },
952 .{ 14979824709379828129, 1520873253036127858 }, .{ 9501408849870009354, 1901091566295159823 },
953 .{ 12855909558809837702, 1188182228934474889 }, .{ 2234828893230133415, 1485227786168093612 },
954 .{ 2793536116537666769, 1856534732710117015 }, .{ 8663489100477123587, 1160334207943823134 },
955 .{ 1605989338741628675, 1450417759929778918 }, .{ 11230858710281811652, 1813022199912223647 },
956 .{ 9426887369424876662, 2266277749890279559 }, .{ 12809333633531629769, 1416423593681424724 },
957 .{ 16011667041914537212, 1770529492101780905 }, .{ 6179525747111007803, 2213161865127226132 },
958 .{ 13085575628799155685, 1383226165704516332 }, .{ 16356969535998944606, 1729032707130645415 },
959 .{ 15834525901571292854, 2161290883913306769 }, .{ 2979049660840976177, 1350806802445816731 },
960 .{ 17558870131333383934, 1688508503057270913 }, .{ 8113529608884566205, 2110635628821588642 },
961 .{ 9682642023980241782, 1319147268013492901 }, .{ 16714988548402690132, 1648934085016866126 },
962 .{ 11670363648648586857, 2061167606271082658 }, .{ 11905663298832754689, 1288229753919426661 },
963 .{ 1047021068258779650, 1610287192399283327 }, .{ 15143834390605638274, 2012858990499104158 },
964 .{ 4853210475701136017, 1258036869061940099 }, .{ 1454827076199032118, 1572546086327425124 },
965 .{ 1818533845248790147, 1965682607909281405 }, .{ 3442426662494187794, 1228551629943300878 },
966 .{ 13526405364972510550, 1535689537429126097 }, .{ 3072948650933474476, 1919611921786407622 },
967 .{ 15755650962115585259, 1199757451116504763 }, .{ 15082877684217093670, 1499696813895630954 },
968 .{ 9630225068416591280, 1874621017369538693 }, .{ 8324733676974063502, 1171638135855961683 },
969 .{ 5794231077790191473, 1464547669819952104 }, .{ 7242788847237739342, 1830684587274940130 },
970 .{ 18276858095901949986, 2288355734093675162 }, .{ 16034722328366106645, 1430222333808546976 },
971 .{ 1596658836748081690, 1787777917260683721 }, .{ 6607509564362490017, 2234722396575854651 },
972 .{ 1823850468512862308, 1396701497859909157 }, .{ 6891499104068465790, 1745876872324886446 },
973 .{ 17837745916940358045, 2182346090406108057 }, .{ 4231062170446641922, 1363966306503817536 },
974 .{ 5288827713058302403, 1704957883129771920 }, .{ 6611034641322878003, 2131197353912214900 },
975 .{ 13355268687681574560, 1331998346195134312 }, .{ 16694085859601968200, 1664997932743917890 },
976 .{ 11644235287647684442, 2081247415929897363 }, .{ 4971804045566108824, 1300779634956185852 },
977 .{ 6214755056957636030, 1625974543695232315 }, .{ 3156757802769657134, 2032468179619040394 },
978 .{ 6584659645158423613, 1270292612261900246 }, .{ 17454196593302805324, 1587865765327375307 },
979 .{ 17206059723201118751, 1984832206659219134 }, .{ 6142101308573311315, 1240520129162011959 },
980 .{ 3065940617289251240, 1550650161452514949 }, .{ 8444111790038951954, 1938312701815643686 },
981 .{ 665883850346957067, 1211445438634777304 }, .{ 832354812933696334, 1514306798293471630 },
982 .{ 10263815553021896226, 1892883497866839537 }, .{ 17944099766707154901, 1183052186166774710 },
983 .{ 13206752671529167818, 1478815232708468388 }, .{ 16508440839411459773, 1848519040885585485 },
984 .{ 12623618533845856310, 1155324400553490928 }, .{ 15779523167307320387, 1444155500691863660 },
985 .{ 1277659885424598868, 1805194375864829576 }, .{ 1597074856780748586, 2256492969831036970 },
986 .{ 5609857803915355770, 1410308106144398106 }, .{ 16235694291748970521, 1762885132680497632 },
987 .{ 1847873790976661535, 2203606415850622041 }, .{ 12684136165428883219, 1377254009906638775 },
988 .{ 11243484188358716120, 1721567512383298469 }, .{ 219297180166231438, 2151959390479123087 },
989 .{ 7054589765244976505, 1344974619049451929 }, .{ 13429923224983608535, 1681218273811814911 },
990 .{ 12175718012802122765, 2101522842264768639 }, .{ 14527352785642408584, 1313451776415480399 },
991 .{ 13547504963625622826, 1641814720519350499 }, .{ 12322695186104640628, 2052268400649188124 },
992 .{ 16925056528170176201, 1282667750405742577 }, .{ 7321262604930556539, 1603334688007178222 },
993 .{ 18374950293017971482, 2004168360008972777 }, .{ 4566814905495150320, 1252605225005607986 },
994 .{ 14931890668723713708, 1565756531257009982 }, .{ 9441491299049866327, 1957195664071262478 },
995 .{ 1289246043478778550, 1223247290044539049 }, .{ 6223243572775861092, 1529059112555673811 },
996 .{ 3167368447542438461, 1911323890694592264 }, .{ 1979605279714024038, 1194577431684120165 },
997 .{ 7086192618069917952, 1493221789605150206 }, .{ 18081112809442173248, 1866527237006437757 },
998 .{ 13606538515115052232, 1166579523129023598 }, .{ 7784801107039039482, 1458224403911279498 },
999 .{ 507629346944023544, 1822780504889099373 }, .{ 5246222702107417334, 2278475631111374216 },
1000 .{ 3278889188817135834, 1424047269444608885 }, .{ 8710297504448807696, 1780059086805761106 }
1001};
1002
1003const FLOAT64_POW5_INV_SPLIT: [342][2]u64 = .{
1004 .{ 1, 2305843009213693952 }, .{ 11068046444225730970, 1844674407370955161 },
1005 .{ 5165088340638674453, 1475739525896764129 }, .{ 7821419487252849886, 1180591620717411303 },
1006 .{ 8824922364862649494, 1888946593147858085 }, .{ 7059937891890119595, 1511157274518286468 },
1007 .{ 13026647942995916322, 1208925819614629174 }, .{ 9774590264567735146, 1934281311383406679 },
1008 .{ 11509021026396098440, 1547425049106725343 }, .{ 16585914450600699399, 1237940039285380274 },
1009 .{ 15469416676735388068, 1980704062856608439 }, .{ 16064882156130220778, 1584563250285286751 },
1010 .{ 9162556910162266299, 1267650600228229401 }, .{ 7281393426775805432, 2028240960365167042 },
1011 .{ 16893161185646375315, 1622592768292133633 }, .{ 2446482504291369283, 1298074214633706907 },
1012 .{ 7603720821608101175, 2076918743413931051 }, .{ 2393627842544570617, 1661534994731144841 },
1013 .{ 16672297533003297786, 1329227995784915872 }, .{ 11918280793837635165, 2126764793255865396 },
1014 .{ 5845275820328197809, 1701411834604692317 }, .{ 15744267100488289217, 1361129467683753853 },
1015 .{ 3054734472329800808, 2177807148294006166 }, .{ 17201182836831481939, 1742245718635204932 },
1016 .{ 6382248639981364905, 1393796574908163946 }, .{ 2832900194486363201, 2230074519853062314 },
1017 .{ 5955668970331000884, 1784059615882449851 }, .{ 1075186361522890384, 1427247692705959881 },
1018 .{ 12788344622662355584, 2283596308329535809 }, .{ 13920024512871794791, 1826877046663628647 },
1019 .{ 3757321980813615186, 1461501637330902918 }, .{ 10384555214134712795, 1169201309864722334 },
1020 .{ 5547241898389809503, 1870722095783555735 }, .{ 4437793518711847602, 1496577676626844588 },
1021 .{ 10928932444453298728, 1197262141301475670 }, .{ 17486291911125277965, 1915619426082361072 },
1022 .{ 6610335899416401726, 1532495540865888858 }, .{ 12666966349016942027, 1225996432692711086 },
1023 .{ 12888448528943286597, 1961594292308337738 }, .{ 17689456452638449924, 1569275433846670190 },
1024 .{ 14151565162110759939, 1255420347077336152 }, .{ 7885109000409574610, 2008672555323737844 },
1025 .{ 9997436015069570011, 1606938044258990275 }, .{ 7997948812055656009, 1285550435407192220 },
1026 .{ 12796718099289049614, 2056880696651507552 }, .{ 2858676849947419045, 1645504557321206042 },
1027 .{ 13354987924183666206, 1316403645856964833 }, .{ 17678631863951955605, 2106245833371143733 },
1028 .{ 3074859046935833515, 1684996666696914987 }, .{ 13527933681774397782, 1347997333357531989 },
1029 .{ 10576647446613305481, 2156795733372051183 }, .{ 15840015586774465031, 1725436586697640946 },
1030 .{ 8982663654677661702, 1380349269358112757 }, .{ 18061610662226169046, 2208558830972980411 },
1031 .{ 10759939715039024913, 1766847064778384329 }, .{ 12297300586773130254, 1413477651822707463 },
1032 .{ 15986332124095098083, 2261564242916331941 }, .{ 9099716884534168143, 1809251394333065553 },
1033 .{ 14658471137111155161, 1447401115466452442 }, .{ 4348079280205103483, 1157920892373161954 },
1034 .{ 14335624477811986218, 1852673427797059126 }, .{ 7779150767507678651, 1482138742237647301 },
1035 .{ 2533971799264232598, 1185710993790117841 }, .{ 15122401323048503126, 1897137590064188545 },
1036 .{ 12097921058438802501, 1517710072051350836 }, .{ 5988988032009131678, 1214168057641080669 },
1037 .{ 16961078480698431330, 1942668892225729070 }, .{ 13568862784558745064, 1554135113780583256 },
1038 .{ 7165741412905085728, 1243308091024466605 }, .{ 11465186260648137165, 1989292945639146568 },
1039 .{ 16550846638002330379, 1591434356511317254 }, .{ 16930026125143774626, 1273147485209053803 },
1040 .{ 4951948911778577463, 2037035976334486086 }, .{ 272210314680951647, 1629628781067588869 },
1041 .{ 3907117066486671641, 1303703024854071095 }, .{ 6251387306378674625, 2085924839766513752 },
1042 .{ 16069156289328670670, 1668739871813211001 }, .{ 9165976216721026213, 1334991897450568801 },
1043 .{ 7286864317269821294, 2135987035920910082 }, .{ 16897537898041588005, 1708789628736728065 },
1044 .{ 13518030318433270404, 1367031702989382452 }, .{ 6871453250525591353, 2187250724783011924 },
1045 .{ 9186511415162383406, 1749800579826409539 }, .{ 11038557946871817048, 1399840463861127631 },
1046 .{ 10282995085511086630, 2239744742177804210 }, .{ 8226396068408869304, 1791795793742243368 },
1047 .{ 13959814484210916090, 1433436634993794694 }, .{ 11267656730511734774, 2293498615990071511 },
1048 .{ 5324776569667477496, 1834798892792057209 }, .{ 7949170070475892320, 1467839114233645767 },
1049 .{ 17427382500606444826, 1174271291386916613 }, .{ 5747719112518849781, 1878834066219066582 },
1050 .{ 15666221734240810795, 1503067252975253265 }, .{ 12532977387392648636, 1202453802380202612 },
1051 .{ 5295368560860596524, 1923926083808324180 }, .{ 4236294848688477220, 1539140867046659344 },
1052 .{ 7078384693692692099, 1231312693637327475 }, .{ 11325415509908307358, 1970100309819723960 },
1053 .{ 9060332407926645887, 1576080247855779168 }, .{ 14626963555825137356, 1260864198284623334 },
1054 .{ 12335095245094488799, 2017382717255397335 }, .{ 9868076196075591040, 1613906173804317868 },
1055 .{ 15273158586344293478, 1291124939043454294 }, .{ 13369007293925138595, 2065799902469526871 },
1056 .{ 7005857020398200553, 1652639921975621497 }, .{ 16672732060544291412, 1322111937580497197 },
1057 .{ 11918976037903224966, 2115379100128795516 }, .{ 5845832015580669650, 1692303280103036413 },
1058 .{ 12055363241948356366, 1353842624082429130 }, .{ 841837113407818570, 2166148198531886609 },
1059 .{ 4362818505468165179, 1732918558825509287 }, .{ 14558301248600263113, 1386334847060407429 },
1060 .{ 12225235553534690011, 2218135755296651887 }, .{ 2401490813343931363, 1774508604237321510 },
1061 .{ 1921192650675145090, 1419606883389857208 }, .{ 17831303500047873437, 2271371013423771532 },
1062 .{ 6886345170554478103, 1817096810739017226 }, .{ 1819727321701672159, 1453677448591213781 },
1063 .{ 16213177116328979020, 1162941958872971024 }, .{ 14873036941900635463, 1860707134196753639 },
1064 .{ 15587778368262418694, 1488565707357402911 }, .{ 8780873879868024632, 1190852565885922329 },
1065 .{ 2981351763563108441, 1905364105417475727 }, .{ 13453127855076217722, 1524291284333980581 },
1066 .{ 7073153469319063855, 1219433027467184465 }, .{ 11317045550910502167, 1951092843947495144 },
1067 .{ 12742985255470312057, 1560874275157996115 }, .{ 10194388204376249646, 1248699420126396892 },
1068 .{ 1553625868034358140, 1997919072202235028 }, .{ 8621598323911307159, 1598335257761788022 },
1069 .{ 17965325103354776697, 1278668206209430417 }, .{ 13987124906400001422, 2045869129935088668 },
1070 .{ 121653480894270168, 1636695303948070935 }, .{ 97322784715416134, 1309356243158456748 },
1071 .{ 14913111714512307107, 2094969989053530796 }, .{ 8241140556867935363, 1675975991242824637 },
1072 .{ 17660958889720079260, 1340780792994259709 }, .{ 17189487779326395846, 2145249268790815535 },
1073 .{ 13751590223461116677, 1716199415032652428 }, .{ 18379969808252713988, 1372959532026121942 },
1074 .{ 14650556434236701088, 2196735251241795108 }, .{ 652398703163629901, 1757388200993436087 },
1075 .{ 11589965406756634890, 1405910560794748869 }, .{ 7475898206584884855, 2249456897271598191 },
1076 .{ 2291369750525997561, 1799565517817278553 }, .{ 9211793429904618695, 1439652414253822842 },
1077 .{ 18428218302589300235, 2303443862806116547 }, .{ 7363877012587619542, 1842755090244893238 },
1078 .{ 13269799239553916280, 1474204072195914590 }, .{ 10615839391643133024, 1179363257756731672 },
1079 .{ 2227947767661371545, 1886981212410770676 }, .{ 16539753473096738529, 1509584969928616540 },
1080 .{ 13231802778477390823, 1207667975942893232 }, .{ 6413489186596184024, 1932268761508629172 },
1081 .{ 16198837793502678189, 1545815009206903337 }, .{ 5580372605318321905, 1236652007365522670 },
1082 .{ 8928596168509315048, 1978643211784836272 }, .{ 18210923379033183008, 1582914569427869017 },
1083 .{ 7190041073742725760, 1266331655542295214 }, .{ 436019273762630246, 2026130648867672343 },
1084 .{ 7727513048493924843, 1620904519094137874 }, .{ 9871359253537050198, 1296723615275310299 },
1085 .{ 4726128361433549347, 2074757784440496479 }, .{ 7470251503888749801, 1659806227552397183 },
1086 .{ 13354898832594820487, 1327844982041917746 }, .{ 13989140502667892133, 2124551971267068394 },
1087 .{ 14880661216876224029, 1699641577013654715 }, .{ 11904528973500979224, 1359713261610923772 },
1088 .{ 4289851098633925465, 2175541218577478036 }, .{ 18189276137874781665, 1740432974861982428 },
1089 .{ 3483374466074094362, 1392346379889585943 }, .{ 1884050330976640656, 2227754207823337509 },
1090 .{ 5196589079523222848, 1782203366258670007 }, .{ 15225317707844309248, 1425762693006936005 },
1091 .{ 5913764258841343181, 2281220308811097609 }, .{ 8420360221814984868, 1824976247048878087 },
1092 .{ 17804334621677718864, 1459980997639102469 }, .{ 17932816512084085415, 1167984798111281975 },
1093 .{ 10245762345624985047, 1868775676978051161 }, .{ 4507261061758077715, 1495020541582440929 },
1094 .{ 7295157664148372495, 1196016433265952743 }, .{ 7982903447895485668, 1913626293225524389 },
1095 .{ 10075671573058298858, 1530901034580419511 }, .{ 4371188443704728763, 1224720827664335609 },
1096 .{ 14372599139411386667, 1959553324262936974 }, .{ 15187428126271019657, 1567642659410349579 },
1097 .{ 15839291315758726049, 1254114127528279663 }, .{ 3206773216762499739, 2006582604045247462 },
1098 .{ 13633465017635730761, 1605266083236197969 }, .{ 14596120828850494932, 1284212866588958375 },
1099 .{ 4907049252451240275, 2054740586542333401 }, .{ 236290587219081897, 1643792469233866721 },
1100 .{ 14946427728742906810, 1315033975387093376 }, .{ 16535586736504830250, 2104054360619349402 },
1101 .{ 5849771759720043554, 1683243488495479522 }, .{ 15747863852001765813, 1346594790796383617 },
1102 .{ 10439186904235184007, 2154551665274213788 }, .{ 15730047152871967852, 1723641332219371030 },
1103 .{ 12584037722297574282, 1378913065775496824 }, .{ 9066413911450387881, 2206260905240794919 },
1104 .{ 10942479943902220628, 1765008724192635935 }, .{ 8753983955121776503, 1412006979354108748 },
1105 .{ 10317025513452932081, 2259211166966573997 }, .{ 874922781278525018, 1807368933573259198 },
1106 .{ 8078635854506640661, 1445895146858607358 }, .{ 13841606313089133175, 1156716117486885886 },
1107 .{ 14767872471458792434, 1850745787979017418 }, .{ 746251532941302978, 1480596630383213935 },
1108 .{ 597001226353042382, 1184477304306571148 }, .{ 15712597221132509104, 1895163686890513836 },
1109 .{ 8880728962164096960, 1516130949512411069 }, .{ 10793931984473187891, 1212904759609928855 },
1110 .{ 17270291175157100626, 1940647615375886168 }, .{ 2748186495899949531, 1552518092300708935 },
1111 .{ 2198549196719959625, 1242014473840567148 }, .{ 18275073973719576693, 1987223158144907436 },
1112 .{ 10930710364233751031, 1589778526515925949 }, .{ 12433917106128911148, 1271822821212740759 },
1113 .{ 8826220925580526867, 2034916513940385215 }, .{ 7060976740464421494, 1627933211152308172 },
1114 .{ 16716827836597268165, 1302346568921846537 }, .{ 11989529279587987770, 2083754510274954460 },
1115 .{ 9591623423670390216, 1667003608219963568 }, .{ 15051996368420132820, 1333602886575970854 },
1116 .{ 13015147745246481542, 2133764618521553367 }, .{ 3033420566713364587, 1707011694817242694 },
1117 .{ 6116085268112601993, 1365609355853794155 }, .{ 9785736428980163188, 2184974969366070648 },
1118 .{ 15207286772667951197, 1747979975492856518 }, .{ 1097782973908629988, 1398383980394285215 },
1119 .{ 1756452758253807981, 2237414368630856344 }, .{ 5094511021344956708, 1789931494904685075 },
1120 .{ 4075608817075965366, 1431945195923748060 }, .{ 6520974107321544586, 2291112313477996896 },
1121 .{ 1527430471115325346, 1832889850782397517 }, .{ 12289990821117991246, 1466311880625918013 },
1122 .{ 17210690286378213644, 1173049504500734410 }, .{ 9090360384495590213, 1876879207201175057 },
1123 .{ 18340334751822203140, 1501503365760940045 }, .{ 14672267801457762512, 1201202692608752036 },
1124 .{ 16096930852848599373, 1921924308174003258 }, .{ 1809498238053148529, 1537539446539202607 },
1125 .{ 12515645034668249793, 1230031557231362085 }, .{ 1578287981759648052, 1968050491570179337 },
1126 .{ 12330676829633449412, 1574440393256143469 }, .{ 13553890278448669853, 1259552314604914775 },
1127 .{ 3239480371808320148, 2015283703367863641 }, .{ 17348979556414297411, 1612226962694290912 },
1128 .{ 6500486015647617283, 1289781570155432730 }, .{ 10400777625036187652, 2063650512248692368 },
1129 .{ 15699319729512770768, 1650920409798953894 }, .{ 16248804598352126938, 1320736327839163115 },
1130 .{ 7551343283653851484, 2113178124542660985 }, .{ 6041074626923081187, 1690542499634128788 },
1131 .{ 12211557331022285596, 1352433999707303030 }, .{ 1091747655926105338, 2163894399531684849 },
1132 .{ 4562746939482794594, 1731115519625347879 }, .{ 7339546366328145998, 1384892415700278303 },
1133 .{ 8053925371383123274, 2215827865120445285 }, .{ 6443140297106498619, 1772662292096356228 },
1134 .{ 12533209867169019542, 1418129833677084982 }, .{ 5295740528502789974, 2269007733883335972 },
1135 .{ 15304638867027962949, 1815206187106668777 }, .{ 4865013464138549713, 1452164949685335022 },
1136 .{ 14960057215536570740, 1161731959748268017 }, .{ 9178696285890871890, 1858771135597228828 },
1137 .{ 14721654658196518159, 1487016908477783062 }, .{ 4398626097073393881, 1189613526782226450 },
1138 .{ 7037801755317430209, 1903381642851562320 }, .{ 5630241404253944167, 1522705314281249856 },
1139 .{ 814844308661245011, 1218164251424999885 }, .{ 1303750893857992017, 1949062802279999816 },
1140 .{ 15800395974054034906, 1559250241823999852 }, .{ 5261619149759407279, 1247400193459199882 },
1141 .{ 12107939454356961969, 1995840309534719811 }, .{ 5997002748743659252, 1596672247627775849 },
1142 .{ 8486951013736837725, 1277337798102220679 }, .{ 2511075177753209390, 2043740476963553087 },
1143 .{ 13076906586428298482, 1634992381570842469 }, .{ 14150874083884549109, 1307993905256673975 },
1144 .{ 4194654460505726958, 2092790248410678361 }, .{ 18113118827372222859, 1674232198728542688 },
1145 .{ 3422448617672047318, 1339385758982834151 }, .{ 16543964232501006678, 2143017214372534641 },
1146 .{ 9545822571258895019, 1714413771498027713 }, .{ 15015355686490936662, 1371531017198422170 },
1147 .{ 5577825024675947042, 2194449627517475473 }, .{ 11840957649224578280, 1755559702013980378 },
1148 .{ 16851463748863483271, 1404447761611184302 }, .{ 12204946739213931940, 2247116418577894884 },
1149 .{ 13453306206113055875, 1797693134862315907 }, .{ 3383947335406624054, 1438154507889852726 },
1150 .{ 16482362180876329456, 2301047212623764361 }, .{ 9496540929959153242, 1840837770099011489 },
1151 .{ 11286581558709232917, 1472670216079209191 }, .{ 5339916432225476010, 1178136172863367353 },
1152 .{ 4854517476818851293, 1885017876581387765 }, .{ 3883613981455081034, 1508014301265110212 },
1153 .{ 14174937629389795797, 1206411441012088169 }, .{ 11611853762797942306, 1930258305619341071 },
1154 .{ 5600134195496443521, 1544206644495472857 }, .{ 15548153800622885787, 1235365315596378285 },
1155 .{ 6430302007287065643, 1976584504954205257 }, .{ 16212288050055383484, 1581267603963364205 },
1156 .{ 12969830440044306787, 1265014083170691364 }, .{ 9683682259845159889, 2024022533073106183 },
1157 .{ 15125643437359948558, 1619218026458484946 }, .{ 8411165935146048523, 1295374421166787957 },
1158 .{ 17147214310975587960, 2072599073866860731 }, .{ 10028422634038560045, 1658079259093488585 },
1159 .{ 8022738107230848036, 1326463407274790868 }, .{ 9147032156827446534, 2122341451639665389 },
1160 .{ 11006974540203867551, 1697873161311732311 }, .{ 5116230817421183718, 1358298529049385849 },
1161 .{ 15564666937357714594, 2173277646479017358 }, .{ 1383687105660440706, 1738622117183213887 },
1162 .{ 12174996128754083534, 1390897693746571109 }, .{ 8411947361780802685, 2225436309994513775 },
1163 .{ 6729557889424642148, 1780349047995611020 }, .{ 5383646311539713719, 1424279238396488816 },
1164 .{ 1235136468979721303, 2278846781434382106 }, .{ 15745504434151418335, 1823077425147505684 },
1165 .{ 16285752362063044992, 1458461940118004547 }, .{ 5649904260166615347, 1166769552094403638 },
1166 .{ 5350498001524674232, 1866831283351045821 }, .{ 591049586477829062, 1493465026680836657 },
1167 .{ 11540886113407994219, 1194772021344669325 }, .{ 18673707743239135, 1911635234151470921 },
1168 .{ 14772334225162232601, 1529308187321176736 }, .{ 8128518565387875758, 1223446549856941389 },
1169 .{ 1937583260394870242, 1957514479771106223 }, .{ 8928764237799716840, 1566011583816884978 },
1170 .{ 14521709019723594119, 1252809267053507982 }, .{ 8477339172590109297, 2004494827285612772 },
1171 .{ 17849917782297818407, 1603595861828490217 }, .{ 6901236596354434079, 1282876689462792174 },
1172 .{ 18420676183650915173, 2052602703140467478 }, .{ 3668494502695001169, 1642082162512373983 },
1173 .{ 10313493231639821582, 1313665730009899186 }, .{ 9122891541139893884, 2101865168015838698 },
1174 .{ 14677010862395735754, 1681492134412670958 }, .{ 673562245690857633, 1345193707530136767 }
1175};
1176
1177// zig fmt: off
1178//
1179// f128 small tables: 9072 bytes
1180
1181const FLOAT128_POW5_INV_BITCOUNT = 249;
1182const FLOAT128_POW5_BITCOUNT = 249;
1183const FLOAT128_POW5_TABLE_SIZE: comptime_int = FLOAT128_POW5_TABLE.len;
1184
1185const FLOAT128_POW5_TABLE: [56][2]u64 = .{
1186 .{ 1, 0 },
1187 .{ 5, 0 },
1188 .{ 25, 0 },
1189 .{ 125, 0 },
1190 .{ 625, 0 },
1191 .{ 3125, 0 },
1192 .{ 15625, 0 },
1193 .{ 78125, 0 },
1194 .{ 390625, 0 },
1195 .{ 1953125, 0 },
1196 .{ 9765625, 0 },
1197 .{ 48828125, 0 },
1198 .{ 244140625, 0 },
1199 .{ 1220703125, 0 },
1200 .{ 6103515625, 0 },
1201 .{ 30517578125, 0 },
1202 .{ 152587890625, 0 },
1203 .{ 762939453125, 0 },
1204 .{ 3814697265625, 0 },
1205 .{ 19073486328125, 0 },
1206 .{ 95367431640625, 0 },
1207 .{ 476837158203125, 0 },
1208 .{ 2384185791015625, 0 },
1209 .{ 11920928955078125, 0 },
1210 .{ 59604644775390625, 0 },
1211 .{ 298023223876953125, 0 },
1212 .{ 1490116119384765625, 0 },
1213 .{ 7450580596923828125, 0 },
1214 .{ 359414837200037393, 2 },
1215 .{ 1797074186000186965, 10 },
1216 .{ 8985370930000934825, 50 },
1217 .{ 8033366502585570893, 252 },
1218 .{ 3273344365508751233, 1262 },
1219 .{ 16366721827543756165, 6310 },
1220 .{ 8046632842880574361, 31554 },
1221 .{ 3339676066983768573, 157772 },
1222 .{ 16698380334918842865, 788860 },
1223 .{ 9704925379756007861, 3944304 },
1224 .{ 11631138751360936073, 19721522 },
1225 .{ 2815461535676025517, 98607613 },
1226 .{ 14077307678380127585, 493038065 },
1227 .{ 15046306170771983077, 2465190328 },
1228 .{ 1444554559021708921, 12325951644 },
1229 .{ 7222772795108544605, 61629758220 },
1230 .{ 17667119901833171409, 308148791101 },
1231 .{ 14548623214327650581, 1540743955509 },
1232 .{ 17402883850509598057, 7703719777548 },
1233 .{ 13227442957709783821, 38518598887744 },
1234 .{ 10796982567420264257, 192592994438723 },
1235 .{ 17091424689682218053, 962964972193617 },
1236 .{ 11670147153572883801, 4814824860968089 },
1237 .{ 3010503546735764157, 24074124304840448 },
1238 .{ 15052517733678820785, 120370621524202240 },
1239 .{ 1475612373555897461, 601853107621011204 },
1240 .{ 7378061867779487305, 3009265538105056020 },
1241 .{ 18443565265187884909, 15046327690525280101 },
1242};
1243
1244const FLOAT128_POW5_SPLIT: [89][4]u64 = .{
1245 .{ 0, 0, 0, 72057594037927936 },
1246 .{ 0, 5206161169240293376, 4575641699882439235, 73468396926392969 },
1247 .{ 3360510775605221349, 6983200512169538081, 4325643253124434363, 74906821675075173 },
1248 .{ 11917660854915489451, 9652941469841108803, 946308467778435600, 76373409087490117 },
1249 .{ 1994853395185689235, 16102657350889591545, 6847013871814915412, 77868710555449746 },
1250 .{ 958415760277438274, 15059347134713823592, 7329070255463483331, 79393288266368765 },
1251 .{ 2065144883315240188, 7145278325844925976, 14718454754511147343, 80947715414629833 },
1252 .{ 8980391188862868935, 13709057401304208685, 8230434828742694591, 82532576417087045 },
1253 .{ 432148644612782575, 7960151582448466064, 12056089168559840552, 84148467132788711 },
1254 .{ 484109300864744403, 15010663910730448582, 16824949663447227068, 85795995087002057 },
1255 .{ 14793711725276144220, 16494403799991899904, 10145107106505865967, 87475779699624060 },
1256 .{ 15427548291869817042, 12330588654550505203, 13980791795114552342, 89188452518064298 },
1257 .{ 9979404135116626552, 13477446383271537499, 14459862802511591337, 90934657454687378 },
1258 .{ 12385121150303452775, 9097130814231585614, 6523855782339765207, 92715051028904201 },
1259 .{ 1822931022538209743, 16062974719797586441, 3619180286173516788, 94530302614003091 },
1260 .{ 12318611738248470829, 13330752208259324507, 10986694768744162601, 96381094688813589 },
1261 .{ 13684493829640282333, 7674802078297225834, 15208116197624593182, 98268123094297527 },
1262 .{ 5408877057066295332, 6470124174091971006, 15112713923117703147, 100192097295163851 },
1263 .{ 11407083166564425062, 18189998238742408185, 4337638702446708282, 102153740646605557 },
1264 .{ 4112405898036935485, 924624216579956435, 14251108172073737125, 104153790666259019 },
1265 .{ 16996739107011444789, 10015944118339042475, 2395188869672266257, 106192999311487969 },
1266 .{ 4588314690421337879, 5339991768263654604, 15441007590670620066, 108272133262096356 },
1267 .{ 2286159977890359825, 14329706763185060248, 5980012964059367667, 110391974208576409 },
1268 .{ 9654767503237031099, 11293544302844823188, 11739932712678287805, 112553319146000238 },
1269 .{ 11362964448496095896, 7990659682315657680, 251480263940996374, 114756980673665505 },
1270 .{ 1423410421096377129, 14274395557581462179, 16553482793602208894, 117003787300607788 },
1271 .{ 2070444190619093137, 11517140404712147401, 11657844572835578076, 119294583757094535 },
1272 .{ 7648316884775828921, 15264332483297977688, 247182277434709002, 121630231312217685 },
1273 .{ 17410896758132241352, 10923914482914417070, 13976383996795783649, 124011608097704390 },
1274 .{ 9542674537907272703, 3079432708831728956, 14235189590642919676, 126439609438067572 },
1275 .{ 10364666969937261816, 8464573184892924210, 12758646866025101190, 128915148187220428 },
1276 .{ 14720354822146013883, 11480204489231511423, 7449876034836187038, 131439155071681461 },
1277 .{ 1692907053653558553, 17835392458598425233, 1754856712536736598, 134012579040499057 },
1278 .{ 5620591334531458755, 11361776175667106627, 13350215315297937856, 136636387622027174 },
1279 .{ 17455759733928092601, 10362573084069962561, 11246018728801810510, 139311567287686283 },
1280 .{ 2465404073814044982, 17694822665274381860, 1509954037718722697, 142039123822846312 },
1281 .{ 2152236053329638369, 11202280800589637091, 16388426812920420176, 72410041352485523 },
1282 .{ 17319024055671609028, 10944982848661280484, 2457150158022562661, 73827744744583080 },
1283 .{ 17511219308535248024, 5122059497846768077, 2089605804219668451, 75273205100637900 },
1284 .{ 10082673333144031533, 14429008783411894887, 12842832230171903890, 76746965869337783 },
1285 .{ 16196653406315961184, 10260180891682904501, 10537411930446752461, 78249581139456266 },
1286 .{ 15084422041749743389, 234835370106753111, 16662517110286225617, 79781615848172976 },
1287 .{ 8199644021067702606, 3787318116274991885, 7438130039325743106, 81343645993472659 },
1288 .{ 12039493937039359765, 9773822153580393709, 5945428874398357806, 82936258850702722 },
1289 .{ 984543865091303961, 7975107621689454830, 6556665988501773347, 84560053193370726 },
1290 .{ 9633317878125234244, 16099592426808915028, 9706674539190598200, 86215639518264828 },
1291 .{ 6860695058870476186, 4471839111886709592, 7828342285492709568, 87903640274981819 },
1292 .{ 14583324717644598331, 4496120889473451238, 5290040788305728466, 89624690099949049 },
1293 .{ 18093669366515003715, 12879506572606942994, 18005739787089675377, 91379436055028227 },
1294 .{ 17997493966862379937, 14646222655265145582, 10265023312844161858, 93168537870790806 },
1295 .{ 12283848109039722318, 11290258077250314935, 9878160025624946825, 94992668194556404 },
1296 .{ 8087752761883078164, 5262596608437575693, 11093553063763274413, 96852512843287537 },
1297 .{ 15027787746776840781, 12250273651168257752, 9290470558712181914, 98748771061435726 },
1298 .{ 15003915578366724489, 2937334162439764327, 5404085603526796602, 100682155783835929 },
1299 .{ 5225610465224746757, 14932114897406142027, 2774647558180708010, 102653393903748137 },
1300 .{ 17112957703385190360, 12069082008339002412, 3901112447086388439, 104663226546146909 },
1301 .{ 4062324464323300238, 3992768146772240329, 15757196565593695724, 106712409346361594 },
1302 .{ 5525364615810306701, 11855206026704935156, 11344868740897365300, 108801712734172003 },
1303 .{ 9274143661888462646, 4478365862348432381, 18010077872551661771, 110931922223466333 },
1304 .{ 12604141221930060148, 8930937759942591500, 9382183116147201338, 113103838707570263 },
1305 .{ 14513929377491886653, 1410646149696279084, 587092196850797612, 115318278760358235 },
1306 .{ 2226851524999454362, 7717102471110805679, 7187441550995571734, 117576074943260147 },
1307 .{ 5527526061344932763, 2347100676188369132, 16976241418824030445, 119878076118278875 },
1308 .{ 6088479778147221611, 17669593130014777580, 10991124207197663546, 122225147767136307 },
1309 .{ 11107734086759692041, 3391795220306863431, 17233960908859089158, 124618172316667879 },
1310 .{ 7913172514655155198, 17726879005381242552, 641069866244011540, 127058049470587962 },
1311 .{ 12596991768458713949, 15714785522479904446, 6035972567136116512, 129545696547750811 },
1312 .{ 16901996933781815980, 4275085211437148707, 14091642539965169063, 132082048827034281 },
1313 .{ 7524574627987869240, 15661204384239316051, 2444526454225712267, 134668059898975949 },
1314 .{ 8199251625090479942, 6803282222165044067, 16064817666437851504, 137304702024293857 },
1315 .{ 4453256673338111920, 15269922543084434181, 3139961729834750852, 139992966499426682 },
1316 .{ 15841763546372731299, 3013174075437671812, 4383755396295695606, 142733864029230733 },
1317 .{ 9771896230907310329, 4900659362437687569, 12386126719044266361, 72764212553486967 },
1318 .{ 9420455527449565190, 1859606122611023693, 6555040298902684281, 74188850200884818 },
1319 .{ 5146105983135678095, 2287300449992174951, 4325371679080264751, 75641380576797959 },
1320 .{ 11019359372592553360, 8422686425957443718, 7175176077944048210, 77122349788024458 },
1321 .{ 11005742969399620716, 4132174559240043701, 9372258443096612118, 78632314633490790 },
1322 .{ 8887589641394725840, 8029899502466543662, 14582206497241572853, 80171842813591127 },
1323 .{ 360247523705545899, 12568341805293354211, 14653258284762517866, 81741513143625247 },
1324 .{ 12314272731984275834, 4740745023227177044, 6141631472368337539, 83341915771415304 },
1325 .{ 441052047733984759, 7940090120939869826, 11750200619921094248, 84973652399183278 },
1326 .{ 3436657868127012749, 9187006432149937667, 16389726097323041290, 86637336509772529 },
1327 .{ 13490220260784534044, 15339072891382896702, 8846102360835316895, 88333593597298497 },
1328 .{ 4125672032094859833, 158347675704003277, 10592598512749774447, 90063061402315272 },
1329 .{ 12189928252974395775, 2386931199439295891, 7009030566469913276, 91826390151586454 },
1330 .{ 9256479608339282969, 2844900158963599229, 11148388908923225596, 93624242802550437 },
1331 .{ 11584393507658707408, 2863659090805147914, 9873421561981063551, 95457295292572042 },
1332 .{ 13984297296943171390, 1931468383973130608, 12905719743235082319, 97326236793074198 },
1333 .{ 5837045222254987499, 10213498696735864176, 14893951506257020749, 99231769968645227 },
1334};
1335
1336// Unfortunately, the results are sometimes off by one or two. We use an additional
1337// lookup table to store those cases and adjust the result.
1338const FLOAT128_POW5_ERRORS: [156]u64 = .{
1339 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x9555596400000000,
1340 0x65a6569525565555, 0x4415551445449655, 0x5105015504144541, 0x65a69969a6965964,
1341 0x5054955969959656, 0x5105154515554145, 0x4055511051591555, 0x5500514455550115,
1342 0x0041140014145515, 0x1005440545511051, 0x0014405450411004, 0x0414440010500000,
1343 0x0044000440010040, 0x5551155000004001, 0x4554555454544114, 0x5150045544005441,
1344 0x0001111400054501, 0x6550955555554554, 0x1504159645559559, 0x4105055141454545,
1345 0x1411541410405454, 0x0415555044545555, 0x0014154115405550, 0x1540055040411445,
1346 0x0000000500000000, 0x5644000000000000, 0x1155555591596555, 0x0410440054569565,
1347 0x5145100010010005, 0x0555041405500150, 0x4141450455140450, 0x0000000144000140,
1348 0x5114004001105410, 0x4444100404005504, 0x0414014410001015, 0x5145055155555015,
1349 0x0141041444445540, 0x0000100451541414, 0x4105041104155550, 0x0500501150451145,
1350 0x1001050000004114, 0x5551504400141045, 0x5110545410151454, 0x0100001400004040,
1351 0x5040010111040000, 0x0140000150541100, 0x4400140400104110, 0x5011014405545004,
1352 0x0000000044155440, 0x0000000010000000, 0x1100401444440001, 0x0040401010055111,
1353 0x5155155551405454, 0x0444440015514411, 0x0054505054014101, 0x0451015441115511,
1354 0x1541411401140551, 0x4155104514445110, 0x4141145450145515, 0x5451445055155050,
1355 0x4400515554110054, 0x5111145104501151, 0x565a655455500501, 0x5565555555525955,
1356 0x0550511500405695, 0x4415504051054544, 0x6555595965555554, 0x0100915915555655,
1357 0x5540001510001001, 0x5450051414000544, 0x1405010555555551, 0x5555515555644155,
1358 0x5555055595496555, 0x5451045004415000, 0x5450510144040144, 0x5554155555556455,
1359 0x5051555495415555, 0x5555554555555545, 0x0000000010005455, 0x4000005000040000,
1360 0x5565555555555954, 0x5554559555555505, 0x9645545495552555, 0x4000400055955564,
1361 0x0040000000000001, 0x4004100100000000, 0x5540040440000411, 0x4565555955545644,
1362 0x1140659549651556, 0x0100000410010000, 0x5555515400004001, 0x5955545555155255,
1363 0x5151055545505556, 0x5051454510554515, 0x0501500050415554, 0x5044154005441005,
1364 0x1455445450550455, 0x0010144055144545, 0x0000401100000004, 0x1050145050000010,
1365 0x0415004554011540, 0x1000510100151150, 0x0100040400001144, 0x0000000000000000,
1366 0x0550004400000100, 0x0151145041451151, 0x0000400400005450, 0x0000100044010004,
1367 0x0100054100050040, 0x0504400005410010, 0x4011410445500105, 0x0000404000144411,
1368 0x0101504404500000, 0x0000005044400400, 0x0000000014000100, 0x0404440414000000,
1369 0x5554100410000140, 0x4555455544505555, 0x5454105055455455, 0x0115454155454015,
1370 0x4404110000045100, 0x4400001100101501, 0x6596955956966a94, 0x0040655955665965,
1371 0x5554144400100155, 0xa549495401011041, 0x5596555565955555, 0x5569965959549555,
1372 0x969565a655555456, 0x0000001000000000, 0x0000000040000140, 0x0000040100000000,
1373 0x1415454400000000, 0x5410415411454114, 0x0400040104000154, 0x0504045000000411,
1374 0x0000001000000010, 0x5554000000001040, 0x5549155551556595, 0x1455541055515555,
1375 0x0510555454554541, 0x9555555555540455, 0x6455456555556465, 0x4524565555654514,
1376 0x5554655255559545, 0x9555455441155556, 0x0000000051515555, 0x0010005040000550,
1377 0x5044044040000000, 0x1045040440010500, 0x0000400000040000, 0x0000000000000000,
1378};
1379
1380const FLOAT128_POW5_INV_SPLIT: [89][4]u64 = .{
1381 .{ 0, 0, 0, 144115188075855872 },
1382 .{ 1573859546583440065, 2691002611772552616, 6763753280790178510, 141347765182270746 },
1383 .{ 12960290449513840412, 12345512957918226762, 18057899791198622765, 138633484706040742 },
1384 .{ 7615871757716765416, 9507132263365501332, 4879801712092008245, 135971326161092377 },
1385 .{ 7869961150745287587, 5804035291554591636, 8883897266325833928, 133360288657597085 },
1386 .{ 2942118023529634767, 15128191429820565086, 10638459445243230718, 130799390525667397 },
1387 .{ 14188759758411913794, 5362791266439207815, 8068821289119264054, 128287668946279217 },
1388 .{ 7183196927902545212, 1952291723540117099, 12075928209936341512, 125824179589281448 },
1389 .{ 5672588001402349748, 17892323620748423487, 9874578446960390364, 123407996258356868 },
1390 .{ 4442590541217566325, 4558254706293456445, 10343828952663182727, 121038210542800766 },
1391 .{ 3005560928406962566, 2082271027139057888, 13961184524927245081, 118713931475986426 },
1392 .{ 13299058168408384786, 17834349496131278595, 9029906103900731664, 116434285200389047 },
1393 .{ 5414878118283973035, 13079825470227392078, 17897304791683760280, 114198414639042157 },
1394 .{ 14609755883382484834, 14991702445765844156, 3269802549772755411, 112005479173303009 },
1395 .{ 15967774957605076027, 2511532636717499923, 16221038267832563171, 109854654326805788 },
1396 .{ 9269330061621627145, 3332501053426257392, 16223281189403734630, 107745131455483836 },
1397 .{ 16739559299223642282, 1873986623300664530, 6546709159471442872, 105676117443544318 },
1398 .{ 17116435360051202055, 1359075105581853924, 2038341371621886470, 103646834405281051 },
1399 .{ 17144715798009627550, 3201623802661132408, 9757551605154622431, 101656519392613377 },
1400 .{ 17580479792687825857, 6546633380567327312, 15099972427870912398, 99704424108241124 },
1401 .{ 9726477118325522902, 14578369026754005435, 11728055595254428803, 97789814624307808 },
1402 .{ 134593949518343635, 5715151379816901985, 1660163707976377376, 95911971106466306 },
1403 .{ 5515914027713859358, 7124354893273815720, 5548463282858794077, 94070187543243255 },
1404 .{ 6188403395862945512, 5681264392632320838, 15417410852121406654, 92263771480600430 },
1405 .{ 15908890877468271457, 10398888261125597540, 4817794962769172309, 90492043761593298 },
1406 .{ 1413077535082201005, 12675058125384151580, 7731426132303759597, 88754338271028867 },
1407 .{ 1486733163972670293, 11369385300195092554, 11610016711694864110, 87050001685026843 },
1408 .{ 8788596583757589684, 3978580923851924802, 9255162428306775812, 85378393225389919 },
1409 .{ 7203518319660962120, 15044736224407683725, 2488132019818199792, 83738884418690858 },
1410 .{ 4004175967662388707, 18236988667757575407, 15613100370957482671, 82130858859985791 },
1411 .{ 18371903370586036463, 53497579022921640, 16465963977267203307, 80553711981064899 },
1412 .{ 10170778323887491315, 1999668801648976001, 10209763593579456445, 79006850823153334 },
1413 .{ 17108131712433974546, 16825784443029944237, 2078700786753338945, 77489693813976938 },
1414 .{ 17221789422665858532, 12145427517550446164, 5391414622238668005, 76001670549108934 },
1415 .{ 4859588996898795878, 1715798948121313204, 3950858167455137171, 74542221577515387 },
1416 .{ 13513469241795711526, 631367850494860526, 10517278915021816160, 73110798191218799 },
1417 .{ 11757513142672073111, 2581974932255022228, 17498959383193606459, 143413724438001539 },
1418 .{ 14524355192525042817, 5640643347559376447, 1309659274756813016, 140659771648132296 },
1419 .{ 2765095348461978538, 11021111021896007722, 3224303603779962366, 137958702611185230 },
1420 .{ 12373410389187981037, 13679193545685856195, 11644609038462631561, 135309501808182158 },
1421 .{ 12813176257562780151, 3754199046160268020, 9954691079802960722, 132711173221007413 },
1422 .{ 17557452279667723458, 3237799193992485824, 17893947919029030695, 130162739957935629 },
1423 .{ 14634200999559435155, 4123869946105211004, 6955301747350769239, 127663243886350468 },
1424 .{ 2185352760627740240, 2864813346878886844, 13049218671329690184, 125211745272516185 },
1425 .{ 6143438674322183002, 10464733336980678750, 6982925169933978309, 122807322428266620 },
1426 .{ 1099509117817174576, 10202656147550524081, 754997032816608484, 120449071364478757 },
1427 .{ 2410631293559367023, 17407273750261453804, 15307291918933463037, 118136105451200587 },
1428 .{ 12224968375134586697, 1664436604907828062, 11506086230137787358, 115867555084305488 },
1429 .{ 3495926216898000888, 18392536965197424288, 10992889188570643156, 113642567358547782 },
1430 .{ 8744506286256259680, 3966568369496879937, 18342264969761820037, 111460305746896569 },
1431 .{ 7689600520560455039, 5254331190877624630, 9628558080573245556, 109319949786027263 },
1432 .{ 11862637625618819436, 3456120362318976488, 14690471063106001082, 107220694767852583 },
1433 .{ 5697330450030126444, 12424082405392918899, 358204170751754904, 105161751436977040 },
1434 .{ 11257457505097373622, 15373192700214208870, 671619062372033814, 103142345693961148 },
1435 .{ 16850355018477166700, 1913910419361963966, 4550257919755970531, 101161718304283822 },
1436 .{ 9670835567561997011, 10584031339132130638, 3060560222974851757, 99219124612893520 },
1437 .{ 7698686577353054710, 11689292838639130817, 11806331021588878241, 97313834264240819 },
1438 .{ 12233569599615692137, 3347791226108469959, 10333904326094451110, 95445130927687169 },
1439 .{ 13049400362825383933, 17142621313007799680, 3790542585289224168, 93612312028186576 },
1440 .{ 12430457242474442072, 5625077542189557960, 14765055286236672238, 91814688482138969 },
1441 .{ 4759444137752473128, 2230562561567025078, 4954443037339580076, 90051584438315940 },
1442 .{ 7246913525170274758, 8910297835195760709, 4015904029508858381, 88322337023761438 },
1443 .{ 12854430245836432067, 8135139748065431455, 11548083631386317976, 86626296094571907 },
1444 .{ 4848827254502687803, 4789491250196085625, 3988192420450664125, 84962823991462151 },
1445 .{ 7435538409611286684, 904061756819742353, 14598026519493048444, 83331295300025028 },
1446 .{ 11042616160352530997, 8948390828345326218, 10052651191118271927, 81731096615594853 },
1447 .{ 11059348291563778943, 11696515766184685544, 3783210511290897367, 80161626312626082 },
1448 .{ 7020010856491885826, 5025093219346041680, 8960210401638911765, 78622294318500592 },
1449 .{ 17732844474490699984, 7820866704994446502, 6088373186798844243, 77112521891678506 },
1450 .{ 688278527545590501, 3045610706602776618, 8684243536999567610, 75631741404109150 },
1451 .{ 2734573255120657297, 3903146411440697663, 9470794821691856713, 74179396127820347 },
1452 .{ 15996457521023071259, 4776627823451271680, 12394856457265744744, 72754940025605801 },
1453 .{ 13492065758834518331, 7390517611012222399, 1630485387832860230, 142715675091463768 },
1454 .{ 13665021627282055864, 9897834675523659302, 17907668136755296849, 139975126841173266 },
1455 .{ 9603773719399446181, 10771916301484339398, 10672699855989487527, 137287204938390542 },
1456 .{ 3630218541553511265, 8139010004241080614, 2876479648932814543, 134650898807055963 },
1457 .{ 8318835909686377084, 9525369258927993371, 2796120270400437057, 132065217277054270 },
1458 .{ 11190003059043290163, 12424345635599592110, 12539346395388933763, 129529188211565064 },
1459 .{ 8701968833973242276, 820569587086330727, 2315591597351480110, 127041858141569228 },
1460 .{ 5115113890115690487, 16906305245394587826, 9899749468931071388, 124602291907373862 },
1461 .{ 15543535488939245974, 10945189844466391399, 3553863472349432246, 122209572307020975 },
1462 .{ 7709257252608325038, 1191832167690640880, 15077137020234258537, 119862799751447719 },
1463 .{ 7541333244210021737, 9790054727902174575, 5160944773155322014, 117561091926268545 },
1464 .{ 12297384708782857832, 1281328873123467374, 4827925254630475769, 115303583460052092 },
1465 .{ 13243237906232367265, 15873887428139547641, 3607993172301799599, 113089425598968120 },
1466 .{ 11384616453739611114, 15184114243769211033, 13148448124803481057, 110917785887682141 },
1467 .{ 17727970963596660683, 1196965221832671990, 14537830463956404138, 108787847856377790 },
1468 .{ 17241367586707330931, 8880584684128262874, 11173506540726547818, 106698810713789254 },
1469 .{ 7184427196661305643, 14332510582433188173, 14230167953789677901, 104649889046128358 },
1470};
1471
1472const FLOAT128_POW5_INV_ERRORS: [154]u64 = .{
1473 0x1144155514145504, 0x0000541555401141, 0x0000000000000000, 0x0154454000000000,
1474 0x4114105515544440, 0x0001001111500415, 0x4041411410011000, 0x5550114515155014,
1475 0x1404100041554551, 0x0515000450404410, 0x5054544401140004, 0x5155501005555105,
1476 0x1144141000105515, 0x0541500000500000, 0x1104105540444140, 0x4000015055514110,
1477 0x0054010450004005, 0x4155515404100005, 0x5155145045155555, 0x1511555515440558,
1478 0x5558544555515555, 0x0000000000000010, 0x5004000000000050, 0x1415510100000010,
1479 0x4545555444514500, 0x5155151555555551, 0x1441540144044554, 0x5150104045544400,
1480 0x5450545401444040, 0x5554455045501400, 0x4655155555555145, 0x1000010055455055,
1481 0x1000004000055004, 0x4455405104000005, 0x4500114504150545, 0x0000000014000000,
1482 0x5450000000000000, 0x5514551511445555, 0x4111501040555451, 0x4515445500054444,
1483 0x5101500104100441, 0x1545115155545055, 0x0000000000000000, 0x1554000000100000,
1484 0x5555545595551555, 0x5555051851455955, 0x5555555555555559, 0x0000400011001555,
1485 0x0000004400040000, 0x5455511555554554, 0x5614555544115445, 0x6455156145555155,
1486 0x5455855455415455, 0x5515555144555545, 0x0114400000145155, 0x0000051000450511,
1487 0x4455154554445100, 0x4554150141544455, 0x65955555559a5965, 0x5555555854559559,
1488 0x9569654559616595, 0x1040044040005565, 0x1010010500011044, 0x1554015545154540,
1489 0x4440555401545441, 0x1014441450550105, 0x4545400410504145, 0x5015111541040151,
1490 0x5145051154000410, 0x1040001044545044, 0x4001400000151410, 0x0540000044040000,
1491 0x0510555454411544, 0x0400054054141550, 0x1001041145001100, 0x0000000140000000,
1492 0x0000000014100000, 0x1544005454000140, 0x4050055505445145, 0x0011511104504155,
1493 0x5505544415045055, 0x1155154445515554, 0x0000000000004555, 0x0000000000000000,
1494 0x5101010510400004, 0x1514045044440400, 0x5515519555515555, 0x4554545441555545,
1495 0x1551055955551515, 0x0150000011505515, 0x0044005040400000, 0x0004001004010050,
1496 0x0000051004450414, 0x0114001101001144, 0x0401000001000001, 0x4500010001000401,
1497 0x0004100000005000, 0x0105000441101100, 0x0455455550454540, 0x5404050144105505,
1498 0x4101510540555455, 0x1055541411451555, 0x5451445110115505, 0x1154110010101545,
1499 0x1145140450054055, 0x5555565415551554, 0x1550559555555555, 0x5555541545045141,
1500 0x4555455450500100, 0x5510454545554555, 0x1510140115045455, 0x1001050040111510,
1501 0x5555454555555504, 0x9954155545515554, 0x6596656555555555, 0x0140410051555559,
1502 0x0011104010001544, 0x965669659a680501, 0x5655a55955556955, 0x4015111014404514,
1503 0x1414155554505145, 0x0540040011051404, 0x1010000000015005, 0x0010054050004410,
1504 0x5041104014000100, 0x4440010500100001, 0x1155510504545554, 0x0450151545115541,
1505 0x4000100400110440, 0x1004440010514440, 0x0000115050450000, 0x0545404455541500,
1506 0x1051051555505101, 0x5505144554544144, 0x4550545555515550, 0x0015400450045445,
1507 0x4514155400554415, 0x4555055051050151, 0x1511441450001014, 0x4544554510404414,
1508 0x4115115545545450, 0x5500541555551555, 0x5550010544155015, 0x0144414045545500,
1509 0x4154050001050150, 0x5550511111000145, 0x1114504055000151, 0x5104041101451040,
1510 0x0010501401051441, 0x0010501450504401, 0x4554585440044444, 0x5155555951450455,
1511 0x0040000400105555, 0x0000000000000001,
1512};
1513
1514// zig fmt: on
1515
1516const builtin = @import("builtin");
1517
1518fn check(comptime T: type, value: T, comptime expected: []const u8) !void {
1519 const I = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
1520
1521 var buf: [6000]u8 = undefined;
1522 const value_bits: I = @bitCast(value);
1523 const s = try formatFloat(&buf, value, .{});
1524 try std.testing.expectEqualStrings(expected, s);
1525
1526 if (T == f80 and builtin.target.os.tag == .windows and builtin.target.cpu.arch == .x86_64) return;
1527
1528 const o = try std.fmt.parseFloat(T, s);
1529 const o_bits: I = @bitCast(o);
1530
1531 if (std.math.isNan(value)) {
1532 try std.testing.expect(std.math.isNan(o));
1533 } else {
1534 try std.testing.expectEqual(value_bits, o_bits);
1535 }
1536}
1537
1538test "format f32" {
1539 try check(f32, 0.0, "0e0");
1540 try check(f32, -0.0, "-0e0");
1541 try check(f32, 1.0, "1e0");
1542 try check(f32, -1.0, "-1e0");
1543 try check(f32, std.math.nan(f32), "nan");
1544 try check(f32, std.math.inf(f32), "inf");
1545 try check(f32, -std.math.inf(f32), "-inf");
1546 try check(f32, 1.1754944e-38, "1.1754944e-38");
1547 try check(f32, @bitCast(@as(u32, 0x7f7fffff)), "3.4028235e38");
1548 try check(f32, @bitCast(@as(u32, 1)), "1e-45");
1549 try check(f32, 3.355445E7, "3.355445e7");
1550 try check(f32, 8.999999e9, "9e9");
1551 try check(f32, 3.4366717e10, "3.436672e10");
1552 try check(f32, 3.0540412e5, "3.0540412e5");
1553 try check(f32, 8.0990312e3, "8.0990312e3");
1554 try check(f32, 2.4414062e-4, "2.4414062e-4");
1555 try check(f32, 2.4414062e-3, "2.4414062e-3");
1556 try check(f32, 4.3945312e-3, "4.3945312e-3");
1557 try check(f32, 6.3476562e-3, "6.3476562e-3");
1558 try check(f32, 4.7223665e21, "4.7223665e21");
1559 try check(f32, 8388608.0, "8.388608e6");
1560 try check(f32, 1.6777216e7, "1.6777216e7");
1561 try check(f32, 3.3554436e7, "3.3554436e7");
1562 try check(f32, 6.7131496e7, "6.7131496e7");
1563 try check(f32, 1.9310392e-38, "1.9310392e-38");
1564 try check(f32, -2.47e-43, "-2.47e-43");
1565 try check(f32, 1.993244e-38, "1.993244e-38");
1566 try check(f32, 4103.9003, "4.1039004e3");
1567 try check(f32, 5.3399997e9, "5.3399997e9");
1568 try check(f32, 6.0898e-39, "6.0898e-39");
1569 try check(f32, 0.0010310042, "1.0310042e-3");
1570 try check(f32, 2.8823261e17, "2.882326e17");
1571 try check(f32, 7.038531e-26, "7.038531e-26");
1572 try check(f32, 9.2234038e17, "9.223404e17");
1573 try check(f32, 6.7108872e7, "6.710887e7");
1574 try check(f32, 1.0e-44, "1e-44");
1575 try check(f32, 2.816025e14, "2.816025e14");
1576 try check(f32, 9.223372e18, "9.223372e18");
1577 try check(f32, 1.5846085e29, "1.5846086e29");
1578 try check(f32, 1.1811161e19, "1.1811161e19");
1579 try check(f32, 5.368709e18, "5.368709e18");
1580 try check(f32, 4.6143165e18, "4.6143166e18");
1581 try check(f32, 0.007812537, "7.812537e-3");
1582 try check(f32, 1.4e-45, "1e-45");
1583 try check(f32, 1.18697724e20, "1.18697725e20");
1584 try check(f32, 1.00014165e-36, "1.00014165e-36");
1585 try check(f32, 200.0, "2e2");
1586 try check(f32, 3.3554432e7, "3.3554432e7");
1587
1588 try check(f32, 1.0, "1e0");
1589 try check(f32, 1.2, "1.2e0");
1590 try check(f32, 1.23, "1.23e0");
1591 try check(f32, 1.234, "1.234e0");
1592 try check(f32, 1.2345, "1.2345e0");
1593 try check(f32, 1.23456, "1.23456e0");
1594 try check(f32, 1.234567, "1.234567e0");
1595 try check(f32, 1.2345678, "1.2345678e0");
1596 try check(f32, 1.23456735e-36, "1.23456735e-36");
1597}
1598
1599test "format f64" {
1600 try check(f64, 0.0, "0e0");
1601 try check(f64, -0.0, "-0e0");
1602 try check(f64, 1.0, "1e0");
1603 try check(f64, -1.0, "-1e0");
1604 try check(f64, std.math.nan(f64), "nan");
1605 try check(f64, std.math.inf(f64), "inf");
1606 try check(f64, -std.math.inf(f64), "-inf");
1607 try check(f64, 2.2250738585072014e-308, "2.2250738585072014e-308");
1608 try check(f64, @bitCast(@as(u64, 0x7fefffffffffffff)), "1.7976931348623157e308");
1609 try check(f64, @bitCast(@as(u64, 1)), "5e-324");
1610 try check(f64, 2.98023223876953125e-8, "2.9802322387695312e-8");
1611 try check(f64, -2.109808898695963e16, "-2.109808898695963e16");
1612 try check(f64, 4.940656e-318, "4.940656e-318");
1613 try check(f64, 1.18575755e-316, "1.18575755e-316");
1614 try check(f64, 2.989102097996e-312, "2.989102097996e-312");
1615 try check(f64, 9.0608011534336e15, "9.0608011534336e15");
1616 try check(f64, 4.708356024711512e18, "4.708356024711512e18");
1617 try check(f64, 9.409340012568248e18, "9.409340012568248e18");
1618 try check(f64, 1.2345678, "1.2345678e0");
1619 try check(f64, @bitCast(@as(u64, 0x4830f0cf064dd592)), "5.764607523034235e39");
1620 try check(f64, @bitCast(@as(u64, 0x4840f0cf064dd592)), "1.152921504606847e40");
1621 try check(f64, @bitCast(@as(u64, 0x4850f0cf064dd592)), "2.305843009213694e40");
1622
1623 try check(f64, 1, "1e0");
1624 try check(f64, 1.2, "1.2e0");
1625 try check(f64, 1.23, "1.23e0");
1626 try check(f64, 1.234, "1.234e0");
1627 try check(f64, 1.2345, "1.2345e0");
1628 try check(f64, 1.23456, "1.23456e0");
1629 try check(f64, 1.234567, "1.234567e0");
1630 try check(f64, 1.2345678, "1.2345678e0");
1631 try check(f64, 1.23456789, "1.23456789e0");
1632 try check(f64, 1.234567895, "1.234567895e0");
1633 try check(f64, 1.2345678901, "1.2345678901e0");
1634 try check(f64, 1.23456789012, "1.23456789012e0");
1635 try check(f64, 1.234567890123, "1.234567890123e0");
1636 try check(f64, 1.2345678901234, "1.2345678901234e0");
1637 try check(f64, 1.23456789012345, "1.23456789012345e0");
1638 try check(f64, 1.234567890123456, "1.234567890123456e0");
1639 try check(f64, 1.2345678901234567, "1.2345678901234567e0");
1640
1641 try check(f64, 4.294967294, "4.294967294e0");
1642 try check(f64, 4.294967295, "4.294967295e0");
1643 try check(f64, 4.294967296, "4.294967296e0");
1644 try check(f64, 4.294967297, "4.294967297e0");
1645 try check(f64, 4.294967298, "4.294967298e0");
1646}
1647
1648test "format f80" {
1649 try check(f80, 0.0, "0e0");
1650 try check(f80, -0.0, "-0e0");
1651 try check(f80, 1.0, "1e0");
1652 try check(f80, -1.0, "-1e0");
1653 try check(f80, std.math.nan(f80), "nan");
1654 try check(f80, std.math.inf(f80), "inf");
1655 try check(f80, -std.math.inf(f80), "-inf");
1656
1657 try check(f80, 2.2250738585072014e-308, "2.2250738585072014e-308");
1658 try check(f80, 2.98023223876953125e-8, "2.98023223876953125e-8");
1659 try check(f80, -2.109808898695963e16, "-2.109808898695963e16");
1660 try check(f80, 4.940656e-318, "4.940656e-318");
1661 try check(f80, 1.18575755e-316, "1.18575755e-316");
1662 try check(f80, 2.989102097996e-312, "2.989102097996e-312");
1663 try check(f80, 9.0608011534336e15, "9.0608011534336e15");
1664 try check(f80, 4.708356024711512e18, "4.708356024711512e18");
1665 try check(f80, 9.409340012568248e18, "9.409340012568248e18");
1666 try check(f80, 1.2345678, "1.2345678e0");
1667}
1668
1669test "format f128" {
1670 try check(f128, 0.0, "0e0");
1671 try check(f128, -0.0, "-0e0");
1672 try check(f128, 1.0, "1e0");
1673 try check(f128, -1.0, "-1e0");
1674 try check(f128, std.math.nan(f128), "nan");
1675 try check(f128, std.math.inf(f128), "inf");
1676 try check(f128, -std.math.inf(f128), "-inf");
1677
1678 try check(f128, 2.2250738585072014e-308, "2.2250738585072014e-308");
1679 try check(f128, 2.98023223876953125e-8, "2.98023223876953125e-8");
1680 try check(f128, -2.109808898695963e16, "-2.109808898695963e16");
1681 try check(f128, 4.940656e-318, "4.940656e-318");
1682 try check(f128, 1.18575755e-316, "1.18575755e-316");
1683 try check(f128, 2.989102097996e-312, "2.989102097996e-312");
1684 try check(f128, 9.0608011534336e15, "9.0608011534336e15");
1685 try check(f128, 4.708356024711512e18, "4.708356024711512e18");
1686 try check(f128, 9.409340012568248e18, "9.409340012568248e18");
1687 try check(f128, 1.2345678, "1.2345678e0");
1688}
1689
1690test "format float to decimal with zero precision" {
1691 try expectFmt("5", "{d:.0}", .{5});
1692 try expectFmt("6", "{d:.0}", .{6});
1693 try expectFmt("7", "{d:.0}", .{7});
1694 try expectFmt("8", "{d:.0}", .{8});
1695}
lib/std/fs/File.zig+857-463
......@@ -1,3 +1,20 @@
1const builtin = @import("builtin");
2const Os = std.builtin.Os;
3const native_os = builtin.os.tag;
4const is_windows = native_os == .windows;
5
6const File = @This();
7const std = @import("../std.zig");
8const Allocator = std.mem.Allocator;
9const posix = std.posix;
10const io = std.io;
11const math = std.math;
12const assert = std.debug.assert;
13const linux = std.os.linux;
14const windows = std.os.windows;
15const maxInt = std.math.maxInt;
16const Alignment = std.mem.Alignment;
17
118/// The OS-specific file descriptor or file handle.
219handle: Handle,
320
......@@ -168,6 +185,18 @@ pub const CreateFlags = struct {
168185 mode: Mode = default_mode,
169186};
170187
188pub fn stdout() File {
189 return .{ .handle = if (is_windows) windows.peb().ProcessParameters.hStdOutput else posix.STDOUT_FILENO };
190}
191
192pub fn stderr() File {
193 return .{ .handle = if (is_windows) windows.peb().ProcessParameters.hStdError else posix.STDERR_FILENO };
194}
195
196pub fn stdin() File {
197 return .{ .handle = if (is_windows) windows.peb().ProcessParameters.hStdInput else posix.STDIN_FILENO };
198}
199
171200/// Upon success, the stream is in an uninitialized state. To continue using it,
172201/// you must use the open() function.
173202pub fn close(self: File) void {
......@@ -351,8 +380,10 @@ pub fn getPos(self: File) GetSeekPosError!u64 {
351380 return posix.lseek_CUR_get(self.handle);
352381}
353382
383pub const GetEndPosError = std.os.windows.GetFileSizeError || StatError;
384
354385/// TODO: integrate with async I/O
355pub fn getEndPos(self: File) GetSeekPosError!u64 {
386pub fn getEndPos(self: File) GetEndPosError!u64 {
356387 if (builtin.os.tag == .windows) {
357388 return windows.GetFileSizeEx(self.handle);
358389 }
......@@ -477,7 +508,6 @@ pub const Stat = struct {
477508pub const StatError = posix.FStatError;
478509
479510/// Returns `Stat` containing basic information about the `File`.
480/// Use `metadata` to retrieve more detailed information (e.g. creation time, permissions).
481511/// TODO: integrate with async I/O
482512pub fn stat(self: File) StatError!Stat {
483513 if (builtin.os.tag == .windows) {
......@@ -743,361 +773,6 @@ pub fn setPermissions(self: File, permissions: Permissions) SetPermissionsError!
743773 }
744774}
745775
746/// Cross-platform representation of file metadata.
747/// Platform-specific functionality is available through the `inner` field.
748pub const Metadata = struct {
749 /// Exposes platform-specific functionality.
750 inner: switch (builtin.os.tag) {
751 .windows => MetadataWindows,
752 .linux => MetadataLinux,
753 .wasi => MetadataWasi,
754 else => MetadataUnix,
755 },
756
757 const Self = @This();
758
759 /// Returns the size of the file
760 pub fn size(self: Self) u64 {
761 return self.inner.size();
762 }
763
764 /// Returns a `Permissions` struct, representing the permissions on the file
765 pub fn permissions(self: Self) Permissions {
766 return self.inner.permissions();
767 }
768
769 /// Returns the `Kind` of file.
770 /// On Windows, can only return: `.file`, `.directory`, `.sym_link` or `.unknown`
771 pub fn kind(self: Self) Kind {
772 return self.inner.kind();
773 }
774
775 /// Returns the last time the file was accessed in nanoseconds since UTC 1970-01-01
776 pub fn accessed(self: Self) i128 {
777 return self.inner.accessed();
778 }
779
780 /// Returns the time the file was modified in nanoseconds since UTC 1970-01-01
781 pub fn modified(self: Self) i128 {
782 return self.inner.modified();
783 }
784
785 /// Returns the time the file was created in nanoseconds since UTC 1970-01-01
786 /// On Windows, this cannot return null
787 /// On Linux, this returns null if the filesystem does not support creation times
788 /// On Unices, this returns null if the filesystem or OS does not support creation times
789 /// 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
790 pub fn created(self: Self) ?i128 {
791 return self.inner.created();
792 }
793};
794
795pub const MetadataUnix = struct {
796 stat: posix.Stat,
797
798 const Self = @This();
799
800 /// Returns the size of the file
801 pub fn size(self: Self) u64 {
802 return @intCast(self.stat.size);
803 }
804
805 /// Returns a `Permissions` struct, representing the permissions on the file
806 pub fn permissions(self: Self) Permissions {
807 return .{ .inner = .{ .mode = self.stat.mode } };
808 }
809
810 /// Returns the `Kind` of the file
811 pub fn kind(self: Self) Kind {
812 if (builtin.os.tag == .wasi and !builtin.link_libc) return switch (self.stat.filetype) {
813 .BLOCK_DEVICE => .block_device,
814 .CHARACTER_DEVICE => .character_device,
815 .DIRECTORY => .directory,
816 .SYMBOLIC_LINK => .sym_link,
817 .REGULAR_FILE => .file,
818 .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
819 else => .unknown,
820 };
821
822 const m = self.stat.mode & posix.S.IFMT;
823
824 switch (m) {
825 posix.S.IFBLK => return .block_device,
826 posix.S.IFCHR => return .character_device,
827 posix.S.IFDIR => return .directory,
828 posix.S.IFIFO => return .named_pipe,
829 posix.S.IFLNK => return .sym_link,
830 posix.S.IFREG => return .file,
831 posix.S.IFSOCK => return .unix_domain_socket,
832 else => {},
833 }
834
835 if (builtin.os.tag.isSolarish()) switch (m) {
836 posix.S.IFDOOR => return .door,
837 posix.S.IFPORT => return .event_port,
838 else => {},
839 };
840
841 return .unknown;
842 }
843
844 /// Returns the last time the file was accessed in nanoseconds since UTC 1970-01-01
845 pub fn accessed(self: Self) i128 {
846 const atime = self.stat.atime();
847 return @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec;
848 }
849
850 /// Returns the last time the file was modified in nanoseconds since UTC 1970-01-01
851 pub fn modified(self: Self) i128 {
852 const mtime = self.stat.mtime();
853 return @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec;
854 }
855
856 /// Returns the time the file was created in nanoseconds since UTC 1970-01-01.
857 /// Returns null if this is not supported by the OS or filesystem
858 pub fn created(self: Self) ?i128 {
859 if (!@hasDecl(@TypeOf(self.stat), "birthtime")) return null;
860 const birthtime = self.stat.birthtime();
861
862 // If the filesystem doesn't support this the value *should* be:
863 // On FreeBSD: nsec = 0, sec = -1
864 // On NetBSD and OpenBSD: nsec = 0, sec = 0
865 // On MacOS, it is set to ctime -- we cannot detect this!!
866 switch (builtin.os.tag) {
867 .freebsd => if (birthtime.sec == -1 and birthtime.nsec == 0) return null,
868 .netbsd, .openbsd => if (birthtime.sec == 0 and birthtime.nsec == 0) return null,
869 .macos => {},
870 else => @compileError("Creation time detection not implemented for OS"),
871 }
872
873 return @as(i128, birthtime.sec) * std.time.ns_per_s + birthtime.nsec;
874 }
875};
876
877/// `MetadataUnix`, but using Linux's `statx` syscall.
878pub const MetadataLinux = struct {
879 statx: std.os.linux.Statx,
880
881 const Self = @This();
882
883 /// Returns the size of the file
884 pub fn size(self: Self) u64 {
885 return self.statx.size;
886 }
887
888 /// Returns a `Permissions` struct, representing the permissions on the file
889 pub fn permissions(self: Self) Permissions {
890 return Permissions{ .inner = PermissionsUnix{ .mode = self.statx.mode } };
891 }
892
893 /// Returns the `Kind` of the file
894 pub fn kind(self: Self) Kind {
895 const m = self.statx.mode & posix.S.IFMT;
896
897 switch (m) {
898 posix.S.IFBLK => return .block_device,
899 posix.S.IFCHR => return .character_device,
900 posix.S.IFDIR => return .directory,
901 posix.S.IFIFO => return .named_pipe,
902 posix.S.IFLNK => return .sym_link,
903 posix.S.IFREG => return .file,
904 posix.S.IFSOCK => return .unix_domain_socket,
905 else => {},
906 }
907
908 return .unknown;
909 }
910
911 /// Returns the last time the file was accessed in nanoseconds since UTC 1970-01-01
912 pub fn accessed(self: Self) i128 {
913 return @as(i128, self.statx.atime.sec) * std.time.ns_per_s + self.statx.atime.nsec;
914 }
915
916 /// Returns the last time the file was modified in nanoseconds since UTC 1970-01-01
917 pub fn modified(self: Self) i128 {
918 return @as(i128, self.statx.mtime.sec) * std.time.ns_per_s + self.statx.mtime.nsec;
919 }
920
921 /// Returns the time the file was created in nanoseconds since UTC 1970-01-01.
922 /// Returns null if this is not supported by the filesystem, or on kernels before than version 4.11
923 pub fn created(self: Self) ?i128 {
924 if (self.statx.mask & std.os.linux.STATX_BTIME == 0) return null;
925 return @as(i128, self.statx.btime.sec) * std.time.ns_per_s + self.statx.btime.nsec;
926 }
927};
928
929pub const MetadataWasi = struct {
930 stat: std.os.wasi.filestat_t,
931
932 pub fn size(self: @This()) u64 {
933 return self.stat.size;
934 }
935
936 pub fn permissions(self: @This()) Permissions {
937 return .{ .inner = .{ .mode = self.stat.mode } };
938 }
939
940 pub fn kind(self: @This()) Kind {
941 return switch (self.stat.filetype) {
942 .BLOCK_DEVICE => .block_device,
943 .CHARACTER_DEVICE => .character_device,
944 .DIRECTORY => .directory,
945 .SYMBOLIC_LINK => .sym_link,
946 .REGULAR_FILE => .file,
947 .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
948 else => .unknown,
949 };
950 }
951
952 pub fn accessed(self: @This()) i128 {
953 return self.stat.atim;
954 }
955
956 pub fn modified(self: @This()) i128 {
957 return self.stat.mtim;
958 }
959
960 pub fn created(self: @This()) ?i128 {
961 return self.stat.ctim;
962 }
963};
964
965pub const MetadataWindows = struct {
966 attributes: windows.DWORD,
967 reparse_tag: windows.DWORD,
968 _size: u64,
969 access_time: i128,
970 modified_time: i128,
971 creation_time: i128,
972
973 const Self = @This();
974
975 /// Returns the size of the file
976 pub fn size(self: Self) u64 {
977 return self._size;
978 }
979
980 /// Returns a `Permissions` struct, representing the permissions on the file
981 pub fn permissions(self: Self) Permissions {
982 return .{ .inner = .{ .attributes = self.attributes } };
983 }
984
985 /// Returns the `Kind` of the file.
986 /// Can only return: `.file`, `.directory`, `.sym_link` or `.unknown`
987 pub fn kind(self: Self) Kind {
988 if (self.attributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) {
989 if (self.reparse_tag & windows.reparse_tag_name_surrogate_bit != 0) {
990 return .sym_link;
991 }
992 } else if (self.attributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0) {
993 return .directory;
994 } else {
995 return .file;
996 }
997 return .unknown;
998 }
999
1000 /// Returns the last time the file was accessed in nanoseconds since UTC 1970-01-01
1001 pub fn accessed(self: Self) i128 {
1002 return self.access_time;
1003 }
1004
1005 /// Returns the time the file was modified in nanoseconds since UTC 1970-01-01
1006 pub fn modified(self: Self) i128 {
1007 return self.modified_time;
1008 }
1009
1010 /// Returns the time the file was created in nanoseconds since UTC 1970-01-01.
1011 /// This never returns null, only returning an optional for compatibility with other OSes
1012 pub fn created(self: Self) ?i128 {
1013 return self.creation_time;
1014 }
1015};
1016
1017pub const MetadataError = posix.FStatError;
1018
1019pub fn metadata(self: File) MetadataError!Metadata {
1020 return .{
1021 .inner = switch (builtin.os.tag) {
1022 .windows => blk: {
1023 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
1024 var info: windows.FILE_ALL_INFORMATION = undefined;
1025
1026 const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation);
1027 switch (rc) {
1028 .SUCCESS => {},
1029 // Buffer overflow here indicates that there is more information available than was able to be stored in the buffer
1030 // size provided. This is treated as success because the type of variable-length information that this would be relevant for
1031 // (name, volume name, etc) we don't care about.
1032 .BUFFER_OVERFLOW => {},
1033 .INVALID_PARAMETER => unreachable,
1034 .ACCESS_DENIED => return error.AccessDenied,
1035 else => return windows.unexpectedStatus(rc),
1036 }
1037
1038 const reparse_tag: windows.DWORD = reparse_blk: {
1039 if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) {
1040 var tag_info: windows.FILE_ATTRIBUTE_TAG_INFO = undefined;
1041 const tag_rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE_ATTRIBUTE_TAG_INFO), .FileAttributeTagInformation);
1042 switch (tag_rc) {
1043 .SUCCESS => {},
1044 // INFO_LENGTH_MISMATCH and ACCESS_DENIED are the only documented possible errors
1045 // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d295752f-ce89-4b98-8553-266d37c84f0e
1046 .INFO_LENGTH_MISMATCH => unreachable,
1047 .ACCESS_DENIED => return error.AccessDenied,
1048 else => return windows.unexpectedStatus(rc),
1049 }
1050 break :reparse_blk tag_info.ReparseTag;
1051 }
1052 break :reparse_blk 0;
1053 };
1054
1055 break :blk .{
1056 .attributes = info.BasicInformation.FileAttributes,
1057 .reparse_tag = reparse_tag,
1058 ._size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
1059 .access_time = windows.fromSysTime(info.BasicInformation.LastAccessTime),
1060 .modified_time = windows.fromSysTime(info.BasicInformation.LastWriteTime),
1061 .creation_time = windows.fromSysTime(info.BasicInformation.CreationTime),
1062 };
1063 },
1064 .linux => blk: {
1065 var stx = std.mem.zeroes(linux.Statx);
1066
1067 // We are gathering information for Metadata, which is meant to contain all the
1068 // native OS information about the file, so use all known flags.
1069 const rc = linux.statx(
1070 self.handle,
1071 "",
1072 linux.AT.EMPTY_PATH,
1073 linux.STATX_BASIC_STATS | linux.STATX_BTIME,
1074 &stx,
1075 );
1076
1077 switch (linux.E.init(rc)) {
1078 .SUCCESS => {},
1079 .ACCES => unreachable,
1080 .BADF => unreachable,
1081 .FAULT => unreachable,
1082 .INVAL => unreachable,
1083 .LOOP => unreachable,
1084 .NAMETOOLONG => unreachable,
1085 .NOENT => unreachable,
1086 .NOMEM => return error.SystemResources,
1087 .NOTDIR => unreachable,
1088 else => |err| return posix.unexpectedErrno(err),
1089 }
1090
1091 break :blk .{
1092 .statx = stx,
1093 };
1094 },
1095 .wasi => .{ .stat = try std.os.fstat_wasi(self.handle) },
1096 else => .{ .stat = try posix.fstat(self.handle) },
1097 },
1098 };
1099}
1100
1101776pub const UpdateTimesError = posix.FutimensError || windows.SetFileTimeError;
1102777
1103778/// The underlying file system may have a different granularity than nanoseconds,
......@@ -1130,19 +805,12 @@ pub fn updateTimes(
1130805 try posix.futimens(self.handle, &times);
1131806}
1132807
1133/// Reads all the bytes from the current position to the end of the file.
1134/// On success, caller owns returned buffer.
1135/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
808/// Deprecated in favor of `Reader`.
1136809pub fn readToEndAlloc(self: File, allocator: Allocator, max_bytes: usize) ![]u8 {
1137810 return self.readToEndAllocOptions(allocator, max_bytes, null, .of(u8), null);
1138811}
1139812
1140/// Reads all the bytes from the current position to the end of the file.
1141/// On success, caller owns returned buffer.
1142/// If the file is larger than `max_bytes`, returns `error.FileTooBig`.
1143/// If `size_hint` is specified the initial buffer size is calculated using
1144/// that value, otherwise an arbitrary value is used instead.
1145/// Allows specifying alignment and a sentinel value.
813/// Deprecated in favor of `Reader`.
1146814pub fn readToEndAllocOptions(
1147815 self: File,
1148816 allocator: Allocator,
......@@ -1161,7 +829,7 @@ pub fn readToEndAllocOptions(
1161829 var array_list = try std.ArrayListAligned(u8, alignment).initCapacity(allocator, initial_cap);
1162830 defer array_list.deinit();
1163831
1164 self.reader().readAllArrayListAligned(alignment, &array_list, max_bytes) catch |err| switch (err) {
832 self.deprecatedReader().readAllArrayListAligned(alignment, &array_list, max_bytes) catch |err| switch (err) {
1165833 error.StreamTooLong => return error.FileTooBig,
1166834 else => |e| return e,
1167835 };
......@@ -1184,8 +852,7 @@ pub fn read(self: File, buffer: []u8) ReadError!usize {
1184852 return posix.read(self.handle, buffer);
1185853}
1186854
1187/// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
1188/// means the file reached the end. Reaching the end of a file is not an error condition.
855/// Deprecated in favor of `Reader`.
1189856pub fn readAll(self: File, buffer: []u8) ReadError!usize {
1190857 var index: usize = 0;
1191858 while (index != buffer.len) {
......@@ -1206,10 +873,7 @@ pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
1206873 return posix.pread(self.handle, buffer, offset);
1207874}
1208875
1209/// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
1210/// means the file reached the end. Reaching the end of a file is not an error condition.
1211/// On Windows, this function currently does alter the file pointer.
1212/// https://github.com/ziglang/zig/issues/12783
876/// Deprecated in favor of `Reader`.
1213877pub fn preadAll(self: File, buffer: []u8, offset: u64) PReadError!usize {
1214878 var index: usize = 0;
1215879 while (index != buffer.len) {
......@@ -1223,8 +887,7 @@ pub fn preadAll(self: File, buffer: []u8, offset: u64) PReadError!usize {
1223887/// See https://github.com/ziglang/zig/issues/7699
1224888pub fn readv(self: File, iovecs: []const posix.iovec) ReadError!usize {
1225889 if (is_windows) {
1226 // TODO improve this to use ReadFileScatter
1227 if (iovecs.len == 0) return @as(usize, 0);
890 if (iovecs.len == 0) return 0;
1228891 const first = iovecs[0];
1229892 return windows.ReadFile(self.handle, first.base[0..first.len], null);
1230893 }
......@@ -1232,19 +895,7 @@ pub fn readv(self: File, iovecs: []const posix.iovec) ReadError!usize {
1232895 return posix.readv(self.handle, iovecs);
1233896}
1234897
1235/// Returns the number of bytes read. If the number read is smaller than the total bytes
1236/// from all the buffers, it means the file reached the end. Reaching the end of a file
1237/// is not an error condition.
1238///
1239/// The `iovecs` parameter is mutable because:
1240/// * This function needs to mutate the fields in order to handle partial
1241/// reads from the underlying OS layer.
1242/// * The OS layer expects pointer addresses to be inside the application's address space
1243/// even if the length is zero. Meanwhile, in Zig, slices may have undefined pointer
1244/// addresses when the length is zero. So this function modifies the base fields
1245/// when the length is zero.
1246///
1247/// Related open issue: https://github.com/ziglang/zig/issues/7699
898/// Deprecated in favor of `Reader`.
1248899pub fn readvAll(self: File, iovecs: []posix.iovec) ReadError!usize {
1249900 if (iovecs.len == 0) return 0;
1250901
......@@ -1279,8 +930,7 @@ pub fn readvAll(self: File, iovecs: []posix.iovec) ReadError!usize {
1279930/// https://github.com/ziglang/zig/issues/12783
1280931pub fn preadv(self: File, iovecs: []const posix.iovec, offset: u64) PReadError!usize {
1281932 if (is_windows) {
1282 // TODO improve this to use ReadFileScatter
1283 if (iovecs.len == 0) return @as(usize, 0);
933 if (iovecs.len == 0) return 0;
1284934 const first = iovecs[0];
1285935 return windows.ReadFile(self.handle, first.base[0..first.len], offset);
1286936 }
......@@ -1288,14 +938,7 @@ pub fn preadv(self: File, iovecs: []const posix.iovec, offset: u64) PReadError!u
1288938 return posix.preadv(self.handle, iovecs, offset);
1289939}
1290940
1291/// Returns the number of bytes read. If the number read is smaller than the total bytes
1292/// from all the buffers, it means the file reached the end. Reaching the end of a file
1293/// is not an error condition.
1294/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
1295/// order to handle partial reads from the underlying OS layer.
1296/// See https://github.com/ziglang/zig/issues/7699
1297/// On Windows, this function currently does alter the file pointer.
1298/// https://github.com/ziglang/zig/issues/12783
941/// Deprecated in favor of `Reader`.
1299942pub fn preadvAll(self: File, iovecs: []posix.iovec, offset: u64) PReadError!usize {
1300943 if (iovecs.len == 0) return 0;
1301944
......@@ -1328,6 +971,7 @@ pub fn write(self: File, bytes: []const u8) WriteError!usize {
1328971 return posix.write(self.handle, bytes);
1329972}
1330973
974/// Deprecated in favor of `Writer`.
1331975pub fn writeAll(self: File, bytes: []const u8) WriteError!void {
1332976 var index: usize = 0;
1333977 while (index < bytes.len) {
......@@ -1345,8 +989,7 @@ pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
1345989 return posix.pwrite(self.handle, bytes, offset);
1346990}
1347991
1348/// On Windows, this function currently does alter the file pointer.
1349/// https://github.com/ziglang/zig/issues/12783
992/// Deprecated in favor of `Writer`.
1350993pub fn pwriteAll(self: File, bytes: []const u8, offset: u64) PWriteError!void {
1351994 var index: usize = 0;
1352995 while (index < bytes.len) {
......@@ -1355,11 +998,10 @@ pub fn pwriteAll(self: File, bytes: []const u8, offset: u64) PWriteError!void {
1355998}
1356999
13571000/// See https://github.com/ziglang/zig/issues/7699
1358/// See equivalent function: `std.net.Stream.writev`.
13591001pub fn writev(self: File, iovecs: []const posix.iovec_const) WriteError!usize {
13601002 if (is_windows) {
13611003 // TODO improve this to use WriteFileScatter
1362 if (iovecs.len == 0) return @as(usize, 0);
1004 if (iovecs.len == 0) return 0;
13631005 const first = iovecs[0];
13641006 return windows.WriteFile(self.handle, first.base[0..first.len], null);
13651007 }
......@@ -1367,15 +1009,7 @@ pub fn writev(self: File, iovecs: []const posix.iovec_const) WriteError!usize {
13671009 return posix.writev(self.handle, iovecs);
13681010}
13691011
1370/// The `iovecs` parameter is mutable because:
1371/// * This function needs to mutate the fields in order to handle partial
1372/// writes from the underlying OS layer.
1373/// * The OS layer expects pointer addresses to be inside the application's address space
1374/// even if the length is zero. Meanwhile, in Zig, slices may have undefined pointer
1375/// addresses when the length is zero. So this function modifies the base fields
1376/// when the length is zero.
1377/// See https://github.com/ziglang/zig/issues/7699
1378/// See equivalent function: `std.net.Stream.writevAll`.
1012/// Deprecated in favor of `Writer`.
13791013pub fn writevAll(self: File, iovecs: []posix.iovec_const) WriteError!void {
13801014 if (iovecs.len == 0) return;
13811015
......@@ -1405,8 +1039,7 @@ pub fn writevAll(self: File, iovecs: []posix.iovec_const) WriteError!void {
14051039/// https://github.com/ziglang/zig/issues/12783
14061040pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError!usize {
14071041 if (is_windows) {
1408 // TODO improve this to use WriteFileScatter
1409 if (iovecs.len == 0) return @as(usize, 0);
1042 if (iovecs.len == 0) return 0;
14101043 const first = iovecs[0];
14111044 return windows.WriteFile(self.handle, first.base[0..first.len], offset);
14121045 }
......@@ -1414,14 +1047,9 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError
14141047 return posix.pwritev(self.handle, iovecs, offset);
14151048}
14161049
1417/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
1418/// order to handle partial writes from the underlying OS layer.
1419/// See https://github.com/ziglang/zig/issues/7699
1420/// On Windows, this function currently does alter the file pointer.
1421/// https://github.com/ziglang/zig/issues/12783
1050/// Deprecated in favor of `Writer`.
14221051pub fn pwritevAll(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError!void {
14231052 if (iovecs.len == 0) return;
1424
14251053 var i: usize = 0;
14261054 var off: u64 = 0;
14271055 while (true) {
......@@ -1439,14 +1067,14 @@ pub fn pwritevAll(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteEr
14391067
14401068pub const CopyRangeError = posix.CopyFileRangeError;
14411069
1070/// Deprecated in favor of `Writer`.
14421071pub fn copyRange(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 {
14431072 const adjusted_len = math.cast(usize, len) orelse maxInt(usize);
14441073 const result = try posix.copy_file_range(in.handle, in_offset, out.handle, out_offset, adjusted_len, 0);
14451074 return result;
14461075}
14471076
1448/// Returns the number of bytes copied. If the number read is smaller than `buffer.len`, it
1449/// means the in file reached the end. Reaching the end of a file is not an error condition.
1077/// Deprecated in favor of `Writer`.
14501078pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 {
14511079 var total_bytes_copied: u64 = 0;
14521080 var in_off = in_offset;
......@@ -1461,24 +1089,18 @@ pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u
14611089 return total_bytes_copied;
14621090}
14631091
1092/// Deprecated in favor of `Writer`.
14641093pub const WriteFileOptions = struct {
14651094 in_offset: u64 = 0,
1466
1467 /// `null` means the entire file. `0` means no bytes from the file.
1468 /// When this is `null`, trailers must be sent in a separate writev() call
1469 /// due to a flaw in the BSD sendfile API. Other operating systems, such as
1470 /// Linux, already do this anyway due to API limitations.
1471 /// If the size of the source file is known, passing the size here will save one syscall.
14721095 in_len: ?u64 = null,
1473
14741096 headers_and_trailers: []posix.iovec_const = &[0]posix.iovec_const{},
1475
1476 /// The trailer count is inferred from `headers_and_trailers.len - header_count`
14771097 header_count: usize = 0,
14781098};
14791099
1100/// Deprecated in favor of `Writer`.
14801101pub const WriteFileError = ReadError || error{EndOfStream} || WriteError;
14811102
1103/// Deprecated in favor of `Writer`.
14821104pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
14831105 return self.writeFileAllSendfile(in_file, args) catch |err| switch (err) {
14841106 error.Unseekable,
......@@ -1488,35 +1110,27 @@ pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFile
14881110 error.NetworkUnreachable,
14891111 error.NetworkSubsystemFailed,
14901112 => return self.writeFileAllUnseekable(in_file, args),
1491
14921113 else => |e| return e,
14931114 };
14941115}
14951116
1496/// Does not try seeking in either of the File parameters.
1497/// See `writeFileAll` as an alternative to calling this.
1117/// Deprecated in favor of `Writer`.
14981118pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
14991119 const headers = args.headers_and_trailers[0..args.header_count];
15001120 const trailers = args.headers_and_trailers[args.header_count..];
1501
15021121 try self.writevAll(headers);
1503
1504 try in_file.reader().skipBytes(args.in_offset, .{ .buf_size = 4096 });
1505
1122 try in_file.deprecatedReader().skipBytes(args.in_offset, .{ .buf_size = 4096 });
15061123 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
15071124 if (args.in_len) |len| {
1508 var stream = std.io.limitedReader(in_file.reader(), len);
1509 try fifo.pump(stream.reader(), self.writer());
1125 var stream = std.io.limitedReader(in_file.deprecatedReader(), len);
1126 try fifo.pump(stream.reader(), self.deprecatedWriter());
15101127 } else {
1511 try fifo.pump(in_file.reader(), self.writer());
1128 try fifo.pump(in_file.deprecatedReader(), self.deprecatedWriter());
15121129 }
1513
15141130 try self.writevAll(trailers);
15151131}
15161132
1517/// Low level function which can fail for OS-specific reasons.
1518/// See `writeFileAll` as an alternative to calling this.
1519/// TODO integrate with async I/O
1133/// Deprecated in favor of `Writer`.
15201134fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) posix.SendFileError!void {
15211135 const count = blk: {
15221136 if (args.in_len) |l| {
......@@ -1581,18 +1195,23 @@ fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) posix
15811195 }
15821196}
15831197
1584pub const Reader = io.Reader(File, ReadError, read);
1198/// Deprecated in favor of `Reader`.
1199pub const DeprecatedReader = io.GenericReader(File, ReadError, read);
15851200
1586pub fn reader(file: File) Reader {
1201/// Deprecated in favor of `Reader`.
1202pub fn deprecatedReader(file: File) DeprecatedReader {
15871203 return .{ .context = file };
15881204}
15891205
1590pub const Writer = io.Writer(File, WriteError, write);
1206/// Deprecated in favor of `Writer`.
1207pub const DeprecatedWriter = io.GenericWriter(File, WriteError, write);
15911208
1592pub fn writer(file: File) Writer {
1209/// Deprecated in favor of `Writer`.
1210pub fn deprecatedWriter(file: File) DeprecatedWriter {
15931211 return .{ .context = file };
15941212}
15951213
1214/// Deprecated in favor of `Reader` and `Writer`.
15961215pub const SeekableStream = io.SeekableStream(
15971216 File,
15981217 SeekError,
......@@ -1603,10 +1222,800 @@ pub const SeekableStream = io.SeekableStream(
16031222 getEndPos,
16041223);
16051224
1225/// Deprecated in favor of `Reader` and `Writer`.
16061226pub fn seekableStream(file: File) SeekableStream {
16071227 return .{ .context = file };
16081228}
16091229
1230/// Memoizes key information about a file handle such as:
1231/// * The size from calling stat, or the error that occurred therein.
1232/// * The current seek position.
1233/// * The error that occurred when trying to seek.
1234/// * Whether reading should be done positionally or streaming.
1235/// * Whether reading should be done via fd-to-fd syscalls (e.g. `sendfile`)
1236/// versus plain variants (e.g. `read`).
1237///
1238/// Fulfills the `std.io.Reader` interface.
1239pub const Reader = struct {
1240 file: File,
1241 err: ?ReadError = null,
1242 mode: Reader.Mode = .positional,
1243 /// Tracks the true seek position in the file. To obtain the logical
1244 /// position, subtract the buffer size from this value.
1245 pos: u64 = 0,
1246 size: ?u64 = null,
1247 size_err: ?GetEndPosError = null,
1248 seek_err: ?Reader.SeekError = null,
1249 interface: std.io.Reader,
1250
1251 pub const SeekError = File.SeekError || error{
1252 /// Seeking fell back to reading, and reached the end before the requested seek position.
1253 /// `pos` remains at the end of the file.
1254 EndOfStream,
1255 /// Seeking fell back to reading, which failed.
1256 ReadFailed,
1257 };
1258
1259 pub const Mode = enum {
1260 streaming,
1261 positional,
1262 /// Avoid syscalls other than `read` and `readv`.
1263 streaming_reading,
1264 /// Avoid syscalls other than `pread` and `preadv`.
1265 positional_reading,
1266 /// Indicates reading cannot continue because of a seek failure.
1267 failure,
1268
1269 pub fn toStreaming(m: @This()) @This() {
1270 return switch (m) {
1271 .positional, .streaming => .streaming,
1272 .positional_reading, .streaming_reading => .streaming_reading,
1273 .failure => .failure,
1274 };
1275 }
1276
1277 pub fn toReading(m: @This()) @This() {
1278 return switch (m) {
1279 .positional, .positional_reading => .positional_reading,
1280 .streaming, .streaming_reading => .streaming_reading,
1281 .failure => .failure,
1282 };
1283 }
1284 };
1285
1286 pub fn initInterface(buffer: []u8) std.io.Reader {
1287 return .{
1288 .vtable = &.{
1289 .stream = Reader.stream,
1290 .discard = Reader.discard,
1291 },
1292 .buffer = buffer,
1293 .seek = 0,
1294 .end = 0,
1295 };
1296 }
1297
1298 pub fn init(file: File, buffer: []u8) Reader {
1299 return .{
1300 .file = file,
1301 .interface = initInterface(buffer),
1302 };
1303 }
1304
1305 pub fn initSize(file: File, buffer: []u8, size: ?u64) Reader {
1306 return .{
1307 .file = file,
1308 .interface = initInterface(buffer),
1309 .size = size,
1310 };
1311 }
1312
1313 pub fn initMode(file: File, buffer: []u8, init_mode: Reader.Mode) Reader {
1314 return .{
1315 .file = file,
1316 .interface = initInterface(buffer),
1317 .mode = init_mode,
1318 };
1319 }
1320
1321 pub fn getSize(r: *Reader) GetEndPosError!u64 {
1322 return r.size orelse {
1323 if (r.size_err) |err| return err;
1324 if (r.file.getEndPos()) |size| {
1325 r.size = size;
1326 return size;
1327 } else |err| {
1328 r.size_err = err;
1329 return err;
1330 }
1331 };
1332 }
1333
1334 pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void {
1335 switch (r.mode) {
1336 .positional, .positional_reading => {
1337 // TODO: make += operator allow any integer types
1338 r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
1339 },
1340 .streaming, .streaming_reading => {
1341 const seek_err = r.seek_err orelse e: {
1342 if (posix.lseek_CUR(r.file.handle, offset)) |_| {
1343 // TODO: make += operator allow any integer types
1344 r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
1345 return;
1346 } else |err| {
1347 r.seek_err = err;
1348 break :e err;
1349 }
1350 };
1351 var remaining = std.math.cast(u64, offset) orelse return seek_err;
1352 while (remaining > 0) {
1353 const n = discard(&r.interface, .limited64(remaining)) catch |err| {
1354 r.seek_err = err;
1355 return err;
1356 };
1357 r.pos += n;
1358 remaining -= n;
1359 }
1360 },
1361 .failure => return r.seek_err.?,
1362 }
1363 }
1364
1365 pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void {
1366 switch (r.mode) {
1367 .positional, .positional_reading => {
1368 r.pos = offset;
1369 },
1370 .streaming, .streaming_reading => {
1371 if (offset >= r.pos) return Reader.seekBy(r, offset - r.pos);
1372 if (r.seek_err) |err| return err;
1373 posix.lseek_SET(r.file.handle, offset) catch |err| {
1374 r.seek_err = err;
1375 return err;
1376 };
1377 r.pos = offset;
1378 },
1379 .failure => return r.seek_err.?,
1380 }
1381 }
1382
1383 /// Number of slices to store on the stack, when trying to send as many byte
1384 /// vectors through the underlying read calls as possible.
1385 const max_buffers_len = 16;
1386
1387 fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {
1388 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
1389 switch (r.mode) {
1390 .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) {
1391 error.Unimplemented => {
1392 r.mode = r.mode.toReading();
1393 return 0;
1394 },
1395 else => |e| return e,
1396 },
1397 .positional_reading => {
1398 if (is_windows) {
1399 // Unfortunately, `ReadFileScatter` cannot be used since it
1400 // requires page alignment.
1401 const dest = limit.slice(try w.writableSliceGreedy(1));
1402 const n = try readPositional(r, dest);
1403 w.advance(n);
1404 return n;
1405 }
1406 var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
1407 const dest = try w.writableVectorPosix(&iovecs_buffer, limit);
1408 assert(dest[0].len > 0);
1409 const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) {
1410 error.Unseekable => {
1411 r.mode = r.mode.toStreaming();
1412 const pos = r.pos;
1413 if (pos != 0) {
1414 r.pos = 0;
1415 r.seekBy(@intCast(pos)) catch {
1416 r.mode = .failure;
1417 return error.ReadFailed;
1418 };
1419 }
1420 return 0;
1421 },
1422 else => |e| {
1423 r.err = e;
1424 return error.ReadFailed;
1425 },
1426 };
1427 if (n == 0) {
1428 r.size = r.pos;
1429 return error.EndOfStream;
1430 }
1431 r.pos += n;
1432 return n;
1433 },
1434 .streaming_reading => {
1435 if (is_windows) {
1436 // Unfortunately, `ReadFileScatter` cannot be used since it
1437 // requires page alignment.
1438 const dest = limit.slice(try w.writableSliceGreedy(1));
1439 const n = try readStreaming(r, dest);
1440 w.advance(n);
1441 return n;
1442 }
1443 var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
1444 const dest = try w.writableVectorPosix(&iovecs_buffer, limit);
1445 assert(dest[0].len > 0);
1446 const n = posix.readv(r.file.handle, dest) catch |err| {
1447 r.err = err;
1448 return error.ReadFailed;
1449 };
1450 if (n == 0) {
1451 r.size = r.pos;
1452 return error.EndOfStream;
1453 }
1454 r.pos += n;
1455 return n;
1456 },
1457 .failure => return error.ReadFailed,
1458 }
1459 }
1460
1461 fn discard(io_reader: *std.io.Reader, limit: std.io.Limit) std.io.Reader.Error!usize {
1462 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
1463 const file = r.file;
1464 const pos = r.pos;
1465 switch (r.mode) {
1466 .positional, .positional_reading => {
1467 const size = r.size orelse {
1468 if (file.getEndPos()) |size| {
1469 r.size = size;
1470 } else |err| {
1471 r.size_err = err;
1472 r.mode = r.mode.toStreaming();
1473 }
1474 return 0;
1475 };
1476 const delta = @min(@intFromEnum(limit), size - pos);
1477 r.pos = pos + delta;
1478 return delta;
1479 },
1480 .streaming, .streaming_reading => {
1481 // Unfortunately we can't seek forward without knowing the
1482 // size because the seek syscalls provided to us will not
1483 // return the true end position if a seek would exceed the
1484 // end.
1485 fallback: {
1486 if (r.size_err == null and r.seek_err == null) break :fallback;
1487 var trash_buffer: [128]u8 = undefined;
1488 const trash = &trash_buffer;
1489 if (is_windows) {
1490 const n = windows.ReadFile(file.handle, trash, null) catch |err| {
1491 r.err = err;
1492 return error.ReadFailed;
1493 };
1494 if (n == 0) {
1495 r.size = pos;
1496 return error.EndOfStream;
1497 }
1498 r.pos = pos + n;
1499 return n;
1500 }
1501 var iovecs: [max_buffers_len]std.posix.iovec = undefined;
1502 var iovecs_i: usize = 0;
1503 var remaining = @intFromEnum(limit);
1504 while (remaining > 0 and iovecs_i < iovecs.len) {
1505 iovecs[iovecs_i] = .{ .base = trash, .len = @min(trash.len, remaining) };
1506 remaining -= iovecs[iovecs_i].len;
1507 iovecs_i += 1;
1508 }
1509 const n = posix.readv(file.handle, iovecs[0..iovecs_i]) catch |err| {
1510 r.err = err;
1511 return error.ReadFailed;
1512 };
1513 if (n == 0) {
1514 r.size = pos;
1515 return error.EndOfStream;
1516 }
1517 r.pos = pos + n;
1518 return n;
1519 }
1520 const size = r.size orelse {
1521 if (file.getEndPos()) |size| {
1522 r.size = size;
1523 } else |err| {
1524 r.size_err = err;
1525 }
1526 return 0;
1527 };
1528 const n = @min(size - pos, std.math.maxInt(i64), @intFromEnum(limit));
1529 file.seekBy(n) catch |err| {
1530 r.seek_err = err;
1531 return 0;
1532 };
1533 r.pos = pos + n;
1534 return n;
1535 },
1536 .failure => return error.ReadFailed,
1537 }
1538 }
1539
1540 pub fn readPositional(r: *Reader, dest: []u8) std.io.Reader.Error!usize {
1541 const n = r.file.pread(dest, r.pos) catch |err| switch (err) {
1542 error.Unseekable => {
1543 r.mode = r.mode.toStreaming();
1544 const pos = r.pos;
1545 if (pos != 0) {
1546 r.pos = 0;
1547 r.seekBy(@intCast(pos)) catch {
1548 r.mode = .failure;
1549 return error.ReadFailed;
1550 };
1551 }
1552 return 0;
1553 },
1554 else => |e| {
1555 r.err = e;
1556 return error.ReadFailed;
1557 },
1558 };
1559 if (n == 0) {
1560 r.size = r.pos;
1561 return error.EndOfStream;
1562 }
1563 r.pos += n;
1564 return n;
1565 }
1566
1567 pub fn readStreaming(r: *Reader, dest: []u8) std.io.Reader.Error!usize {
1568 const n = r.file.read(dest) catch |err| {
1569 r.err = err;
1570 return error.ReadFailed;
1571 };
1572 if (n == 0) {
1573 r.size = r.pos;
1574 return error.EndOfStream;
1575 }
1576 r.pos += n;
1577 return n;
1578 }
1579
1580 pub fn read(r: *Reader, dest: []u8) std.io.Reader.Error!usize {
1581 switch (r.mode) {
1582 .positional, .positional_reading => return readPositional(r, dest),
1583 .streaming, .streaming_reading => return readStreaming(r, dest),
1584 .failure => return error.ReadFailed,
1585 }
1586 }
1587
1588 pub fn atEnd(r: *Reader) bool {
1589 // Even if stat fails, size is set when end is encountered.
1590 const size = r.size orelse return false;
1591 return size - r.pos == 0;
1592 }
1593};
1594
1595pub const Writer = struct {
1596 file: File,
1597 err: ?WriteError = null,
1598 mode: Writer.Mode = .positional,
1599 /// Tracks the true seek position in the file. To obtain the logical
1600 /// position, add the buffer size to this value.
1601 pos: u64 = 0,
1602 sendfile_err: ?SendfileError = null,
1603 copy_file_range_err: ?CopyFileRangeError = null,
1604 fcopyfile_err: ?FcopyfileError = null,
1605 seek_err: ?SeekError = null,
1606 interface: std.io.Writer,
1607
1608 pub const Mode = Reader.Mode;
1609
1610 pub const SendfileError = error{
1611 UnsupportedOperation,
1612 SystemResources,
1613 InputOutput,
1614 BrokenPipe,
1615 WouldBlock,
1616 Unexpected,
1617 };
1618
1619 pub const CopyFileRangeError = std.os.freebsd.CopyFileRangeError || std.os.linux.wrapped.CopyFileRangeError;
1620
1621 pub const FcopyfileError = error{
1622 OperationNotSupported,
1623 OutOfMemory,
1624 Unexpected,
1625 };
1626
1627 /// Number of slices to store on the stack, when trying to send as many byte
1628 /// vectors through the underlying write calls as possible.
1629 const max_buffers_len = 16;
1630
1631 pub fn init(file: File, buffer: []u8) Writer {
1632 return initMode(file, buffer, .positional);
1633 }
1634
1635 pub fn initMode(file: File, buffer: []u8, init_mode: Writer.Mode) Writer {
1636 return .{
1637 .file = file,
1638 .interface = initInterface(buffer),
1639 .mode = init_mode,
1640 };
1641 }
1642
1643 pub fn initInterface(buffer: []u8) std.io.Writer {
1644 return .{
1645 .vtable = &.{
1646 .drain = drain,
1647 .sendFile = sendFile,
1648 },
1649 .buffer = buffer,
1650 };
1651 }
1652
1653 pub fn moveToReader(w: *Writer) Reader {
1654 defer w.* = undefined;
1655 return .{
1656 .file = w.file,
1657 .mode = w.mode,
1658 .pos = w.pos,
1659 .seek_err = w.seek_err,
1660 };
1661 }
1662
1663 pub fn drain(io_w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
1664 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
1665 const handle = w.file.handle;
1666 const buffered = io_w.buffered();
1667 if (is_windows) switch (w.mode) {
1668 .positional, .positional_reading => {
1669 if (buffered.len != 0) {
1670 const n = windows.WriteFile(handle, buffered, w.pos) catch |err| {
1671 w.err = err;
1672 return error.WriteFailed;
1673 };
1674 w.pos += n;
1675 return io_w.consume(n);
1676 }
1677 for (data[0 .. data.len - 1]) |buf| {
1678 if (buf.len == 0) continue;
1679 const n = windows.WriteFile(handle, buf, w.pos) catch |err| {
1680 w.err = err;
1681 return error.WriteFailed;
1682 };
1683 w.pos += n;
1684 return io_w.consume(n);
1685 }
1686 const pattern = data[data.len - 1];
1687 if (pattern.len == 0 or splat == 0) return 0;
1688 const n = windows.WriteFile(handle, pattern, w.pos) catch |err| {
1689 w.err = err;
1690 return error.WriteFailed;
1691 };
1692 w.pos += n;
1693 return io_w.consume(n);
1694 },
1695 .streaming, .streaming_reading => {
1696 if (buffered.len != 0) {
1697 const n = windows.WriteFile(handle, buffered, null) catch |err| {
1698 w.err = err;
1699 return error.WriteFailed;
1700 };
1701 w.pos += n;
1702 return io_w.consume(n);
1703 }
1704 for (data[0 .. data.len - 1]) |buf| {
1705 if (buf.len == 0) continue;
1706 const n = windows.WriteFile(handle, buf, null) catch |err| {
1707 w.err = err;
1708 return error.WriteFailed;
1709 };
1710 w.pos += n;
1711 return io_w.consume(n);
1712 }
1713 const pattern = data[data.len - 1];
1714 if (pattern.len == 0 or splat == 0) return 0;
1715 const n = windows.WriteFile(handle, pattern, null) catch |err| {
1716 std.debug.print("windows write file failed3: {t}\n", .{err});
1717 w.err = err;
1718 return error.WriteFailed;
1719 };
1720 w.pos += n;
1721 return io_w.consume(n);
1722 },
1723 .failure => return error.WriteFailed,
1724 };
1725 var iovecs: [max_buffers_len]std.posix.iovec_const = undefined;
1726 var len: usize = 0;
1727 if (buffered.len > 0) {
1728 iovecs[len] = .{ .base = buffered.ptr, .len = buffered.len };
1729 len += 1;
1730 }
1731 for (data[0 .. data.len - 1]) |d| {
1732 if (d.len == 0) continue;
1733 iovecs[len] = .{ .base = d.ptr, .len = d.len };
1734 len += 1;
1735 if (iovecs.len - len == 0) break;
1736 }
1737 const pattern = data[data.len - 1];
1738 if (iovecs.len - len != 0) switch (splat) {
1739 0 => {},
1740 1 => if (pattern.len != 0) {
1741 iovecs[len] = .{ .base = pattern.ptr, .len = pattern.len };
1742 len += 1;
1743 },
1744 else => switch (pattern.len) {
1745 0 => {},
1746 1 => {
1747 const splat_buffer_candidate = io_w.buffer[io_w.end..];
1748 var backup_buffer: [64]u8 = undefined;
1749 const splat_buffer = if (splat_buffer_candidate.len >= backup_buffer.len)
1750 splat_buffer_candidate
1751 else
1752 &backup_buffer;
1753 const memset_len = @min(splat_buffer.len, splat);
1754 const buf = splat_buffer[0..memset_len];
1755 @memset(buf, pattern[0]);
1756 iovecs[len] = .{ .base = buf.ptr, .len = buf.len };
1757 len += 1;
1758 var remaining_splat = splat - buf.len;
1759 while (remaining_splat > splat_buffer.len and iovecs.len - len != 0) {
1760 assert(buf.len == splat_buffer.len);
1761 iovecs[len] = .{ .base = splat_buffer.ptr, .len = splat_buffer.len };
1762 len += 1;
1763 remaining_splat -= splat_buffer.len;
1764 }
1765 if (remaining_splat > 0 and iovecs.len - len != 0) {
1766 iovecs[len] = .{ .base = splat_buffer.ptr, .len = remaining_splat };
1767 len += 1;
1768 }
1769 },
1770 else => for (0..splat) |_| {
1771 iovecs[len] = .{ .base = pattern.ptr, .len = pattern.len };
1772 len += 1;
1773 if (iovecs.len - len == 0) break;
1774 },
1775 },
1776 };
1777 if (len == 0) return 0;
1778 switch (w.mode) {
1779 .positional, .positional_reading => {
1780 const n = std.posix.pwritev(handle, iovecs[0..len], w.pos) catch |err| switch (err) {
1781 error.Unseekable => {
1782 w.mode = w.mode.toStreaming();
1783 const pos = w.pos;
1784 if (pos != 0) {
1785 w.pos = 0;
1786 w.seekTo(@intCast(pos)) catch {
1787 w.mode = .failure;
1788 return error.WriteFailed;
1789 };
1790 }
1791 return 0;
1792 },
1793 else => |e| {
1794 w.err = e;
1795 return error.WriteFailed;
1796 },
1797 };
1798 w.pos += n;
1799 return io_w.consume(n);
1800 },
1801 .streaming, .streaming_reading => {
1802 const n = std.posix.writev(handle, iovecs[0..len]) catch |err| {
1803 w.err = err;
1804 return error.WriteFailed;
1805 };
1806 w.pos += n;
1807 return io_w.consume(n);
1808 },
1809 .failure => return error.WriteFailed,
1810 }
1811 }
1812
1813 pub fn sendFile(
1814 io_w: *std.io.Writer,
1815 file_reader: *Reader,
1816 limit: std.io.Limit,
1817 ) std.io.Writer.FileError!usize {
1818 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
1819 const out_fd = w.file.handle;
1820 const in_fd = file_reader.file.handle;
1821 // TODO try using copy_file_range on FreeBSD
1822 // TODO try using sendfile on macOS
1823 // TODO try using sendfile on FreeBSD
1824 if (native_os == .linux and w.mode == .streaming) sf: {
1825 // Try using sendfile on Linux.
1826 if (w.sendfile_err != null) break :sf;
1827 // Linux sendfile does not support headers.
1828 const buffered = limit.slice(file_reader.interface.buffer);
1829 if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1);
1830 const max_count = 0x7ffff000; // Avoid EINVAL.
1831 var off: std.os.linux.off_t = undefined;
1832 const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) {
1833 .positional => o: {
1834 const size = file_reader.size orelse {
1835 if (file_reader.file.getEndPos()) |size| {
1836 file_reader.size = size;
1837 } else |err| {
1838 file_reader.size_err = err;
1839 file_reader.mode = .streaming;
1840 }
1841 return 0;
1842 };
1843 off = std.math.cast(std.os.linux.off_t, file_reader.pos) orelse return error.ReadFailed;
1844 break :o .{ &off, @min(@intFromEnum(limit), size - file_reader.pos, max_count) };
1845 },
1846 .streaming => .{ null, limit.minInt(max_count) },
1847 .streaming_reading, .positional_reading => break :sf,
1848 .failure => return error.ReadFailed,
1849 };
1850 const n = std.os.linux.wrapped.sendfile(out_fd, in_fd, off_ptr, count) catch |err| switch (err) {
1851 error.Unseekable => {
1852 file_reader.mode = file_reader.mode.toStreaming();
1853 const pos = file_reader.pos;
1854 if (pos != 0) {
1855 file_reader.pos = 0;
1856 file_reader.seekBy(@intCast(pos)) catch {
1857 file_reader.mode = .failure;
1858 return error.ReadFailed;
1859 };
1860 }
1861 return 0;
1862 },
1863 else => |e| {
1864 w.sendfile_err = e;
1865 return 0;
1866 },
1867 };
1868 if (n == 0) {
1869 file_reader.size = file_reader.pos;
1870 return error.EndOfStream;
1871 }
1872 file_reader.pos += n;
1873 w.pos += n;
1874 return n;
1875 }
1876 const copy_file_range = switch (native_os) {
1877 .freebsd => std.os.freebsd.copy_file_range,
1878 .linux => if (std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 })) std.os.linux.wrapped.copy_file_range else {},
1879 else => {},
1880 };
1881 if (@TypeOf(copy_file_range) != void) cfr: {
1882 if (w.copy_file_range_err != null) break :cfr;
1883 const buffered = limit.slice(file_reader.interface.buffer);
1884 if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1);
1885 var off_in: i64 = undefined;
1886 var off_out: i64 = undefined;
1887 const off_in_ptr: ?*i64 = switch (file_reader.mode) {
1888 .positional_reading, .streaming_reading => return error.Unimplemented,
1889 .positional => p: {
1890 off_in = @intCast(file_reader.pos);
1891 break :p &off_in;
1892 },
1893 .streaming => null,
1894 .failure => return error.WriteFailed,
1895 };
1896 const off_out_ptr: ?*i64 = switch (w.mode) {
1897 .positional_reading, .streaming_reading => return error.Unimplemented,
1898 .positional => p: {
1899 off_out = @intCast(w.pos);
1900 break :p &off_out;
1901 },
1902 .streaming => null,
1903 .failure => return error.WriteFailed,
1904 };
1905 const n = copy_file_range(in_fd, off_in_ptr, out_fd, off_out_ptr, @intFromEnum(limit), 0) catch |err| {
1906 w.copy_file_range_err = err;
1907 return 0;
1908 };
1909 if (n == 0) {
1910 file_reader.size = file_reader.pos;
1911 return error.EndOfStream;
1912 }
1913 file_reader.pos += n;
1914 w.pos += n;
1915 return n;
1916 }
1917
1918 if (builtin.os.tag.isDarwin()) fcf: {
1919 if (w.fcopyfile_err != null) break :fcf;
1920 if (file_reader.pos != 0) break :fcf;
1921 if (w.pos != 0) break :fcf;
1922 if (limit != .unlimited) break :fcf;
1923 const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true });
1924 switch (posix.errno(rc)) {
1925 .SUCCESS => {},
1926 .INVAL => if (builtin.mode == .Debug) @panic("invalid API usage") else {
1927 w.fcopyfile_err = error.Unexpected;
1928 return 0;
1929 },
1930 .NOMEM => {
1931 w.fcopyfile_err = error.OutOfMemory;
1932 return 0;
1933 },
1934 .OPNOTSUPP => {
1935 w.fcopyfile_err = error.OperationNotSupported;
1936 return 0;
1937 },
1938 else => |err| {
1939 w.fcopyfile_err = posix.unexpectedErrno(err);
1940 return 0;
1941 },
1942 }
1943 const n = if (file_reader.size) |size| size else @panic("TODO figure out how much copied");
1944 file_reader.pos = n;
1945 w.pos = n;
1946 return n;
1947 }
1948
1949 return error.Unimplemented;
1950 }
1951
1952 pub fn seekTo(w: *Writer, offset: u64) SeekError!void {
1953 switch (w.mode) {
1954 .positional, .positional_reading => {
1955 w.pos = offset;
1956 },
1957 .streaming, .streaming_reading => {
1958 if (w.seek_err) |err| return err;
1959 posix.lseek_SET(w.file.handle, offset) catch |err| {
1960 w.seek_err = err;
1961 return err;
1962 };
1963 w.pos = offset;
1964 },
1965 .failure => return w.seek_err.?,
1966 }
1967 }
1968
1969 pub const EndError = SetEndPosError || std.io.Writer.Error;
1970
1971 /// Flushes any buffered data and sets the end position of the file.
1972 ///
1973 /// If not overwriting existing contents, then calling `interface.flush`
1974 /// directly is sufficient.
1975 ///
1976 /// Flush failure is handled by setting `err` so that it can be handled
1977 /// along with other write failures.
1978 pub fn end(w: *Writer) EndError!void {
1979 try w.interface.flush();
1980 return w.file.setEndPos(w.pos);
1981 }
1982};
1983
1984/// Defaults to positional reading; falls back to streaming.
1985///
1986/// Positional is more threadsafe, since the global seek position is not
1987/// affected.
1988pub fn reader(file: File, buffer: []u8) Reader {
1989 return .init(file, buffer);
1990}
1991
1992/// Positional is more threadsafe, since the global seek position is not
1993/// affected, but when such syscalls are not available, preemptively choosing
1994/// `Reader.Mode.streaming` will skip a failed syscall.
1995pub fn readerStreaming(file: File, buffer: []u8) Reader {
1996 return .{
1997 .file = file,
1998 .interface = Reader.initInterface(buffer),
1999 .mode = .streaming,
2000 .seek_err = error.Unseekable,
2001 };
2002}
2003
2004/// Defaults to positional reading; falls back to streaming.
2005///
2006/// Positional is more threadsafe, since the global seek position is not
2007/// affected.
2008pub fn writer(file: File, buffer: []u8) Writer {
2009 return .init(file, buffer);
2010}
2011
2012/// Positional is more threadsafe, since the global seek position is not
2013/// affected, but when such syscalls are not available, preemptively choosing
2014/// `Writer.Mode.streaming` will skip a failed syscall.
2015pub fn writerStreaming(file: File, buffer: []u8) Writer {
2016 return .initMode(file, buffer, .streaming);
2017}
2018
16102019const range_off: windows.LARGE_INTEGER = 0;
16112020const range_len: windows.LARGE_INTEGER = 1;
16122021
......@@ -1769,18 +2178,3 @@ pub fn downgradeLock(file: File) LockError!void {
17692178 };
17702179 }
17712180}
1772
1773const File = @This();
1774const std = @import("../std.zig");
1775const builtin = @import("builtin");
1776const Allocator = std.mem.Allocator;
1777const posix = std.posix;
1778const io = std.io;
1779const math = std.math;
1780const assert = std.debug.assert;
1781const linux = std.os.linux;
1782const windows = std.os.windows;
1783const Os = std.builtin.Os;
1784const maxInt = std.math.maxInt;
1785const is_windows = builtin.os.tag == .windows;
1786const Alignment = std.mem.Alignment;
lib/std/fs/path.zig+2-5
......@@ -146,14 +146,11 @@ pub fn joinZ(allocator: Allocator, paths: []const []const u8) ![:0]u8 {
146146 return out[0 .. out.len - 1 :0];
147147}
148148
149pub fn fmtJoin(paths: []const []const u8) std.fmt.Formatter(formatJoin) {
149pub fn fmtJoin(paths: []const []const u8) std.fmt.Formatter([]const []const u8, formatJoin) {
150150 return .{ .data = paths };
151151}
152152
153fn formatJoin(paths: []const []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, w: anytype) !void {
154 _ = fmt;
155 _ = options;
156
153fn formatJoin(paths: []const []const u8, w: *std.io.Writer) std.io.Writer.Error!void {
157154 const first_path_idx = for (paths, 0..) |p, idx| {
158155 if (p.len != 0) break idx;
159156 } else return;
lib/std/fs/test.zig+2-109
......@@ -1798,11 +1798,11 @@ test "walker" {
17981798 var num_walked: usize = 0;
17991799 while (try walker.next()) |entry| {
18001800 testing.expect(expected_basenames.has(entry.basename)) catch |err| {
1801 std.debug.print("found unexpected basename: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.basename)});
1801 std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)});
18021802 return err;
18031803 };
18041804 testing.expect(expected_paths.has(entry.path)) catch |err| {
1805 std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)});
1805 std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)});
18061806 return err;
18071807 };
18081808 // make sure that the entry.dir is the containing dir
......@@ -1953,113 +1953,6 @@ test "chown" {
19531953 try dir.chown(null, null);
19541954}
19551955
1956test "File.Metadata" {
1957 var tmp = tmpDir(.{});
1958 defer tmp.cleanup();
1959
1960 const file = try tmp.dir.createFile("test_file", .{ .read = true });
1961 defer file.close();
1962
1963 const metadata = try file.metadata();
1964 try testing.expectEqual(File.Kind.file, metadata.kind());
1965 try testing.expectEqual(@as(u64, 0), metadata.size());
1966 _ = metadata.accessed();
1967 _ = metadata.modified();
1968 _ = metadata.created();
1969}
1970
1971test "File.Permissions" {
1972 if (native_os == .wasi)
1973 return error.SkipZigTest;
1974
1975 var tmp = tmpDir(.{});
1976 defer tmp.cleanup();
1977
1978 const file = try tmp.dir.createFile("test_file", .{ .read = true });
1979 defer file.close();
1980
1981 const metadata = try file.metadata();
1982 var permissions = metadata.permissions();
1983
1984 try testing.expect(!permissions.readOnly());
1985 permissions.setReadOnly(true);
1986 try testing.expect(permissions.readOnly());
1987
1988 try file.setPermissions(permissions);
1989 const new_permissions = (try file.metadata()).permissions();
1990 try testing.expect(new_permissions.readOnly());
1991
1992 // Must be set to non-read-only to delete
1993 permissions.setReadOnly(false);
1994 try file.setPermissions(permissions);
1995}
1996
1997test "File.PermissionsUnix" {
1998 if (native_os == .windows or native_os == .wasi)
1999 return error.SkipZigTest;
2000
2001 var tmp = tmpDir(.{});
2002 defer tmp.cleanup();
2003
2004 const file = try tmp.dir.createFile("test_file", .{ .mode = 0o666, .read = true });
2005 defer file.close();
2006
2007 const metadata = try file.metadata();
2008 var permissions = metadata.permissions();
2009
2010 permissions.setReadOnly(true);
2011 try testing.expect(permissions.readOnly());
2012 try testing.expect(!permissions.inner.unixHas(.user, .write));
2013 permissions.inner.unixSet(.user, .{ .write = true });
2014 try testing.expect(!permissions.readOnly());
2015 try testing.expect(permissions.inner.unixHas(.user, .write));
2016 try testing.expect(permissions.inner.mode & 0o400 != 0);
2017
2018 permissions.setReadOnly(true);
2019 try file.setPermissions(permissions);
2020 permissions = (try file.metadata()).permissions();
2021 try testing.expect(permissions.readOnly());
2022
2023 // Must be set to non-read-only to delete
2024 permissions.setReadOnly(false);
2025 try file.setPermissions(permissions);
2026
2027 const permissions_unix = File.PermissionsUnix.unixNew(0o754);
2028 try testing.expect(permissions_unix.unixHas(.user, .execute));
2029 try testing.expect(!permissions_unix.unixHas(.other, .execute));
2030}
2031
2032test "delete a read-only file on windows" {
2033 if (native_os != .windows)
2034 return error.SkipZigTest;
2035
2036 var tmp = testing.tmpDir(.{});
2037 defer tmp.cleanup();
2038
2039 const file = try tmp.dir.createFile("test_file", .{ .read = true });
2040 defer file.close();
2041 // Create a file and make it read-only
2042 const metadata = try file.metadata();
2043 var permissions = metadata.permissions();
2044 permissions.setReadOnly(true);
2045 try file.setPermissions(permissions);
2046
2047 // If the OS and filesystem support it, POSIX_SEMANTICS and IGNORE_READONLY_ATTRIBUTE
2048 // is used meaning that the deletion of a read-only file will succeed.
2049 // Otherwise, this delete will fail and the read-only flag must be unset before it's
2050 // able to be deleted.
2051 const delete_result = tmp.dir.deleteFile("test_file");
2052 if (delete_result) {
2053 try testing.expectError(error.FileNotFound, tmp.dir.deleteFile("test_file"));
2054 } else |err| {
2055 try testing.expectEqual(@as(anyerror, error.AccessDenied), err);
2056 // Now make the file not read-only
2057 permissions.setReadOnly(false);
2058 try file.setPermissions(permissions);
2059 try tmp.dir.deleteFile("test_file");
2060 }
2061}
2062
20631956test "delete a setAsCwd directory on Windows" {
20641957 if (native_os != .windows) return error.SkipZigTest;
20651958
lib/std/hash/benchmark.zig+1-1
......@@ -346,7 +346,7 @@ fn mode(comptime x: comptime_int) comptime_int {
346346}
347347
348348pub fn main() !void {
349 const stdout = std.io.getStdOut().writer();
349 const stdout = std.fs.File.stdout().deprecatedWriter();
350350
351351 var buffer: [1024]u8 = undefined;
352352 var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]);
lib/std/heap/debug_allocator.zig+10-10
......@@ -436,7 +436,7 @@ pub fn DebugAllocator(comptime config: Config) type {
436436 const stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc);
437437 const page_addr = @intFromPtr(bucket) & ~(page_size - 1);
438438 const addr = page_addr + slot_index * size_class;
439 log.err("memory address 0x{x} leaked: {}", .{ addr, stack_trace });
439 log.err("memory address 0x{x} leaked: {f}", .{ addr, stack_trace });
440440 leaks = true;
441441 }
442442 }
......@@ -463,7 +463,7 @@ pub fn DebugAllocator(comptime config: Config) type {
463463 while (it.next()) |large_alloc| {
464464 if (config.retain_metadata and large_alloc.freed) continue;
465465 const stack_trace = large_alloc.getStackTrace(.alloc);
466 log.err("memory address 0x{x} leaked: {}", .{
466 log.err("memory address 0x{x} leaked: {f}", .{
467467 @intFromPtr(large_alloc.bytes.ptr), stack_trace,
468468 });
469469 leaks = true;
......@@ -522,7 +522,7 @@ pub fn DebugAllocator(comptime config: Config) type {
522522 .index = 0,
523523 };
524524 std.debug.captureStackTrace(ret_addr, &second_free_stack_trace);
525 log.err("Double free detected. Allocation: {} First free: {} Second free: {}", .{
525 log.err("Double free detected. Allocation: {f} First free: {f} Second free: {f}", .{
526526 alloc_stack_trace, free_stack_trace, second_free_stack_trace,
527527 });
528528 }
......@@ -568,7 +568,7 @@ pub fn DebugAllocator(comptime config: Config) type {
568568 .index = 0,
569569 };
570570 std.debug.captureStackTrace(ret_addr, &free_stack_trace);
571 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{
571 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
572572 entry.value_ptr.bytes.len,
573573 old_mem.len,
574574 entry.value_ptr.getStackTrace(.alloc),
......@@ -678,7 +678,7 @@ pub fn DebugAllocator(comptime config: Config) type {
678678 .index = 0,
679679 };
680680 std.debug.captureStackTrace(ret_addr, &free_stack_trace);
681 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{
681 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
682682 entry.value_ptr.bytes.len,
683683 old_mem.len,
684684 entry.value_ptr.getStackTrace(.alloc),
......@@ -907,7 +907,7 @@ pub fn DebugAllocator(comptime config: Config) type {
907907 };
908908 std.debug.captureStackTrace(return_address, &free_stack_trace);
909909 if (old_memory.len != requested_size) {
910 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{
910 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
911911 requested_size,
912912 old_memory.len,
913913 bucketStackTrace(bucket, slot_count, slot_index, .alloc),
......@@ -915,7 +915,7 @@ pub fn DebugAllocator(comptime config: Config) type {
915915 });
916916 }
917917 if (alignment != slot_alignment) {
918 log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {} Free: {}", .{
918 log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{
919919 slot_alignment.toByteUnits(),
920920 alignment.toByteUnits(),
921921 bucketStackTrace(bucket, slot_count, slot_index, .alloc),
......@@ -1006,7 +1006,7 @@ pub fn DebugAllocator(comptime config: Config) type {
10061006 };
10071007 std.debug.captureStackTrace(return_address, &free_stack_trace);
10081008 if (memory.len != requested_size) {
1009 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{
1009 log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{
10101010 requested_size,
10111011 memory.len,
10121012 bucketStackTrace(bucket, slot_count, slot_index, .alloc),
......@@ -1014,7 +1014,7 @@ pub fn DebugAllocator(comptime config: Config) type {
10141014 });
10151015 }
10161016 if (alignment != slot_alignment) {
1017 log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {} Free: {}", .{
1017 log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{
10181018 slot_alignment.toByteUnits(),
10191019 alignment.toByteUnits(),
10201020 bucketStackTrace(bucket, slot_count, slot_index, .alloc),
......@@ -1054,7 +1054,7 @@ const TraceKind = enum {
10541054 free,
10551055};
10561056
1057const test_config = Config{};
1057const test_config: Config = .{};
10581058
10591059test "small allocations - free in same order" {
10601060 var gpa = DebugAllocator(test_config){};
lib/std/http.zig+12-8
......@@ -1,3 +1,7 @@
1const builtin = @import("builtin");
2const std = @import("std.zig");
3const assert = std.debug.assert;
4
15pub const Client = @import("http/Client.zig");
26pub const Server = @import("http/Server.zig");
37pub const protocol = @import("http/protocol.zig");
......@@ -38,8 +42,8 @@ pub const Method = enum(u64) {
3842 return x;
3943 }
4044
41 pub fn write(self: Method, w: anytype) !void {
42 const bytes = std.mem.asBytes(&@intFromEnum(self));
45 pub fn format(self: Method, w: *std.io.Writer) std.io.Writer.Error!void {
46 const bytes: []const u8 = @ptrCast(&@intFromEnum(self));
4347 const str = std.mem.sliceTo(bytes, 0);
4448 try w.writeAll(str);
4549 }
......@@ -77,7 +81,9 @@ pub const Method = enum(u64) {
7781 };
7882 }
7983
80 /// 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.
84 /// An HTTP method is idempotent if an identical request can be made once
85 /// or several times in a row with the same effect while leaving the server
86 /// in the same state.
8187 ///
8288 /// https://developer.mozilla.org/en-US/docs/Glossary/Idempotent
8389 ///
......@@ -90,7 +96,8 @@ pub const Method = enum(u64) {
9096 };
9197 }
9298
93 /// 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.
99 /// A cacheable response can be stored to be retrieved and used later,
100 /// saving a new request to the server.
94101 ///
95102 /// https://developer.mozilla.org/en-US/docs/Glossary/cacheable
96103 ///
......@@ -282,10 +289,10 @@ pub const Status = enum(u10) {
282289 }
283290};
284291
292/// compression is intentionally omitted here since it is handled in `ContentEncoding`.
285293pub const TransferEncoding = enum {
286294 chunked,
287295 none,
288 // compression is intentionally omitted here, as std.http.Client stores it as content-encoding
289296};
290297
291298pub const ContentEncoding = enum {
......@@ -308,9 +315,6 @@ pub const Header = struct {
308315 value: []const u8,
309316};
310317
311const builtin = @import("builtin");
312const std = @import("std.zig");
313
314318test {
315319 if (builtin.os.tag != .wasi) {
316320 _ = Client;
lib/std/http/Client.zig+37-24
......@@ -311,7 +311,7 @@ pub const Connection = struct {
311311 EndOfStream,
312312 };
313313
314 pub const Reader = std.io.Reader(*Connection, ReadError, read);
314 pub const Reader = std.io.GenericReader(*Connection, ReadError, read);
315315
316316 pub fn reader(conn: *Connection) Reader {
317317 return Reader{ .context = conn };
......@@ -374,7 +374,7 @@ pub const Connection = struct {
374374 UnexpectedWriteFailure,
375375 };
376376
377 pub const Writer = std.io.Writer(*Connection, WriteError, write);
377 pub const Writer = std.io.GenericWriter(*Connection, WriteError, write);
378378
379379 pub fn writer(conn: *Connection) Writer {
380380 return Writer{ .context = conn };
......@@ -823,21 +823,28 @@ pub const Request = struct {
823823 return error.UnsupportedTransferEncoding;
824824
825825 const connection = req.connection.?;
826 const w = connection.writer();
826 var connection_writer_adapter = connection.writer().adaptToNewApi();
827 const w = &connection_writer_adapter.new_interface;
828 sendAdapted(req, connection, w) catch |err| switch (err) {
829 error.WriteFailed => return connection_writer_adapter.err.?,
830 else => |e| return e,
831 };
832 }
827833
828 try req.method.write(w);
834 fn sendAdapted(req: *Request, connection: *Connection, w: *std.io.Writer) !void {
835 try req.method.format(w);
829836 try w.writeByte(' ');
830837
831838 if (req.method == .CONNECT) {
832 try req.uri.writeToStream(.{ .authority = true }, w);
839 try req.uri.writeToStream(w, .{ .authority = true });
833840 } else {
834 try req.uri.writeToStream(.{
841 try req.uri.writeToStream(w, .{
835842 .scheme = connection.proxied,
836843 .authentication = connection.proxied,
837844 .authority = connection.proxied,
838845 .path = true,
839846 .query = true,
840 }, w);
847 });
841848 }
842849 try w.writeByte(' ');
843850 try w.writeAll(@tagName(req.version));
......@@ -845,7 +852,7 @@ pub const Request = struct {
845852
846853 if (try emitOverridableHeader("host: ", req.headers.host, w)) {
847854 try w.writeAll("host: ");
848 try req.uri.writeToStream(.{ .authority = true }, w);
855 try req.uri.writeToStream(w, .{ .authority = true });
849856 try w.writeAll("\r\n");
850857 }
851858
......@@ -934,7 +941,7 @@ pub const Request = struct {
934941
935942 const TransferReadError = Connection.ReadError || proto.HeadersParser.ReadError;
936943
937 const TransferReader = std.io.Reader(*Request, TransferReadError, transferRead);
944 const TransferReader = std.io.GenericReader(*Request, TransferReadError, transferRead);
938945
939946 fn transferReader(req: *Request) TransferReader {
940947 return .{ .context = req };
......@@ -1094,7 +1101,7 @@ pub const Request = struct {
10941101 pub const ReadError = TransferReadError || proto.HeadersParser.CheckCompleteHeadError ||
10951102 error{ DecompressionFailure, InvalidTrailers };
10961103
1097 pub const Reader = std.io.Reader(*Request, ReadError, read);
1104 pub const Reader = std.io.GenericReader(*Request, ReadError, read);
10981105
10991106 pub fn reader(req: *Request) Reader {
11001107 return .{ .context = req };
......@@ -1134,7 +1141,7 @@ pub const Request = struct {
11341141
11351142 pub const WriteError = Connection.WriteError || error{ NotWriteable, MessageTooLong };
11361143
1137 pub const Writer = std.io.Writer(*Request, WriteError, write);
1144 pub const Writer = std.io.GenericWriter(*Request, WriteError, write);
11381145
11391146 pub fn writer(req: *Request) Writer {
11401147 return .{ .context = req };
......@@ -1283,26 +1290,32 @@ pub const basic_authorization = struct {
12831290 }
12841291
12851292 pub fn valueLengthFromUri(uri: Uri) usize {
1286 var stream = std.io.countingWriter(std.io.null_writer);
1287 try stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty});
1288 const user_len = stream.bytes_written;
1289 stream.bytes_written = 0;
1290 try stream.writer().print("{password}", .{uri.password orelse Uri.Component.empty});
1291 const password_len = stream.bytes_written;
1293 const user: Uri.Component = uri.user orelse .empty;
1294 const password: Uri.Component = uri.password orelse .empty;
1295
1296 var dw: std.io.Writer.Discarding = .init(&.{});
1297 user.formatUser(&dw.writer) catch unreachable; // discarding
1298 const user_len = dw.count + dw.writer.end;
1299
1300 dw.count = 0;
1301 dw.writer.end = 0;
1302 password.formatPassword(&dw.writer) catch unreachable; // discarding
1303 const password_len = dw.count + dw.writer.end;
1304
12921305 return valueLength(@intCast(user_len), @intCast(password_len));
12931306 }
12941307
12951308 pub fn value(uri: Uri, out: []u8) []u8 {
1309 const user: Uri.Component = uri.user orelse .empty;
1310 const password: Uri.Component = uri.password orelse .empty;
1311
12961312 var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
1297 var stream = std.io.fixedBufferStream(&buf);
1298 stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty}) catch
1299 unreachable;
1300 assert(stream.pos <= max_user_len);
1301 stream.writer().print(":{password}", .{uri.password orelse Uri.Component.empty}) catch
1302 unreachable;
1313 var w: std.io.Writer = .fixed(&buf);
1314 user.formatUser(&w) catch unreachable; // fixed
1315 password.formatPassword(&w) catch unreachable; // fixed
13031316
13041317 @memcpy(out[0..prefix.len], prefix);
1305 const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], stream.getWritten());
1318 const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], w.buffered());
13061319 return out[0 .. prefix.len + base64.len];
13071320 }
13081321};
lib/std/http/protocol.zig+2-2
......@@ -344,7 +344,7 @@ const MockBufferedConnection = struct {
344344 }
345345
346346 pub const ReadError = std.io.FixedBufferStream([]const u8).ReadError || error{EndOfStream};
347 pub const Reader = std.io.Reader(*MockBufferedConnection, ReadError, read);
347 pub const Reader = std.io.GenericReader(*MockBufferedConnection, ReadError, read);
348348
349349 pub fn reader(conn: *MockBufferedConnection) Reader {
350350 return Reader{ .context = conn };
......@@ -359,7 +359,7 @@ const MockBufferedConnection = struct {
359359 }
360360
361361 pub const WriteError = std.io.FixedBufferStream([]const u8).WriteError;
362 pub const Writer = std.io.Writer(*MockBufferedConnection, WriteError, write);
362 pub const Writer = std.io.GenericWriter(*MockBufferedConnection, WriteError, write);
363363
364364 pub fn writer(conn: *MockBufferedConnection) Writer {
365365 return Writer{ .context = conn };
lib/std/http/test.zig+2-4
......@@ -385,10 +385,8 @@ test "general client/server API coverage" {
385385 fn handleRequest(request: *http.Server.Request, listen_port: u16) !void {
386386 const log = std.log.scoped(.server);
387387
388 log.info("{} {s} {s}", .{
389 request.head.method,
390 @tagName(request.head.version),
391 request.head.target,
388 log.info("{f} {s} {s}", .{
389 request.head.method, @tagName(request.head.version), request.head.target,
392390 });
393391
394392 const gpa = std.testing.allocator;
lib/std/io.zig+90-42
......@@ -14,54 +14,80 @@ const File = std.fs.File;
1414const Allocator = std.mem.Allocator;
1515const Alignment = std.mem.Alignment;
1616
17fn getStdOutHandle() posix.fd_t {
18 if (is_windows) {
19 return windows.peb().ProcessParameters.hStdOutput;
17pub const Limit = enum(usize) {
18 nothing = 0,
19 unlimited = std.math.maxInt(usize),
20 _,
21
22 /// `std.math.maxInt(usize)` is interpreted to mean `.unlimited`.
23 pub fn limited(n: usize) Limit {
24 return @enumFromInt(n);
2025 }
2126
22 if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdOutHandle")) {
23 return root.os.io.getStdOutHandle();
27 /// Any value grater than `std.math.maxInt(usize)` is interpreted to mean
28 /// `.unlimited`.
29 pub fn limited64(n: u64) Limit {
30 return @enumFromInt(@min(n, std.math.maxInt(usize)));
2431 }
2532
26 return posix.STDOUT_FILENO;
27}
33 pub fn countVec(data: []const []const u8) Limit {
34 var total: usize = 0;
35 for (data) |d| total += d.len;
36 return .limited(total);
37 }
2838
29pub fn getStdOut() File {
30 return .{ .handle = getStdOutHandle() };
31}
39 pub fn min(a: Limit, b: Limit) Limit {
40 return @enumFromInt(@min(@intFromEnum(a), @intFromEnum(b)));
41 }
3242
33fn getStdErrHandle() posix.fd_t {
34 if (is_windows) {
35 return windows.peb().ProcessParameters.hStdError;
43 pub fn minInt(l: Limit, n: usize) usize {
44 return @min(n, @intFromEnum(l));
3645 }
3746
38 if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdErrHandle")) {
39 return root.os.io.getStdErrHandle();
47 pub fn minInt64(l: Limit, n: u64) usize {
48 return @min(n, @intFromEnum(l));
4049 }
4150
42 return posix.STDERR_FILENO;
43}
51 pub fn slice(l: Limit, s: []u8) []u8 {
52 return s[0..l.minInt(s.len)];
53 }
4454
45pub fn getStdErr() File {
46 return .{ .handle = getStdErrHandle() };
47}
55 pub fn sliceConst(l: Limit, s: []const u8) []const u8 {
56 return s[0..l.minInt(s.len)];
57 }
4858
49fn getStdInHandle() posix.fd_t {
50 if (is_windows) {
51 return windows.peb().ProcessParameters.hStdInput;
59 pub fn toInt(l: Limit) ?usize {
60 return switch (l) {
61 else => @intFromEnum(l),
62 .unlimited => null,
63 };
5264 }
5365
54 if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdInHandle")) {
55 return root.os.io.getStdInHandle();
66 /// Reduces a slice to account for the limit, leaving room for one extra
67 /// byte above the limit, allowing for the use case of differentiating
68 /// between end-of-stream and reaching the limit.
69 pub fn slice1(l: Limit, non_empty_buffer: []u8) []u8 {
70 assert(non_empty_buffer.len >= 1);
71 return non_empty_buffer[0..@min(@intFromEnum(l) +| 1, non_empty_buffer.len)];
5672 }
5773
58 return posix.STDIN_FILENO;
59}
74 pub fn nonzero(l: Limit) bool {
75 return @intFromEnum(l) > 0;
76 }
6077
61pub fn getStdIn() File {
62 return .{ .handle = getStdInHandle() };
63}
78 /// Return a new limit reduced by `amount` or return `null` indicating
79 /// limit would be exceeded.
80 pub fn subtract(l: Limit, amount: usize) ?Limit {
81 if (l == .unlimited) return .unlimited;
82 if (amount > @intFromEnum(l)) return null;
83 return @enumFromInt(@intFromEnum(l) - amount);
84 }
85};
86
87pub const Reader = @import("io/Reader.zig");
88pub const Writer = @import("io/Writer.zig");
6489
90/// Deprecated in favor of `Reader`.
6591pub fn GenericReader(
6692 comptime Context: type,
6793 comptime ReadError: type,
......@@ -289,6 +315,7 @@ pub fn GenericReader(
289315 };
290316}
291317
318/// Deprecated in favor of `Writer`.
292319pub fn GenericWriter(
293320 comptime Context: type,
294321 comptime WriteError: type,
......@@ -347,18 +374,39 @@ pub fn GenericWriter(
347374 const ptr: *const Context = @alignCast(@ptrCast(context));
348375 return writeFn(ptr.*, bytes);
349376 }
377
378 /// Helper for bridging to the new `Writer` API while upgrading.
379 pub fn adaptToNewApi(self: *const Self) Adapter {
380 return .{
381 .derp_writer = self.*,
382 .new_interface = .{
383 .buffer = &.{},
384 .vtable = &.{ .drain = Adapter.drain },
385 },
386 };
387 }
388
389 pub const Adapter = struct {
390 derp_writer: Self,
391 new_interface: Writer,
392 err: ?Error = null,
393
394 fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize {
395 _ = splat;
396 const a: *@This() = @fieldParentPtr("new_interface", w);
397 return a.derp_writer.write(data[0]) catch |err| {
398 a.err = err;
399 return error.WriteFailed;
400 };
401 }
402 };
350403 };
351404}
352405
353/// Deprecated; consider switching to `AnyReader` or use `GenericReader`
354/// to use previous API.
355pub const Reader = GenericReader;
356/// Deprecated; consider switching to `AnyWriter` or use `GenericWriter`
357/// to use previous API.
358pub const Writer = GenericWriter;
359
360pub const AnyReader = @import("io/Reader.zig");
361pub const AnyWriter = @import("io/Writer.zig");
406/// Deprecated in favor of `Reader`.
407pub const AnyReader = @import("io/DeprecatedReader.zig");
408/// Deprecated in favor of `Writer`.
409pub const AnyWriter = @import("io/DeprecatedWriter.zig");
362410
363411pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
364412
......@@ -407,7 +455,7 @@ pub const tty = @import("io/tty.zig");
407455/// A Writer that doesn't write to anything.
408456pub const null_writer: NullWriter = .{ .context = {} };
409457
410pub const NullWriter = Writer(void, error{}, dummyWrite);
458pub const NullWriter = GenericWriter(void, error{}, dummyWrite);
411459fn dummyWrite(context: void, data: []const u8) error{}!usize {
412460 _ = context;
413461 return data.len;
......@@ -819,8 +867,8 @@ pub fn PollFiles(comptime StreamEnum: type) type {
819867}
820868
821869test {
822 _ = AnyReader;
823 _ = AnyWriter;
870 _ = Reader;
871 _ = Writer;
824872 _ = @import("io/bit_reader.zig");
825873 _ = @import("io/bit_writer.zig");
826874 _ = @import("io/buffered_atomic_file.zig");
lib/std/io/DeprecatedReader.zig created+386
......@@ -0,0 +1,386 @@
1context: *const anyopaque,
2readFn: *const fn (context: *const anyopaque, buffer: []u8) anyerror!usize,
3
4pub const Error = anyerror;
5
6/// Returns the number of bytes read. It may be less than buffer.len.
7/// If the number of bytes read is 0, it means end of stream.
8/// End of stream is not an error condition.
9pub fn read(self: Self, buffer: []u8) anyerror!usize {
10 return self.readFn(self.context, buffer);
11}
12
13/// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
14/// means the stream reached the end. Reaching the end of a stream is not an error
15/// condition.
16pub fn readAll(self: Self, buffer: []u8) anyerror!usize {
17 return readAtLeast(self, buffer, buffer.len);
18}
19
20/// Returns the number of bytes read, calling the underlying read
21/// function the minimal number of times until the buffer has at least
22/// `len` bytes filled. If the number read is less than `len` it means
23/// the stream reached the end. Reaching the end of the stream is not
24/// an error condition.
25pub fn readAtLeast(self: Self, buffer: []u8, len: usize) anyerror!usize {
26 assert(len <= buffer.len);
27 var index: usize = 0;
28 while (index < len) {
29 const amt = try self.read(buffer[index..]);
30 if (amt == 0) break;
31 index += amt;
32 }
33 return index;
34}
35
36/// If the number read would be smaller than `buf.len`, `error.EndOfStream` is returned instead.
37pub fn readNoEof(self: Self, buf: []u8) anyerror!void {
38 const amt_read = try self.readAll(buf);
39 if (amt_read < buf.len) return error.EndOfStream;
40}
41
42/// Appends to the `std.ArrayList` contents by reading from the stream
43/// until end of stream is found.
44/// If the number of bytes appended would exceed `max_append_size`,
45/// `error.StreamTooLong` is returned
46/// and the `std.ArrayList` has exactly `max_append_size` bytes appended.
47pub fn readAllArrayList(
48 self: Self,
49 array_list: *std.ArrayList(u8),
50 max_append_size: usize,
51) anyerror!void {
52 return self.readAllArrayListAligned(null, array_list, max_append_size);
53}
54
55pub fn readAllArrayListAligned(
56 self: Self,
57 comptime alignment: ?Alignment,
58 array_list: *std.ArrayListAligned(u8, alignment),
59 max_append_size: usize,
60) anyerror!void {
61 try array_list.ensureTotalCapacity(@min(max_append_size, 4096));
62 const original_len = array_list.items.len;
63 var start_index: usize = original_len;
64 while (true) {
65 array_list.expandToCapacity();
66 const dest_slice = array_list.items[start_index..];
67 const bytes_read = try self.readAll(dest_slice);
68 start_index += bytes_read;
69
70 if (start_index - original_len > max_append_size) {
71 array_list.shrinkAndFree(original_len + max_append_size);
72 return error.StreamTooLong;
73 }
74
75 if (bytes_read != dest_slice.len) {
76 array_list.shrinkAndFree(start_index);
77 return;
78 }
79
80 // This will trigger ArrayList to expand superlinearly at whatever its growth rate is.
81 try array_list.ensureTotalCapacity(start_index + 1);
82 }
83}
84
85/// Allocates enough memory to hold all the contents of the stream. If the allocated
86/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
87/// Caller owns returned memory.
88/// If this function returns an error, the contents from the stream read so far are lost.
89pub fn readAllAlloc(self: Self, allocator: mem.Allocator, max_size: usize) anyerror![]u8 {
90 var array_list = std.ArrayList(u8).init(allocator);
91 defer array_list.deinit();
92 try self.readAllArrayList(&array_list, max_size);
93 return try array_list.toOwnedSlice();
94}
95
96/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.
97/// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found.
98/// Does not include the delimiter in the result.
99/// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the
100/// `std.ArrayList` is populated with `max_size` bytes from the stream.
101pub fn readUntilDelimiterArrayList(
102 self: Self,
103 array_list: *std.ArrayList(u8),
104 delimiter: u8,
105 max_size: usize,
106) anyerror!void {
107 array_list.shrinkRetainingCapacity(0);
108 try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size);
109}
110
111/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.
112/// Allocates enough memory to read until `delimiter`. If the allocated
113/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
114/// Caller owns returned memory.
115/// If this function returns an error, the contents from the stream read so far are lost.
116pub fn readUntilDelimiterAlloc(
117 self: Self,
118 allocator: mem.Allocator,
119 delimiter: u8,
120 max_size: usize,
121) anyerror![]u8 {
122 var array_list = std.ArrayList(u8).init(allocator);
123 defer array_list.deinit();
124 try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size);
125 return try array_list.toOwnedSlice();
126}
127
128/// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead.
129/// Reads from the stream until specified byte is found. If the buffer is not
130/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
131/// If end-of-stream is found, `error.EndOfStream` is returned.
132/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
133/// delimiter byte is written to the output buffer but is not included
134/// in the returned slice.
135pub fn readUntilDelimiter(self: Self, buf: []u8, delimiter: u8) anyerror![]u8 {
136 var fbs = std.io.fixedBufferStream(buf);
137 try self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len);
138 const output = fbs.getWritten();
139 buf[output.len] = delimiter; // emulating old behaviour
140 return output;
141}
142
143/// Deprecated: use `streamUntilDelimiter` with ArrayList's (or any other's) writer instead.
144/// Allocates enough memory to read until `delimiter` or end-of-stream.
145/// If the allocated memory would be greater than `max_size`, returns
146/// `error.StreamTooLong`. If end-of-stream is found, returns the rest
147/// of the stream. If this function is called again after that, returns
148/// null.
149/// Caller owns returned memory.
150/// If this function returns an error, the contents from the stream read so far are lost.
151pub fn readUntilDelimiterOrEofAlloc(
152 self: Self,
153 allocator: mem.Allocator,
154 delimiter: u8,
155 max_size: usize,
156) anyerror!?[]u8 {
157 var array_list = std.ArrayList(u8).init(allocator);
158 defer array_list.deinit();
159 self.streamUntilDelimiter(array_list.writer(), delimiter, max_size) catch |err| switch (err) {
160 error.EndOfStream => if (array_list.items.len == 0) {
161 return null;
162 },
163 else => |e| return e,
164 };
165 return try array_list.toOwnedSlice();
166}
167
168/// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead.
169/// Reads from the stream until specified byte is found. If the buffer is not
170/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
171/// If end-of-stream is found, returns the rest of the stream. If this
172/// function is called again after that, returns null.
173/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
174/// delimiter byte is written to the output buffer but is not included
175/// in the returned slice.
176pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) anyerror!?[]u8 {
177 var fbs = std.io.fixedBufferStream(buf);
178 self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len) catch |err| switch (err) {
179 error.EndOfStream => if (fbs.getWritten().len == 0) {
180 return null;
181 },
182
183 else => |e| return e,
184 };
185 const output = fbs.getWritten();
186 buf[output.len] = delimiter; // emulating old behaviour
187 return output;
188}
189
190/// Appends to the `writer` contents by reading from the stream until `delimiter` is found.
191/// Does not write the delimiter itself.
192/// If `optional_max_size` is not null and amount of written bytes exceeds `optional_max_size`,
193/// returns `error.StreamTooLong` and finishes appending.
194/// If `optional_max_size` is null, appending is unbounded.
195pub fn streamUntilDelimiter(
196 self: Self,
197 writer: anytype,
198 delimiter: u8,
199 optional_max_size: ?usize,
200) anyerror!void {
201 if (optional_max_size) |max_size| {
202 for (0..max_size) |_| {
203 const byte: u8 = try self.readByte();
204 if (byte == delimiter) return;
205 try writer.writeByte(byte);
206 }
207 return error.StreamTooLong;
208 } else {
209 while (true) {
210 const byte: u8 = try self.readByte();
211 if (byte == delimiter) return;
212 try writer.writeByte(byte);
213 }
214 // Can not throw `error.StreamTooLong` since there are no boundary.
215 }
216}
217
218/// Reads from the stream until specified byte is found, discarding all data,
219/// including the delimiter.
220/// If end-of-stream is found, this function succeeds.
221pub fn skipUntilDelimiterOrEof(self: Self, delimiter: u8) anyerror!void {
222 while (true) {
223 const byte = self.readByte() catch |err| switch (err) {
224 error.EndOfStream => return,
225 else => |e| return e,
226 };
227 if (byte == delimiter) return;
228 }
229}
230
231/// Reads 1 byte from the stream or returns `error.EndOfStream`.
232pub fn readByte(self: Self) anyerror!u8 {
233 var result: [1]u8 = undefined;
234 const amt_read = try self.read(result[0..]);
235 if (amt_read < 1) return error.EndOfStream;
236 return result[0];
237}
238
239/// Same as `readByte` except the returned byte is signed.
240pub fn readByteSigned(self: Self) anyerror!i8 {
241 return @as(i8, @bitCast(try self.readByte()));
242}
243
244/// Reads exactly `num_bytes` bytes and returns as an array.
245/// `num_bytes` must be comptime-known
246pub fn readBytesNoEof(self: Self, comptime num_bytes: usize) anyerror![num_bytes]u8 {
247 var bytes: [num_bytes]u8 = undefined;
248 try self.readNoEof(&bytes);
249 return bytes;
250}
251
252/// Reads bytes until `bounded.len` is equal to `num_bytes`,
253/// or the stream ends.
254///
255/// * it is assumed that `num_bytes` will not exceed `bounded.capacity()`
256pub fn readIntoBoundedBytes(
257 self: Self,
258 comptime num_bytes: usize,
259 bounded: *std.BoundedArray(u8, num_bytes),
260) anyerror!void {
261 while (bounded.len < num_bytes) {
262 // get at most the number of bytes free in the bounded array
263 const bytes_read = try self.read(bounded.unusedCapacitySlice());
264 if (bytes_read == 0) return;
265
266 // bytes_read will never be larger than @TypeOf(bounded.len)
267 // due to `self.read` being bounded by `bounded.unusedCapacitySlice()`
268 bounded.len += @as(@TypeOf(bounded.len), @intCast(bytes_read));
269 }
270}
271
272/// Reads at most `num_bytes` and returns as a bounded array.
273pub fn readBoundedBytes(self: Self, comptime num_bytes: usize) anyerror!std.BoundedArray(u8, num_bytes) {
274 var result = std.BoundedArray(u8, num_bytes){};
275 try self.readIntoBoundedBytes(num_bytes, &result);
276 return result;
277}
278
279pub inline fn readInt(self: Self, comptime T: type, endian: std.builtin.Endian) anyerror!T {
280 const bytes = try self.readBytesNoEof(@divExact(@typeInfo(T).int.bits, 8));
281 return mem.readInt(T, &bytes, endian);
282}
283
284pub fn readVarInt(
285 self: Self,
286 comptime ReturnType: type,
287 endian: std.builtin.Endian,
288 size: usize,
289) anyerror!ReturnType {
290 assert(size <= @sizeOf(ReturnType));
291 var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
292 const bytes = bytes_buf[0..size];
293 try self.readNoEof(bytes);
294 return mem.readVarInt(ReturnType, bytes, endian);
295}
296
297/// Optional parameters for `skipBytes`
298pub const SkipBytesOptions = struct {
299 buf_size: usize = 512,
300};
301
302// `num_bytes` is a `u64` to match `off_t`
303/// Reads `num_bytes` bytes from the stream and discards them
304pub fn skipBytes(self: Self, num_bytes: u64, comptime options: SkipBytesOptions) anyerror!void {
305 var buf: [options.buf_size]u8 = undefined;
306 var remaining = num_bytes;
307
308 while (remaining > 0) {
309 const amt = @min(remaining, options.buf_size);
310 try self.readNoEof(buf[0..amt]);
311 remaining -= amt;
312 }
313}
314
315/// Reads `slice.len` bytes from the stream and returns if they are the same as the passed slice
316pub fn isBytes(self: Self, slice: []const u8) anyerror!bool {
317 var i: usize = 0;
318 var matches = true;
319 while (i < slice.len) : (i += 1) {
320 if (slice[i] != try self.readByte()) {
321 matches = false;
322 }
323 }
324 return matches;
325}
326
327pub fn readStruct(self: Self, comptime T: type) anyerror!T {
328 // Only extern and packed structs have defined in-memory layout.
329 comptime assert(@typeInfo(T).@"struct".layout != .auto);
330 var res: [1]T = undefined;
331 try self.readNoEof(mem.sliceAsBytes(res[0..]));
332 return res[0];
333}
334
335pub fn readStructEndian(self: Self, comptime T: type, endian: std.builtin.Endian) anyerror!T {
336 var res = try self.readStruct(T);
337 if (native_endian != endian) {
338 mem.byteSwapAllFields(T, &res);
339 }
340 return res;
341}
342
343/// Reads an integer with the same size as the given enum's tag type. If the integer matches
344/// an enum tag, casts the integer to the enum tag and returns it. Otherwise, returns an `error.InvalidValue`.
345/// TODO optimization taking advantage of most fields being in order
346pub fn readEnum(self: Self, comptime Enum: type, endian: std.builtin.Endian) anyerror!Enum {
347 const E = error{
348 /// An integer was read, but it did not match any of the tags in the supplied enum.
349 InvalidValue,
350 };
351 const type_info = @typeInfo(Enum).@"enum";
352 const tag = try self.readInt(type_info.tag_type, endian);
353
354 inline for (std.meta.fields(Enum)) |field| {
355 if (tag == field.value) {
356 return @field(Enum, field.name);
357 }
358 }
359
360 return E.InvalidValue;
361}
362
363/// Reads the stream until the end, ignoring all the data.
364/// Returns the number of bytes discarded.
365pub fn discard(self: Self) anyerror!u64 {
366 var trash: [4096]u8 = undefined;
367 var index: u64 = 0;
368 while (true) {
369 const n = try self.read(&trash);
370 if (n == 0) return index;
371 index += n;
372 }
373}
374
375const std = @import("../std.zig");
376const Self = @This();
377const math = std.math;
378const assert = std.debug.assert;
379const mem = std.mem;
380const testing = std.testing;
381const native_endian = @import("builtin").target.cpu.arch.endian();
382const Alignment = std.mem.Alignment;
383
384test {
385 _ = @import("Reader/test.zig");
386}
lib/std/io/DeprecatedWriter.zig created+109
......@@ -0,0 +1,109 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const native_endian = @import("builtin").target.cpu.arch.endian();
5
6context: *const anyopaque,
7writeFn: *const fn (context: *const anyopaque, bytes: []const u8) anyerror!usize,
8
9const Self = @This();
10pub const Error = anyerror;
11
12pub fn write(self: Self, bytes: []const u8) anyerror!usize {
13 return self.writeFn(self.context, bytes);
14}
15
16pub fn writeAll(self: Self, bytes: []const u8) anyerror!void {
17 var index: usize = 0;
18 while (index != bytes.len) {
19 index += try self.write(bytes[index..]);
20 }
21}
22
23pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void {
24 return std.fmt.format(self, format, args);
25}
26
27pub fn writeByte(self: Self, byte: u8) anyerror!void {
28 const array = [1]u8{byte};
29 return self.writeAll(&array);
30}
31
32pub fn writeByteNTimes(self: Self, byte: u8, n: usize) anyerror!void {
33 var bytes: [256]u8 = undefined;
34 @memset(bytes[0..], byte);
35
36 var remaining: usize = n;
37 while (remaining > 0) {
38 const to_write = @min(remaining, bytes.len);
39 try self.writeAll(bytes[0..to_write]);
40 remaining -= to_write;
41 }
42}
43
44pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) anyerror!void {
45 var i: usize = 0;
46 while (i < n) : (i += 1) {
47 try self.writeAll(bytes);
48 }
49}
50
51pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void {
52 var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined;
53 mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
54 return self.writeAll(&bytes);
55}
56
57pub fn writeStruct(self: Self, value: anytype) anyerror!void {
58 // Only extern and packed structs have defined in-memory layout.
59 comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto);
60 return self.writeAll(mem.asBytes(&value));
61}
62
63pub fn writeStructEndian(self: Self, value: anytype, endian: std.builtin.Endian) anyerror!void {
64 // TODO: make sure this value is not a reference type
65 if (native_endian == endian) {
66 return self.writeStruct(value);
67 } else {
68 var copy = value;
69 mem.byteSwapAllFields(@TypeOf(value), &copy);
70 return self.writeStruct(copy);
71 }
72}
73
74pub fn writeFile(self: Self, file: std.fs.File) anyerror!void {
75 // TODO: figure out how to adjust std lib abstractions so that this ends up
76 // doing sendfile or maybe even copy_file_range under the right conditions.
77 var buf: [4000]u8 = undefined;
78 while (true) {
79 const n = try file.readAll(&buf);
80 try self.writeAll(buf[0..n]);
81 if (n < buf.len) return;
82 }
83}
84
85/// Helper for bridging to the new `Writer` API while upgrading.
86pub fn adaptToNewApi(self: *const Self) Adapter {
87 return .{
88 .derp_writer = self.*,
89 .new_interface = .{
90 .buffer = &.{},
91 .vtable = &.{ .drain = Adapter.drain },
92 },
93 };
94}
95
96pub const Adapter = struct {
97 derp_writer: Self,
98 new_interface: std.io.Writer,
99 err: ?Error = null,
100
101 fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
102 _ = splat;
103 const a: *@This() = @fieldParentPtr("new_interface", w);
104 return a.derp_writer.write(data[0]) catch |err| {
105 a.err = err;
106 return error.WriteFailed;
107 };
108 }
109};
lib/std/io/Reader.zig+1660-315
......@@ -1,386 +1,1731 @@
1context: *const anyopaque,
2readFn: *const fn (context: *const anyopaque, buffer: []u8) anyerror!usize,
1const Reader = @This();
32
4pub const Error = anyerror;
3const builtin = @import("builtin");
4const native_endian = builtin.target.cpu.arch.endian();
55
6/// Returns the number of bytes read. It may be less than buffer.len.
7/// If the number of bytes read is 0, it means end of stream.
8/// End of stream is not an error condition.
9pub fn read(self: Self, buffer: []u8) anyerror!usize {
10 return self.readFn(self.context, buffer);
6const std = @import("../std.zig");
7const Writer = std.io.Writer;
8const assert = std.debug.assert;
9const testing = std.testing;
10const Allocator = std.mem.Allocator;
11const ArrayList = std.ArrayListUnmanaged;
12const Limit = std.io.Limit;
13
14pub const Limited = @import("Reader/Limited.zig");
15
16vtable: *const VTable,
17buffer: []u8,
18/// Number of bytes which have been consumed from `buffer`.
19seek: usize,
20/// In `buffer` before this are buffered bytes, after this is `undefined`.
21end: usize,
22
23pub const VTable = struct {
24 /// Writes bytes from the internally tracked logical position to `w`.
25 ///
26 /// Returns the number of bytes written, which will be at minimum `0` and
27 /// at most `limit`. The number returned, including zero, does not indicate
28 /// end of stream. `limit` is guaranteed to be at least as large as the
29 /// buffer capacity of `w`, a value whose minimum size is determined by the
30 /// stream implementation.
31 ///
32 /// The reader's internal logical seek position moves forward in accordance
33 /// with the number of bytes returned from this function.
34 ///
35 /// Implementations are encouraged to utilize mandatory minimum buffer
36 /// sizes combined with short reads (returning a value less than `limit`)
37 /// in order to minimize complexity.
38 ///
39 /// Although this function is usually called when `buffer` is empty, it is
40 /// also called when it needs to be filled more due to the API user
41 /// requesting contiguous memory. In either case, the existing buffer data
42 /// should be ignored; new data written to `w`.
43 ///
44 /// In addition to, or instead of writing to `w`, the implementation may
45 /// choose to store data in `buffer`, modifying `seek` and `end`
46 /// accordingly. Stream implementations are encouraged to take advantage of
47 /// this if simplifies the logic.
48 stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize,
49
50 /// Consumes bytes from the internally tracked stream position without
51 /// providing access to them.
52 ///
53 /// Returns the number of bytes discarded, which will be at minimum `0` and
54 /// at most `limit`. The number of bytes returned, including zero, does not
55 /// indicate end of stream.
56 ///
57 /// The reader's internal logical seek position moves forward in accordance
58 /// with the number of bytes returned from this function.
59 ///
60 /// Implementations are encouraged to utilize mandatory minimum buffer
61 /// sizes combined with short reads (returning a value less than `limit`)
62 /// in order to minimize complexity.
63 ///
64 /// The default implementation is is based on calling `stream`, borrowing
65 /// `buffer` to construct a temporary `Writer` and ignoring the written
66 /// data.
67 ///
68 /// This function is only called when `buffer` is empty.
69 discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard,
70};
71
72pub const StreamError = error{
73 /// See the `Reader` implementation for detailed diagnostics.
74 ReadFailed,
75 /// See the `Writer` implementation for detailed diagnostics.
76 WriteFailed,
77 /// End of stream indicated from the `Reader`. This error cannot originate
78 /// from the `Writer`.
79 EndOfStream,
80};
81
82pub const Error = error{
83 /// See the `Reader` implementation for detailed diagnostics.
84 ReadFailed,
85 EndOfStream,
86};
87
88pub const StreamRemainingError = error{
89 /// See the `Reader` implementation for detailed diagnostics.
90 ReadFailed,
91 /// See the `Writer` implementation for detailed diagnostics.
92 WriteFailed,
93};
94
95pub const ShortError = error{
96 /// See the `Reader` implementation for detailed diagnostics.
97 ReadFailed,
98};
99
100pub const failing: Reader = .{
101 .vtable = &.{
102 .read = failingStream,
103 .discard = failingDiscard,
104 },
105 .buffer = &.{},
106 .seek = 0,
107 .end = 0,
108};
109
110/// This is generally safe to `@constCast` because it has an empty buffer, so
111/// there is not really a way to accidentally attempt mutation of these fields.
112const ending_state: Reader = .fixed(&.{});
113pub const ending: *Reader = @constCast(&ending_state);
114
115pub fn limited(r: *Reader, limit: Limit, buffer: []u8) Limited {
116 return .init(r, limit, buffer);
11117}
12118
13/// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
14/// means the stream reached the end. Reaching the end of a stream is not an error
15/// condition.
16pub fn readAll(self: Self, buffer: []u8) anyerror!usize {
17 return readAtLeast(self, buffer, buffer.len);
119/// Constructs a `Reader` such that it will read from `buffer` and then end.
120pub fn fixed(buffer: []const u8) Reader {
121 return .{
122 .vtable = &.{
123 .stream = endingStream,
124 .discard = endingDiscard,
125 },
126 // This cast is safe because all potential writes to it will instead
127 // return `error.EndOfStream`.
128 .buffer = @constCast(buffer),
129 .end = buffer.len,
130 .seek = 0,
131 };
18132}
19133
20/// Returns the number of bytes read, calling the underlying read
21/// function the minimal number of times until the buffer has at least
22/// `len` bytes filled. If the number read is less than `len` it means
23/// the stream reached the end. Reaching the end of the stream is not
24/// an error condition.
25pub fn readAtLeast(self: Self, buffer: []u8, len: usize) anyerror!usize {
26 assert(len <= buffer.len);
27 var index: usize = 0;
28 while (index < len) {
29 const amt = try self.read(buffer[index..]);
30 if (amt == 0) break;
31 index += amt;
134pub fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
135 const buffer = limit.slice(r.buffer[r.seek..r.end]);
136 if (buffer.len > 0) {
137 @branchHint(.likely);
138 const n = try w.write(buffer);
139 r.seek += n;
140 return n;
141 }
142 const n = try r.vtable.stream(r, w, limit);
143 assert(n <= @intFromEnum(limit));
144 return n;
145}
146
147pub fn discard(r: *Reader, limit: Limit) Error!usize {
148 const buffered_len = r.end - r.seek;
149 const remaining: Limit = if (limit.toInt()) |n| l: {
150 if (buffered_len >= n) {
151 r.seek += n;
152 return n;
153 }
154 break :l .limited(n - buffered_len);
155 } else .unlimited;
156 r.seek = 0;
157 r.end = 0;
158 const n = try r.vtable.discard(r, remaining);
159 assert(n <= @intFromEnum(remaining));
160 return buffered_len + n;
161}
162
163pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
164 assert(r.seek == 0);
165 assert(r.end == 0);
166 var dw: Writer.Discarding = .init(r.buffer);
167 const n = r.stream(&dw.writer, limit) catch |err| switch (err) {
168 error.WriteFailed => unreachable,
169 error.ReadFailed => return error.ReadFailed,
170 error.EndOfStream => return error.EndOfStream,
171 };
172 assert(n <= @intFromEnum(limit));
173 return n;
174}
175
176/// "Pump" exactly `n` bytes from the reader to the writer.
177pub fn streamExact(r: *Reader, w: *Writer, n: usize) StreamError!void {
178 var remaining = n;
179 while (remaining != 0) remaining -= try r.stream(w, .limited(remaining));
180}
181
182/// "Pump" data from the reader to the writer, handling `error.EndOfStream` as
183/// a success case.
184///
185/// Returns total number of bytes written to `w`.
186pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {
187 var offset: usize = 0;
188 while (true) {
189 offset += r.stream(w, .unlimited) catch |err| switch (err) {
190 error.EndOfStream => return offset,
191 else => |e| return e,
192 };
32193 }
33 return index;
34}
35
36/// If the number read would be smaller than `buf.len`, `error.EndOfStream` is returned instead.
37pub fn readNoEof(self: Self, buf: []u8) anyerror!void {
38 const amt_read = try self.readAll(buf);
39 if (amt_read < buf.len) return error.EndOfStream;
40}
41
42/// Appends to the `std.ArrayList` contents by reading from the stream
43/// until end of stream is found.
44/// If the number of bytes appended would exceed `max_append_size`,
45/// `error.StreamTooLong` is returned
46/// and the `std.ArrayList` has exactly `max_append_size` bytes appended.
47pub fn readAllArrayList(
48 self: Self,
49 array_list: *std.ArrayList(u8),
50 max_append_size: usize,
51) anyerror!void {
52 return self.readAllArrayListAligned(null, array_list, max_append_size);
53}
54
55pub fn readAllArrayListAligned(
56 self: Self,
57 comptime alignment: ?Alignment,
58 array_list: *std.ArrayListAligned(u8, alignment),
59 max_append_size: usize,
60) anyerror!void {
61 try array_list.ensureTotalCapacity(@min(max_append_size, 4096));
62 const original_len = array_list.items.len;
63 var start_index: usize = original_len;
194}
195
196/// Consumes the stream until the end, ignoring all the data, returning the
197/// number of bytes discarded.
198pub fn discardRemaining(r: *Reader) ShortError!usize {
199 var offset: usize = r.end - r.seek;
200 r.seek = 0;
201 r.end = 0;
64202 while (true) {
65 array_list.expandToCapacity();
66 const dest_slice = array_list.items[start_index..];
67 const bytes_read = try self.readAll(dest_slice);
68 start_index += bytes_read;
203 offset += r.vtable.discard(r, .unlimited) catch |err| switch (err) {
204 error.EndOfStream => return offset,
205 else => |e| return e,
206 };
207 }
208}
209
210pub const LimitedAllocError = Allocator.Error || ShortError || error{StreamTooLong};
69211
70 if (start_index - original_len > max_append_size) {
71 array_list.shrinkAndFree(original_len + max_append_size);
212/// Transfers all bytes from the current position to the end of the stream, up
213/// to `limit`, returning them as a caller-owned allocated slice.
214///
215/// If `limit` would be exceeded, `error.StreamTooLong` is returned instead. In
216/// such case, the next byte that would be read will be the first one to exceed
217/// `limit`, and all preceeding bytes have been discarded.
218///
219/// Asserts `buffer` has nonzero capacity.
220///
221/// See also:
222/// * `appendRemaining`
223pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocError![]u8 {
224 var buffer: ArrayList(u8) = .empty;
225 defer buffer.deinit(gpa);
226 try appendRemaining(r, gpa, null, &buffer, limit);
227 return buffer.toOwnedSlice(gpa);
228}
229
230/// Transfers all bytes from the current position to the end of the stream, up
231/// to `limit`, appending them to `list`.
232///
233/// If `limit` would be exceeded, `error.StreamTooLong` is returned instead. In
234/// such case, the next byte that would be read will be the first one to exceed
235/// `limit`, and all preceeding bytes have been appended to `list`.
236///
237/// Asserts `buffer` has nonzero capacity.
238///
239/// See also:
240/// * `allocRemaining`
241pub fn appendRemaining(
242 r: *Reader,
243 gpa: Allocator,
244 comptime alignment: ?std.mem.Alignment,
245 list: *std.ArrayListAlignedUnmanaged(u8, alignment),
246 limit: Limit,
247) LimitedAllocError!void {
248 const buffer = r.buffer;
249 const buffer_contents = buffer[r.seek..r.end];
250 const copy_len = limit.minInt(buffer_contents.len);
251 try list.ensureUnusedCapacity(gpa, copy_len);
252 @memcpy(list.unusedCapacitySlice()[0..copy_len], buffer[0..copy_len]);
253 list.items.len += copy_len;
254 r.seek += copy_len;
255 if (copy_len == buffer_contents.len) {
256 r.seek = 0;
257 r.end = 0;
258 }
259 var remaining = limit.subtract(copy_len).?;
260 while (true) {
261 try list.ensureUnusedCapacity(gpa, 1);
262 const dest = remaining.slice(list.unusedCapacitySlice());
263 const additional_buffer: []u8 = if (@intFromEnum(remaining) == dest.len) buffer else &.{};
264 const n = readVec(r, &.{ dest, additional_buffer }) catch |err| switch (err) {
265 error.EndOfStream => break,
266 error.ReadFailed => return error.ReadFailed,
267 };
268 if (n > dest.len) {
269 r.end = n - dest.len;
270 list.items.len += dest.len;
72271 return error.StreamTooLong;
73272 }
273 list.items.len += n;
274 remaining = remaining.subtract(n).?;
275 }
276}
277
278/// Writes bytes from the internally tracked stream position to `data`.
279///
280/// Returns the number of bytes written, which will be at minimum `0` and
281/// at most the sum of each data slice length. The number of bytes read,
282/// including zero, does not indicate end of stream.
283///
284/// The reader's internal logical seek position moves forward in accordance
285/// with the number of bytes returned from this function.
286pub fn readVec(r: *Reader, data: []const []u8) Error!usize {
287 return readVecLimit(r, data, .unlimited);
288}
289
290/// Equivalent to `readVec` but reads at most `limit` bytes.
291///
292/// This ultimately will lower to a call to `stream`, but it must ensure
293/// that the buffer used has at least as much capacity, in case that function
294/// depends on a minimum buffer capacity. It also ensures that if the `stream`
295/// implementation calls `Writer.writableVector`, it will get this data slice
296/// along with the buffer at the end.
297pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize {
298 comptime assert(@intFromEnum(Limit.unlimited) == std.math.maxInt(usize));
299 var remaining = @intFromEnum(limit);
300 for (data, 0..) |buf, i| {
301 const buffer_contents = r.buffer[r.seek..r.end];
302 const copy_len = @min(buffer_contents.len, buf.len, remaining);
303 @memcpy(buf[0..copy_len], buffer_contents[0..copy_len]);
304 r.seek += copy_len;
305 remaining -= copy_len;
306 if (remaining == 0) break;
307 if (buf.len - copy_len == 0) continue;
74308
75 if (bytes_read != dest_slice.len) {
76 array_list.shrinkAndFree(start_index);
77 return;
309 // All of `buffer` has been copied to `data`. We now set up a structure
310 // that enables the `Writer.writableVector` API, while also ensuring
311 // API that directly operates on the `Writable.buffer` has its minimum
312 // buffer capacity requirements met.
313 r.seek = 0;
314 r.end = 0;
315 const first = buf[copy_len..];
316 const middle = data[i + 1 ..];
317 var wrapper: Writer.VectorWrapper = .{
318 .it = .{
319 .first = first,
320 .middle = middle,
321 .last = r.buffer,
322 },
323 .writer = .{
324 .buffer = if (first.len >= r.buffer.len) first else r.buffer,
325 .vtable = Writer.VectorWrapper.vtable,
326 },
327 };
328 var n = r.vtable.stream(r, &wrapper.writer, .limited(remaining)) catch |err| switch (err) {
329 error.WriteFailed => {
330 assert(!wrapper.used);
331 if (wrapper.writer.buffer.ptr == first.ptr) {
332 remaining -= wrapper.writer.end;
333 } else {
334 assert(wrapper.writer.end <= r.buffer.len);
335 r.end = wrapper.writer.end;
336 }
337 break;
338 },
339 else => |e| return e,
340 };
341 if (!wrapper.used) {
342 if (wrapper.writer.buffer.ptr == first.ptr) {
343 remaining -= n;
344 } else {
345 assert(n <= r.buffer.len);
346 r.end = n;
347 }
348 break;
349 }
350 if (n < first.len) {
351 remaining -= n;
352 break;
78353 }
354 remaining -= first.len;
355 n -= first.len;
356 for (middle) |mid| {
357 if (n < mid.len) {
358 remaining -= n;
359 break;
360 }
361 remaining -= mid.len;
362 n -= mid.len;
363 }
364 assert(n <= r.buffer.len);
365 r.end = n;
366 break;
367 }
368 return @intFromEnum(limit) - remaining;
369}
370
371pub fn buffered(r: *Reader) []u8 {
372 return r.buffer[r.seek..r.end];
373}
374
375pub fn bufferedLen(r: *const Reader) usize {
376 return r.end - r.seek;
377}
79378
80 // This will trigger ArrayList to expand superlinearly at whatever its growth rate is.
81 try array_list.ensureTotalCapacity(start_index + 1);
379pub fn hashed(r: *Reader, hasher: anytype) Hashed(@TypeOf(hasher)) {
380 return .{ .in = r, .hasher = hasher };
381}
382
383pub fn readVecAll(r: *Reader, data: [][]u8) Error!void {
384 var index: usize = 0;
385 var truncate: usize = 0;
386 while (index < data.len) {
387 {
388 const untruncated = data[index];
389 data[index] = untruncated[truncate..];
390 defer data[index] = untruncated;
391 truncate += try r.readVec(data[index..]);
392 }
393 while (index < data.len and truncate >= data[index].len) {
394 truncate -= data[index].len;
395 index += 1;
396 }
82397 }
83398}
84399
85/// Allocates enough memory to hold all the contents of the stream. If the allocated
86/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
87/// Caller owns returned memory.
88/// If this function returns an error, the contents from the stream read so far are lost.
89pub fn readAllAlloc(self: Self, allocator: mem.Allocator, max_size: usize) anyerror![]u8 {
90 var array_list = std.ArrayList(u8).init(allocator);
91 defer array_list.deinit();
92 try self.readAllArrayList(&array_list, max_size);
93 return try array_list.toOwnedSlice();
94}
95
96/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.
97/// Replaces the `std.ArrayList` contents by reading from the stream until `delimiter` is found.
98/// Does not include the delimiter in the result.
99/// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the
100/// `std.ArrayList` is populated with `max_size` bytes from the stream.
101pub fn readUntilDelimiterArrayList(
102 self: Self,
103 array_list: *std.ArrayList(u8),
104 delimiter: u8,
105 max_size: usize,
106) anyerror!void {
107 array_list.shrinkRetainingCapacity(0);
108 try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size);
109}
110
111/// Deprecated: use `streamUntilDelimiter` with ArrayList's writer instead.
112/// Allocates enough memory to read until `delimiter`. If the allocated
113/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
114/// Caller owns returned memory.
115/// If this function returns an error, the contents from the stream read so far are lost.
116pub fn readUntilDelimiterAlloc(
117 self: Self,
118 allocator: mem.Allocator,
119 delimiter: u8,
120 max_size: usize,
121) anyerror![]u8 {
122 var array_list = std.ArrayList(u8).init(allocator);
123 defer array_list.deinit();
124 try self.streamUntilDelimiter(array_list.writer(), delimiter, max_size);
125 return try array_list.toOwnedSlice();
126}
127
128/// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead.
129/// Reads from the stream until specified byte is found. If the buffer is not
130/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
131/// If end-of-stream is found, `error.EndOfStream` is returned.
132/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
133/// delimiter byte is written to the output buffer but is not included
134/// in the returned slice.
135pub fn readUntilDelimiter(self: Self, buf: []u8, delimiter: u8) anyerror![]u8 {
136 var fbs = std.io.fixedBufferStream(buf);
137 try self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len);
138 const output = fbs.getWritten();
139 buf[output.len] = delimiter; // emulating old behaviour
140 return output;
141}
142
143/// Deprecated: use `streamUntilDelimiter` with ArrayList's (or any other's) writer instead.
144/// Allocates enough memory to read until `delimiter` or end-of-stream.
145/// If the allocated memory would be greater than `max_size`, returns
146/// `error.StreamTooLong`. If end-of-stream is found, returns the rest
147/// of the stream. If this function is called again after that, returns
148/// null.
149/// Caller owns returned memory.
150/// If this function returns an error, the contents from the stream read so far are lost.
151pub fn readUntilDelimiterOrEofAlloc(
152 self: Self,
153 allocator: mem.Allocator,
154 delimiter: u8,
155 max_size: usize,
156) anyerror!?[]u8 {
157 var array_list = std.ArrayList(u8).init(allocator);
158 defer array_list.deinit();
159 self.streamUntilDelimiter(array_list.writer(), delimiter, max_size) catch |err| switch (err) {
160 error.EndOfStream => if (array_list.items.len == 0) {
161 return null;
400/// Returns the next `len` bytes from the stream, filling the buffer as
401/// necessary.
402///
403/// Invalidates previously returned values from `peek`.
404///
405/// Asserts that the `Reader` was initialized with a buffer capacity at
406/// least as big as `len`.
407///
408/// If there are fewer than `len` bytes left in the stream, `error.EndOfStream`
409/// is returned instead.
410///
411/// See also:
412/// * `peek`
413/// * `toss`
414pub fn peek(r: *Reader, n: usize) Error![]u8 {
415 try r.fill(n);
416 return r.buffer[r.seek..][0..n];
417}
418
419/// Returns all the next buffered bytes, after filling the buffer to ensure it
420/// contains at least `n` bytes.
421///
422/// Invalidates previously returned values from `peek` and `peekGreedy`.
423///
424/// Asserts that the `Reader` was initialized with a buffer capacity at
425/// least as big as `n`.
426///
427/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
428/// is returned instead.
429///
430/// See also:
431/// * `peek`
432/// * `toss`
433pub fn peekGreedy(r: *Reader, n: usize) Error![]u8 {
434 try r.fill(n);
435 return r.buffer[r.seek..r.end];
436}
437
438/// Skips the next `n` bytes from the stream, advancing the seek position. This
439/// is typically and safely used after `peek`.
440///
441/// Asserts that the number of bytes buffered is at least as many as `n`.
442///
443/// The "tossed" memory remains alive until a "peek" operation occurs.
444///
445/// See also:
446/// * `peek`.
447/// * `discard`.
448pub fn toss(r: *Reader, n: usize) void {
449 r.seek += n;
450 assert(r.seek <= r.end);
451}
452
453/// Equivalent to `toss(r.bufferedLen())`.
454pub fn tossBuffered(r: *Reader) void {
455 r.seek = 0;
456 r.end = 0;
457}
458
459/// Equivalent to `peek` followed by `toss`.
460///
461/// The data returned is invalidated by the next call to `take`, `peek`,
462/// `fill`, and functions with those prefixes.
463pub fn take(r: *Reader, n: usize) Error![]u8 {
464 const result = try r.peek(n);
465 r.toss(n);
466 return result;
467}
468
469/// Returns the next `n` bytes from the stream as an array, filling the buffer
470/// as necessary and advancing the seek position `n` bytes.
471///
472/// Asserts that the `Reader` was initialized with a buffer capacity at
473/// least as big as `n`.
474///
475/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
476/// is returned instead.
477///
478/// See also:
479/// * `take`
480pub fn takeArray(r: *Reader, comptime n: usize) Error!*[n]u8 {
481 return (try r.take(n))[0..n];
482}
483
484/// Returns the next `n` bytes from the stream as an array, filling the buffer
485/// as necessary, without advancing the seek position.
486///
487/// Asserts that the `Reader` was initialized with a buffer capacity at
488/// least as big as `n`.
489///
490/// If there are fewer than `n` bytes left in the stream, `error.EndOfStream`
491/// is returned instead.
492///
493/// See also:
494/// * `peek`
495/// * `takeArray`
496pub fn peekArray(r: *Reader, comptime n: usize) Error!*[n]u8 {
497 return (try r.peek(n))[0..n];
498}
499
500/// Skips the next `n` bytes from the stream, advancing the seek position.
501///
502/// Unlike `toss` which is infallible, in this function `n` can be any amount.
503///
504/// Returns `error.EndOfStream` if fewer than `n` bytes could be discarded.
505///
506/// See also:
507/// * `toss`
508/// * `discardRemaining`
509/// * `discardShort`
510/// * `discard`
511pub fn discardAll(r: *Reader, n: usize) Error!void {
512 if ((try r.discardShort(n)) != n) return error.EndOfStream;
513}
514
515pub fn discardAll64(r: *Reader, n: u64) Error!void {
516 var remaining: u64 = n;
517 while (remaining > 0) {
518 const limited_remaining = std.math.cast(usize, remaining) orelse std.math.maxInt(usize);
519 try discardAll(r, limited_remaining);
520 remaining -= limited_remaining;
521 }
522}
523
524/// Skips the next `n` bytes from the stream, advancing the seek position.
525///
526/// Unlike `toss` which is infallible, in this function `n` can be any amount.
527///
528/// Returns the number of bytes discarded, which is less than `n` if and only
529/// if the stream reached the end.
530///
531/// See also:
532/// * `discardAll`
533/// * `discardRemaining`
534/// * `discard`
535pub fn discardShort(r: *Reader, n: usize) ShortError!usize {
536 const proposed_seek = r.seek + n;
537 if (proposed_seek <= r.end) {
538 @branchHint(.likely);
539 r.seek = proposed_seek;
540 return n;
541 }
542 var remaining = n - (r.end - r.seek);
543 r.end = 0;
544 r.seek = 0;
545 while (true) {
546 const discard_len = r.vtable.discard(r, .limited(remaining)) catch |err| switch (err) {
547 error.EndOfStream => return n - remaining,
548 error.ReadFailed => return error.ReadFailed,
549 };
550 remaining -= discard_len;
551 if (remaining == 0) return n;
552 }
553}
554
555/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
556/// the seek position.
557///
558/// Invalidates previously returned values from `peek`.
559///
560/// If the provided buffer cannot be filled completely, `error.EndOfStream` is
561/// returned instead.
562///
563/// See also:
564/// * `peek`
565/// * `readSliceShort`
566pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
567 const n = try readSliceShort(r, buffer);
568 if (n != buffer.len) return error.EndOfStream;
569}
570
571/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
572/// the seek position.
573///
574/// Invalidates previously returned values from `peek`.
575///
576/// Returns the number of bytes read, which is less than `buffer.len` if and
577/// only if the stream reached the end.
578///
579/// See also:
580/// * `readSliceAll`
581pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
582 const in_buffer = r.buffer[r.seek..r.end];
583 const copy_len = @min(buffer.len, in_buffer.len);
584 @memcpy(buffer[0..copy_len], in_buffer[0..copy_len]);
585 if (buffer.len - copy_len == 0) {
586 r.seek += copy_len;
587 return buffer.len;
588 }
589 var i: usize = copy_len;
590 r.end = 0;
591 r.seek = 0;
592 while (true) {
593 const remaining = buffer[i..];
594 var wrapper: Writer.VectorWrapper = .{
595 .it = .{
596 .first = remaining,
597 .last = r.buffer,
598 },
599 .writer = .{
600 .buffer = if (remaining.len >= r.buffer.len) remaining else r.buffer,
601 .vtable = Writer.VectorWrapper.vtable,
602 },
603 };
604 const n = r.vtable.stream(r, &wrapper.writer, .unlimited) catch |err| switch (err) {
605 error.WriteFailed => {
606 if (!wrapper.used) {
607 assert(r.seek == 0);
608 r.seek = remaining.len;
609 r.end = wrapper.writer.end;
610 @memcpy(remaining, r.buffer[0..remaining.len]);
611 }
612 return buffer.len;
613 },
614 error.EndOfStream => return i,
615 error.ReadFailed => return error.ReadFailed,
616 };
617 if (n < remaining.len) {
618 i += n;
619 continue;
620 }
621 r.end = n - remaining.len;
622 return buffer.len;
623 }
624}
625
626/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
627/// the seek position.
628///
629/// Invalidates previously returned values from `peek`.
630///
631/// If the provided buffer cannot be filled completely, `error.EndOfStream` is
632/// returned instead.
633///
634/// The function is inline to avoid the dead code in case `endian` is
635/// comptime-known and matches host endianness.
636///
637/// See also:
638/// * `readSliceAll`
639/// * `readSliceEndianAlloc`
640pub inline fn readSliceEndian(
641 r: *Reader,
642 comptime Elem: type,
643 buffer: []Elem,
644 endian: std.builtin.Endian,
645) Error!void {
646 try readSliceAll(r, @ptrCast(buffer));
647 if (native_endian != endian) for (buffer) |*elem| std.mem.byteSwapAllFields(Elem, elem);
648}
649
650pub const ReadAllocError = Error || Allocator.Error;
651
652/// The function is inline to avoid the dead code in case `endian` is
653/// comptime-known and matches host endianness.
654pub inline fn readSliceEndianAlloc(
655 r: *Reader,
656 allocator: Allocator,
657 comptime Elem: type,
658 len: usize,
659 endian: std.builtin.Endian,
660) ReadAllocError![]Elem {
661 const dest = try allocator.alloc(Elem, len);
662 errdefer allocator.free(dest);
663 try readSliceAll(r, @ptrCast(dest));
664 if (native_endian != endian) for (dest) |*elem| std.mem.byteSwapAllFields(Elem, elem);
665 return dest;
666}
667
668/// Shortcut for calling `readSliceAll` with a buffer provided by `allocator`.
669pub fn readAlloc(r: *Reader, allocator: Allocator, len: usize) ReadAllocError![]u8 {
670 const dest = try allocator.alloc(u8, len);
671 errdefer allocator.free(dest);
672 try readSliceAll(r, dest);
673 return dest;
674}
675
676pub const DelimiterError = error{
677 /// See the `Reader` implementation for detailed diagnostics.
678 ReadFailed,
679 /// For "inclusive" functions, stream ended before the delimiter was found.
680 /// For "exclusive" functions, stream ended and there are no more bytes to
681 /// return.
682 EndOfStream,
683 /// The delimiter was not found within a number of bytes matching the
684 /// capacity of the `Reader`.
685 StreamTooLong,
686};
687
688/// Returns a slice of the next bytes of buffered data from the stream until
689/// `sentinel` is found, advancing the seek position.
690///
691/// Returned slice has a sentinel.
692///
693/// Invalidates previously returned values from `peek`.
694///
695/// See also:
696/// * `peekSentinel`
697/// * `takeDelimiterExclusive`
698/// * `takeDelimiterInclusive`
699pub fn takeSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel]u8 {
700 const result = try r.peekSentinel(sentinel);
701 r.toss(result.len + 1);
702 return result;
703}
704
705/// Returns a slice of the next bytes of buffered data from the stream until
706/// `sentinel` is found, without advancing the seek position.
707///
708/// Returned slice has a sentinel; end of stream does not count as a delimiter.
709///
710/// Invalidates previously returned values from `peek`.
711///
712/// See also:
713/// * `takeSentinel`
714/// * `peekDelimiterExclusive`
715/// * `peekDelimiterInclusive`
716pub fn peekSentinel(r: *Reader, comptime sentinel: u8) DelimiterError![:sentinel]u8 {
717 const result = try r.peekDelimiterInclusive(sentinel);
718 return result[0 .. result.len - 1 :sentinel];
719}
720
721/// Returns a slice of the next bytes of buffered data from the stream until
722/// `delimiter` is found, advancing the seek position.
723///
724/// Returned slice includes the delimiter as the last byte.
725///
726/// Invalidates previously returned values from `peek`.
727///
728/// See also:
729/// * `takeSentinel`
730/// * `takeDelimiterExclusive`
731/// * `peekDelimiterInclusive`
732pub fn takeDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
733 const result = try r.peekDelimiterInclusive(delimiter);
734 r.toss(result.len);
735 return result;
736}
737
738/// Returns a slice of the next bytes of buffered data from the stream until
739/// `delimiter` is found, without advancing the seek position.
740///
741/// Returned slice includes the delimiter as the last byte.
742///
743/// Invalidates previously returned values from `peek`.
744///
745/// See also:
746/// * `peekSentinel`
747/// * `peekDelimiterExclusive`
748/// * `takeDelimiterInclusive`
749pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
750 const buffer = r.buffer[0..r.end];
751 const seek = r.seek;
752 if (std.mem.indexOfScalarPos(u8, buffer, seek, delimiter)) |end| {
753 @branchHint(.likely);
754 return buffer[seek .. end + 1];
755 }
756 if (r.vtable.stream == &endingStream) {
757 // Protect the `@constCast` of `fixed`.
758 return error.EndOfStream;
759 }
760 r.rebase();
761 while (r.buffer.len - r.end != 0) {
762 const end_cap = r.buffer[r.end..];
763 var writer: Writer = .fixed(end_cap);
764 const n = r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) {
765 error.WriteFailed => unreachable,
766 else => |e| return e,
767 };
768 r.end += n;
769 if (std.mem.indexOfScalarPos(u8, end_cap[0..n], 0, delimiter)) |end| {
770 return r.buffer[0 .. r.end - n + end + 1];
771 }
772 }
773 return error.StreamTooLong;
774}
775
776/// Returns a slice of the next bytes of buffered data from the stream until
777/// `delimiter` is found, advancing the seek position.
778///
779/// Returned slice excludes the delimiter. End-of-stream is treated equivalent
780/// to a delimiter, unless it would result in a length 0 return value, in which
781/// case `error.EndOfStream` is returned instead.
782///
783/// If the delimiter is not found within a number of bytes matching the
784/// capacity of this `Reader`, `error.StreamTooLong` is returned. In
785/// such case, the stream state is unmodified as if this function was never
786/// called.
787///
788/// Invalidates previously returned values from `peek`.
789///
790/// See also:
791/// * `takeDelimiterInclusive`
792/// * `peekDelimiterExclusive`
793pub fn takeDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
794 const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {
795 error.EndOfStream => {
796 const remaining = r.buffer[r.seek..r.end];
797 if (remaining.len == 0) return error.EndOfStream;
798 r.toss(remaining.len);
799 return remaining;
162800 },
163801 else => |e| return e,
164802 };
165 return try array_list.toOwnedSlice();
166}
167
168/// Deprecated: use `streamUntilDelimiter` with FixedBufferStream's writer instead.
169/// Reads from the stream until specified byte is found. If the buffer is not
170/// large enough to hold the entire contents, `error.StreamTooLong` is returned.
171/// If end-of-stream is found, returns the rest of the stream. If this
172/// function is called again after that, returns null.
173/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
174/// delimiter byte is written to the output buffer but is not included
175/// in the returned slice.
176pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) anyerror!?[]u8 {
177 var fbs = std.io.fixedBufferStream(buf);
178 self.streamUntilDelimiter(fbs.writer(), delimiter, fbs.buffer.len) catch |err| switch (err) {
179 error.EndOfStream => if (fbs.getWritten().len == 0) {
180 return null;
803 r.toss(result.len);
804 return result[0 .. result.len - 1];
805}
806
807/// Returns a slice of the next bytes of buffered data from the stream until
808/// `delimiter` is found, without advancing the seek position.
809///
810/// Returned slice excludes the delimiter. End-of-stream is treated equivalent
811/// to a delimiter, unless it would result in a length 0 return value, in which
812/// case `error.EndOfStream` is returned instead.
813///
814/// If the delimiter is not found within a number of bytes matching the
815/// capacity of this `Reader`, `error.StreamTooLong` is returned. In
816/// such case, the stream state is unmodified as if this function was never
817/// called.
818///
819/// Invalidates previously returned values from `peek`.
820///
821/// See also:
822/// * `peekDelimiterInclusive`
823/// * `takeDelimiterExclusive`
824pub fn peekDelimiterExclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
825 const result = r.peekDelimiterInclusive(delimiter) catch |err| switch (err) {
826 error.EndOfStream => {
827 const remaining = r.buffer[r.seek..r.end];
828 if (remaining.len == 0) return error.EndOfStream;
829 r.toss(remaining.len);
830 return remaining;
181831 },
832 else => |e| return e,
833 };
834 return result[0 .. result.len - 1];
835}
182836
837/// Appends to `w` contents by reading from the stream until `delimiter` is
838/// found. Does not write the delimiter itself.
839///
840/// Returns number of bytes streamed, which may be zero, or error.EndOfStream
841/// if the delimiter was not found.
842///
843/// See also:
844/// * `streamDelimiterEnding`
845/// * `streamDelimiterLimit`
846pub fn streamDelimiter(r: *Reader, w: *Writer, delimiter: u8) StreamError!usize {
847 const n = streamDelimiterLimit(r, w, delimiter, .unlimited) catch |err| switch (err) {
848 error.StreamTooLong => unreachable, // unlimited is passed
183849 else => |e| return e,
184850 };
185 const output = fbs.getWritten();
186 buf[output.len] = delimiter; // emulating old behaviour
187 return output;
851 if (r.seek == r.end) return error.EndOfStream;
852 return n;
188853}
189854
190/// Appends to the `writer` contents by reading from the stream until `delimiter` is found.
855/// Appends to `w` contents by reading from the stream until `delimiter` is found.
191856/// Does not write the delimiter itself.
192/// If `optional_max_size` is not null and amount of written bytes exceeds `optional_max_size`,
193/// returns `error.StreamTooLong` and finishes appending.
194/// If `optional_max_size` is null, appending is unbounded.
195pub fn streamUntilDelimiter(
196 self: Self,
197 writer: anytype,
857///
858/// Returns number of bytes streamed, which may be zero. End of stream can be
859/// detected by checking if the next byte in the stream is the delimiter.
860///
861/// See also:
862/// * `streamDelimiter`
863/// * `streamDelimiterLimit`
864pub fn streamDelimiterEnding(
865 r: *Reader,
866 w: *Writer,
198867 delimiter: u8,
199 optional_max_size: ?usize,
200) anyerror!void {
201 if (optional_max_size) |max_size| {
202 for (0..max_size) |_| {
203 const byte: u8 = try self.readByte();
204 if (byte == delimiter) return;
205 try writer.writeByte(byte);
206 }
207 return error.StreamTooLong;
208 } else {
209 while (true) {
210 const byte: u8 = try self.readByte();
211 if (byte == delimiter) return;
212 try writer.writeByte(byte);
868) StreamRemainingError!usize {
869 return streamDelimiterLimit(r, w, delimiter, .unlimited) catch |err| switch (err) {
870 error.StreamTooLong => unreachable, // unlimited is passed
871 else => |e| return e,
872 };
873}
874
875pub const StreamDelimiterLimitError = error{
876 ReadFailed,
877 WriteFailed,
878 /// The delimiter was not found within the limit.
879 StreamTooLong,
880};
881
882/// Appends to `w` contents by reading from the stream until `delimiter` is found.
883/// Does not write the delimiter itself.
884///
885/// Returns number of bytes streamed, which may be zero. End of stream can be
886/// detected by checking if the next byte in the stream is the delimiter.
887pub fn streamDelimiterLimit(
888 r: *Reader,
889 w: *Writer,
890 delimiter: u8,
891 limit: Limit,
892) StreamDelimiterLimitError!usize {
893 var remaining = @intFromEnum(limit);
894 while (remaining != 0) {
895 const available = Limit.limited(remaining).slice(r.peekGreedy(1) catch |err| switch (err) {
896 error.ReadFailed => return error.ReadFailed,
897 error.EndOfStream => return @intFromEnum(limit) - remaining,
898 });
899 if (std.mem.indexOfScalar(u8, available, delimiter)) |delimiter_index| {
900 try w.writeAll(available[0..delimiter_index]);
901 r.toss(delimiter_index);
902 remaining -= delimiter_index;
903 return @intFromEnum(limit) - remaining;
213904 }
214 // Can not throw `error.StreamTooLong` since there are no boundary.
905 try w.writeAll(available);
906 r.toss(available.len);
907 remaining -= available.len;
215908 }
909 return error.StreamTooLong;
216910}
217911
218912/// Reads from the stream until specified byte is found, discarding all data,
219913/// including the delimiter.
220/// If end-of-stream is found, this function succeeds.
221pub fn skipUntilDelimiterOrEof(self: Self, delimiter: u8) anyerror!void {
222 while (true) {
223 const byte = self.readByte() catch |err| switch (err) {
224 error.EndOfStream => return,
914///
915/// Returns number of bytes discarded, or `error.EndOfStream` if the delimiter
916/// is not found.
917///
918/// See also:
919/// * `discardDelimiterExclusive`
920/// * `discardDelimiterLimit`
921pub fn discardDelimiterInclusive(r: *Reader, delimiter: u8) Error!usize {
922 const n = discardDelimiterLimit(r, delimiter, .unlimited) catch |err| switch (err) {
923 error.StreamTooLong => unreachable, // unlimited is passed
924 else => |e| return e,
925 };
926 if (r.seek == r.end) return error.EndOfStream;
927 assert(r.buffer[r.seek] == delimiter);
928 toss(r, 1);
929 return n + 1;
930}
931
932/// Reads from the stream until specified byte is found, discarding all data,
933/// excluding the delimiter.
934///
935/// Returns the number of bytes discarded.
936///
937/// Succeeds if stream ends before delimiter found. End of stream can be
938/// detected by checking if the delimiter is buffered.
939///
940/// See also:
941/// * `discardDelimiterInclusive`
942/// * `discardDelimiterLimit`
943pub fn discardDelimiterExclusive(r: *Reader, delimiter: u8) ShortError!usize {
944 return discardDelimiterLimit(r, delimiter, .unlimited) catch |err| switch (err) {
945 error.StreamTooLong => unreachable, // unlimited is passed
946 else => |e| return e,
947 };
948}
949
950pub const DiscardDelimiterLimitError = error{
951 ReadFailed,
952 /// The delimiter was not found within the limit.
953 StreamTooLong,
954};
955
956/// Reads from the stream until specified byte is found, discarding all data,
957/// excluding the delimiter.
958///
959/// Returns the number of bytes discarded.
960///
961/// Succeeds if stream ends before delimiter found. End of stream can be
962/// detected by checking if the delimiter is buffered.
963pub fn discardDelimiterLimit(r: *Reader, delimiter: u8, limit: Limit) DiscardDelimiterLimitError!usize {
964 var remaining = @intFromEnum(limit);
965 while (remaining != 0) {
966 const available = Limit.limited(remaining).slice(r.peekGreedy(1) catch |err| switch (err) {
967 error.ReadFailed => return error.ReadFailed,
968 error.EndOfStream => return @intFromEnum(limit) - remaining,
969 });
970 if (std.mem.indexOfScalar(u8, available, delimiter)) |delimiter_index| {
971 r.toss(delimiter_index);
972 remaining -= delimiter_index;
973 return @intFromEnum(limit) - remaining;
974 }
975 r.toss(available.len);
976 remaining -= available.len;
977 }
978 return error.StreamTooLong;
979}
980
981/// Fills the buffer such that it contains at least `n` bytes, without
982/// advancing the seek position.
983///
984/// Returns `error.EndOfStream` if and only if there are fewer than `n` bytes
985/// remaining.
986///
987/// Asserts buffer capacity is at least `n`.
988pub fn fill(r: *Reader, n: usize) Error!void {
989 assert(n <= r.buffer.len);
990 if (r.seek + n <= r.end) {
991 @branchHint(.likely);
992 return;
993 }
994 if (r.seek + n <= r.buffer.len) while (true) {
995 const end_cap = r.buffer[r.end..];
996 var writer: Writer = .fixed(end_cap);
997 r.end += r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) {
998 error.WriteFailed => unreachable,
225999 else => |e| return e,
2261000 };
227 if (byte == delimiter) return;
1001 if (r.seek + n <= r.end) return;
1002 };
1003 if (r.vtable.stream == &endingStream) {
1004 // Protect the `@constCast` of `fixed`.
1005 return error.EndOfStream;
1006 }
1007 rebaseCapacity(r, n);
1008 var writer: Writer = .{
1009 .buffer = r.buffer,
1010 .vtable = &.{ .drain = Writer.fixedDrain },
1011 };
1012 while (r.end < r.seek + n) {
1013 writer.end = r.end;
1014 r.end += r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) {
1015 error.WriteFailed => unreachable,
1016 error.ReadFailed, error.EndOfStream => |e| return e,
1017 };
2281018 }
2291019}
2301020
231/// Reads 1 byte from the stream or returns `error.EndOfStream`.
232pub fn readByte(self: Self) anyerror!u8 {
233 var result: [1]u8 = undefined;
234 const amt_read = try self.read(result[0..]);
235 if (amt_read < 1) return error.EndOfStream;
236 return result[0];
237}
238
239/// Same as `readByte` except the returned byte is signed.
240pub fn readByteSigned(self: Self) anyerror!i8 {
241 return @as(i8, @bitCast(try self.readByte()));
242}
243
244/// Reads exactly `num_bytes` bytes and returns as an array.
245/// `num_bytes` must be comptime-known
246pub fn readBytesNoEof(self: Self, comptime num_bytes: usize) anyerror![num_bytes]u8 {
247 var bytes: [num_bytes]u8 = undefined;
248 try self.readNoEof(&bytes);
249 return bytes;
250}
251
252/// Reads bytes until `bounded.len` is equal to `num_bytes`,
253/// or the stream ends.
254///
255/// * it is assumed that `num_bytes` will not exceed `bounded.capacity()`
256pub fn readIntoBoundedBytes(
257 self: Self,
258 comptime num_bytes: usize,
259 bounded: *std.BoundedArray(u8, num_bytes),
260) anyerror!void {
261 while (bounded.len < num_bytes) {
262 // get at most the number of bytes free in the bounded array
263 const bytes_read = try self.read(bounded.unusedCapacitySlice());
264 if (bytes_read == 0) return;
265
266 // bytes_read will never be larger than @TypeOf(bounded.len)
267 // due to `self.read` being bounded by `bounded.unusedCapacitySlice()`
268 bounded.len += @as(@TypeOf(bounded.len), @intCast(bytes_read));
1021/// Without advancing the seek position, does exactly one underlying read, filling the buffer as
1022/// much as possible. This may result in zero bytes added to the buffer, which is not an end of
1023/// stream condition. End of stream is communicated via returning `error.EndOfStream`.
1024///
1025/// Asserts buffer capacity is at least 1.
1026pub fn fillMore(r: *Reader) Error!void {
1027 rebaseCapacity(r, 1);
1028 var writer: Writer = .{
1029 .buffer = r.buffer,
1030 .end = r.end,
1031 .vtable = &.{ .drain = Writer.fixedDrain },
1032 };
1033 r.end += r.vtable.stream(r, &writer, .limited(r.buffer.len - r.end)) catch |err| switch (err) {
1034 error.WriteFailed => unreachable,
1035 else => |e| return e,
1036 };
1037}
1038
1039/// Returns the next byte from the stream or returns `error.EndOfStream`.
1040///
1041/// Does not advance the seek position.
1042///
1043/// Asserts the buffer capacity is nonzero.
1044pub fn peekByte(r: *Reader) Error!u8 {
1045 const buffer = r.buffer[0..r.end];
1046 const seek = r.seek;
1047 if (seek < buffer.len) {
1048 @branchHint(.likely);
1049 return buffer[seek];
2691050 }
1051 try fill(r, 1);
1052 return r.buffer[r.seek];
2701053}
2711054
272/// Reads at most `num_bytes` and returns as a bounded array.
273pub fn readBoundedBytes(self: Self, comptime num_bytes: usize) anyerror!std.BoundedArray(u8, num_bytes) {
274 var result = std.BoundedArray(u8, num_bytes){};
275 try self.readIntoBoundedBytes(num_bytes, &result);
1055/// Reads 1 byte from the stream or returns `error.EndOfStream`.
1056///
1057/// Asserts the buffer capacity is nonzero.
1058pub fn takeByte(r: *Reader) Error!u8 {
1059 const result = try peekByte(r);
1060 r.seek += 1;
2761061 return result;
2771062}
2781063
279pub inline fn readInt(self: Self, comptime T: type, endian: std.builtin.Endian) anyerror!T {
280 const bytes = try self.readBytesNoEof(@divExact(@typeInfo(T).int.bits, 8));
281 return mem.readInt(T, &bytes, endian);
1064/// Same as `takeByte` except the returned byte is signed.
1065pub fn takeByteSigned(r: *Reader) Error!i8 {
1066 return @bitCast(try r.takeByte());
2821067}
2831068
284pub fn readVarInt(
285 self: Self,
286 comptime ReturnType: type,
287 endian: std.builtin.Endian,
288 size: usize,
289) anyerror!ReturnType {
290 assert(size <= @sizeOf(ReturnType));
291 var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
292 const bytes = bytes_buf[0..size];
293 try self.readNoEof(bytes);
294 return mem.readVarInt(ReturnType, bytes, endian);
295}
296
297/// Optional parameters for `skipBytes`
298pub const SkipBytesOptions = struct {
299 buf_size: usize = 512,
300};
301
302// `num_bytes` is a `u64` to match `off_t`
303/// Reads `num_bytes` bytes from the stream and discards them
304pub fn skipBytes(self: Self, num_bytes: u64, comptime options: SkipBytesOptions) anyerror!void {
305 var buf: [options.buf_size]u8 = undefined;
306 var remaining = num_bytes;
1069/// Asserts the buffer was initialized with a capacity at least `@bitSizeOf(T) / 8`.
1070pub inline fn takeInt(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1071 const n = @divExact(@typeInfo(T).int.bits, 8);
1072 return std.mem.readInt(T, try r.takeArray(n), endian);
1073}
3071074
308 while (remaining > 0) {
309 const amt = @min(remaining, options.buf_size);
310 try self.readNoEof(buf[0..amt]);
311 remaining -= amt;
312 }
1075/// Asserts the buffer was initialized with a capacity at least `n`.
1076pub fn takeVarInt(r: *Reader, comptime Int: type, endian: std.builtin.Endian, n: usize) Error!Int {
1077 assert(n <= @sizeOf(Int));
1078 return std.mem.readVarInt(Int, try r.take(n), endian);
3131079}
3141080
315/// Reads `slice.len` bytes from the stream and returns if they are the same as the passed slice
316pub fn isBytes(self: Self, slice: []const u8) anyerror!bool {
317 var i: usize = 0;
318 var matches = true;
319 while (i < slice.len) : (i += 1) {
320 if (slice[i] != try self.readByte()) {
321 matches = false;
322 }
323 }
324 return matches;
1081/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1082///
1083/// Advances the seek position.
1084///
1085/// See also:
1086/// * `peekStruct`
1087/// * `takeStructEndian`
1088pub fn takeStruct(r: *Reader, comptime T: type) Error!*align(1) T {
1089 // Only extern and packed structs have defined in-memory layout.
1090 comptime assert(@typeInfo(T).@"struct".layout != .auto);
1091 return @ptrCast(try r.takeArray(@sizeOf(T)));
3251092}
3261093
327pub fn readStruct(self: Self, comptime T: type) anyerror!T {
1094/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1095///
1096/// Does not advance the seek position.
1097///
1098/// See also:
1099/// * `takeStruct`
1100/// * `peekStructEndian`
1101pub fn peekStruct(r: *Reader, comptime T: type) Error!*align(1) T {
3281102 // Only extern and packed structs have defined in-memory layout.
3291103 comptime assert(@typeInfo(T).@"struct".layout != .auto);
330 var res: [1]T = undefined;
331 try self.readNoEof(mem.sliceAsBytes(res[0..]));
332 return res[0];
1104 return @ptrCast(try r.peekArray(@sizeOf(T)));
3331105}
3341106
335pub fn readStructEndian(self: Self, comptime T: type, endian: std.builtin.Endian) anyerror!T {
336 var res = try self.readStruct(T);
337 if (native_endian != endian) {
338 mem.byteSwapAllFields(T, &res);
339 }
1107/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1108///
1109/// This function is inline to avoid referencing `std.mem.byteSwapAllFields`
1110/// when `endian` is comptime-known and matches the host endianness.
1111///
1112/// See also:
1113/// * `takeStruct`
1114/// * `peekStructEndian`
1115pub inline fn takeStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1116 var res = (try r.takeStruct(T)).*;
1117 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
3401118 return res;
3411119}
3421120
343/// Reads an integer with the same size as the given enum's tag type. If the integer matches
344/// an enum tag, casts the integer to the enum tag and returns it. Otherwise, returns an `error.InvalidValue`.
345/// TODO optimization taking advantage of most fields being in order
346pub fn readEnum(self: Self, comptime Enum: type, endian: std.builtin.Endian) anyerror!Enum {
347 const E = error{
348 /// An integer was read, but it did not match any of the tags in the supplied enum.
349 InvalidValue,
1121/// Asserts the buffer was initialized with a capacity at least `@sizeOf(T)`.
1122///
1123/// This function is inline to avoid referencing `std.mem.byteSwapAllFields`
1124/// when `endian` is comptime-known and matches the host endianness.
1125///
1126/// See also:
1127/// * `takeStructEndian`
1128/// * `peekStruct`
1129pub inline fn peekStructEndian(r: *Reader, comptime T: type, endian: std.builtin.Endian) Error!T {
1130 var res = (try r.peekStruct(T)).*;
1131 if (native_endian != endian) std.mem.byteSwapAllFields(T, &res);
1132 return res;
1133}
1134
1135pub const TakeEnumError = Error || error{InvalidEnumTag};
1136
1137/// Reads an integer with the same size as the given enum's tag type. If the
1138/// integer matches an enum tag, casts the integer to the enum tag and returns
1139/// it. Otherwise, returns `error.InvalidEnumTag`.
1140///
1141/// Asserts the buffer was initialized with a capacity at least `@sizeOf(Enum)`.
1142pub fn takeEnum(r: *Reader, comptime Enum: type, endian: std.builtin.Endian) TakeEnumError!Enum {
1143 const Tag = @typeInfo(Enum).@"enum".tag_type;
1144 const int = try r.takeInt(Tag, endian);
1145 return std.meta.intToEnum(Enum, int);
1146}
1147
1148/// Reads an integer with the same size as the given nonexhaustive enum's tag type.
1149///
1150/// Asserts the buffer was initialized with a capacity at least `@sizeOf(Enum)`.
1151pub fn takeEnumNonexhaustive(r: *Reader, comptime Enum: type, endian: std.builtin.Endian) Error!Enum {
1152 const info = @typeInfo(Enum).@"enum";
1153 comptime assert(!info.is_exhaustive);
1154 comptime assert(@bitSizeOf(info.tag_type) == @sizeOf(info.tag_type) * 8);
1155 return takeEnum(r, Enum, endian) catch |err| switch (err) {
1156 error.InvalidEnumTag => unreachable,
1157 else => |e| return e,
3501158 };
351 const type_info = @typeInfo(Enum).@"enum";
352 const tag = try self.readInt(type_info.tag_type, endian);
1159}
3531160
354 inline for (std.meta.fields(Enum)) |field| {
355 if (tag == field.value) {
356 return @field(Enum, field.name);
357 }
1161pub const TakeLeb128Error = Error || error{Overflow};
1162
1163/// Read a single LEB128 value as type T, or `error.Overflow` if the value cannot fit.
1164pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
1165 const result_info = @typeInfo(Result).int;
1166 return std.math.cast(Result, try r.takeMultipleOf7Leb128(@Type(.{ .int = .{
1167 .signedness = result_info.signedness,
1168 .bits = std.mem.alignForwardAnyAlign(u16, result_info.bits, 7),
1169 } }))) orelse error.Overflow;
1170}
1171
1172pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void {
1173 if (n <= r.buffer.len) return;
1174 if (r.seek > 0) rebase(r);
1175 var list: ArrayList(u8) = .{
1176 .items = r.buffer[0..r.end],
1177 .capacity = r.buffer.len,
1178 };
1179 defer r.buffer = list.allocatedSlice();
1180 try list.ensureTotalCapacity(allocator, n);
1181}
1182
1183pub const FillAllocError = Error || Allocator.Error;
1184
1185pub fn fillAlloc(r: *Reader, allocator: Allocator, n: usize) FillAllocError!void {
1186 try expandTotalCapacity(r, allocator, n);
1187 return fill(r, n);
1188}
1189
1190/// Returns a slice into the unused capacity of `buffer` with at least
1191/// `min_len` bytes, extending `buffer` by resizing it with `gpa` as necessary.
1192///
1193/// After calling this function, typically the caller will follow up with a
1194/// call to `advanceBufferEnd` to report the actual number of bytes buffered.
1195pub fn writableSliceGreedyAlloc(r: *Reader, allocator: Allocator, min_len: usize) Allocator.Error![]u8 {
1196 {
1197 const unused = r.buffer[r.end..];
1198 if (unused.len >= min_len) return unused;
1199 }
1200 if (r.seek > 0) rebase(r);
1201 {
1202 var list: ArrayList(u8) = .{
1203 .items = r.buffer[0..r.end],
1204 .capacity = r.buffer.len,
1205 };
1206 defer r.buffer = list.allocatedSlice();
1207 try list.ensureUnusedCapacity(allocator, min_len);
3581208 }
1209 const unused = r.buffer[r.end..];
1210 assert(unused.len >= min_len);
1211 return unused;
1212}
3591213
360 return E.InvalidValue;
1214/// After writing directly into the unused capacity of `buffer`, this function
1215/// updates `end` so that users of `Reader` can receive the data.
1216pub fn advanceBufferEnd(r: *Reader, n: usize) void {
1217 assert(n <= r.buffer.len - r.end);
1218 r.end += n;
3611219}
3621220
363/// Reads the stream until the end, ignoring all the data.
364/// Returns the number of bytes discarded.
365pub fn discard(self: Self) anyerror!u64 {
366 var trash: [4096]u8 = undefined;
367 var index: u64 = 0;
1221fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
1222 const result_info = @typeInfo(Result).int;
1223 comptime assert(result_info.bits % 7 == 0);
1224 var remaining_bits: std.math.Log2IntCeil(Result) = result_info.bits;
1225 const UnsignedResult = @Type(.{ .int = .{
1226 .signedness = .unsigned,
1227 .bits = result_info.bits,
1228 } });
1229 var result: UnsignedResult = 0;
1230 var fits = true;
3681231 while (true) {
369 const n = try self.read(&trash);
370 if (n == 0) return index;
371 index += n;
1232 const buffer: []const packed struct(u8) { bits: u7, more: bool } = @ptrCast(try r.peekGreedy(1));
1233 for (buffer, 1..) |byte, len| {
1234 if (remaining_bits > 0) {
1235 result = @shlExact(@as(UnsignedResult, byte.bits), result_info.bits - 7) |
1236 if (result_info.bits > 7) @shrExact(result, 7) else 0;
1237 remaining_bits -= 7;
1238 } else if (fits) fits = switch (result_info.signedness) {
1239 .signed => @as(i7, @bitCast(byte.bits)) ==
1240 @as(i7, @truncate(@as(Result, @bitCast(result)) >> (result_info.bits - 1))),
1241 .unsigned => byte.bits == 0,
1242 };
1243 if (byte.more) continue;
1244 r.toss(len);
1245 return if (fits) @as(Result, @bitCast(result)) >> remaining_bits else error.Overflow;
1246 }
1247 r.toss(buffer.len);
3721248 }
3731249}
3741250
375const std = @import("../std.zig");
376const Self = @This();
377const math = std.math;
378const assert = std.debug.assert;
379const mem = std.mem;
380const testing = std.testing;
381const native_endian = @import("builtin").target.cpu.arch.endian();
382const Alignment = std.mem.Alignment;
1251/// Left-aligns data such that `r.seek` becomes zero.
1252pub fn rebase(r: *Reader) void {
1253 if (r.seek == 0) return;
1254 const data = r.buffer[r.seek..r.end];
1255 @memmove(r.buffer[0..data.len], data);
1256 r.seek = 0;
1257 r.end = data.len;
1258}
1259
1260/// Ensures `capacity` more data can be buffered without rebasing, by rebasing
1261/// if necessary.
1262///
1263/// Asserts `capacity` is within the buffer capacity.
1264pub fn rebaseCapacity(r: *Reader, capacity: usize) void {
1265 if (r.end > r.buffer.len - capacity) rebase(r);
1266}
1267
1268/// Advances the stream and decreases the size of the storage buffer by `n`,
1269/// returning the range of bytes no longer accessible by `r`.
1270///
1271/// This action can be undone by `restitute`.
1272///
1273/// Asserts there are at least `n` buffered bytes already.
1274///
1275/// Asserts that `r.seek` is zero, i.e. the buffer is in a rebased state.
1276pub fn steal(r: *Reader, n: usize) []u8 {
1277 assert(r.seek == 0);
1278 assert(n <= r.end);
1279 const stolen = r.buffer[0..n];
1280 r.buffer = r.buffer[n..];
1281 r.end -= n;
1282 return stolen;
1283}
1284
1285/// Expands the storage buffer, undoing the effects of `steal`
1286/// Assumes that `n` does not exceed the total number of stolen bytes.
1287pub fn restitute(r: *Reader, n: usize) void {
1288 r.buffer = (r.buffer.ptr - n)[0 .. r.buffer.len + n];
1289 r.end += n;
1290 r.seek += n;
1291}
3831292
384test {
385 _ = @import("Reader/test.zig");
1293test fixed {
1294 var r: Reader = .fixed("a\x02");
1295 try testing.expect((try r.takeByte()) == 'a');
1296 try testing.expect((try r.takeEnum(enum(u8) {
1297 a = 0,
1298 b = 99,
1299 c = 2,
1300 d = 3,
1301 }, builtin.cpu.arch.endian())) == .c);
1302 try testing.expectError(error.EndOfStream, r.takeByte());
1303}
1304
1305test peek {
1306 var r: Reader = .fixed("abc");
1307 try testing.expectEqualStrings("ab", try r.peek(2));
1308 try testing.expectEqualStrings("a", try r.peek(1));
1309}
1310
1311test peekGreedy {
1312 var r: Reader = .fixed("abc");
1313 try testing.expectEqualStrings("abc", try r.peekGreedy(1));
1314}
1315
1316test toss {
1317 var r: Reader = .fixed("abc");
1318 r.toss(1);
1319 try testing.expectEqualStrings("bc", r.buffered());
1320}
1321
1322test take {
1323 var r: Reader = .fixed("abc");
1324 try testing.expectEqualStrings("ab", try r.take(2));
1325 try testing.expectEqualStrings("c", try r.take(1));
1326}
1327
1328test takeArray {
1329 var r: Reader = .fixed("abc");
1330 try testing.expectEqualStrings("ab", try r.takeArray(2));
1331 try testing.expectEqualStrings("c", try r.takeArray(1));
1332}
1333
1334test peekArray {
1335 var r: Reader = .fixed("abc");
1336 try testing.expectEqualStrings("ab", try r.peekArray(2));
1337 try testing.expectEqualStrings("a", try r.peekArray(1));
1338}
1339
1340test discardAll {
1341 var r: Reader = .fixed("foobar");
1342 try r.discardAll(3);
1343 try testing.expectEqualStrings("bar", try r.take(3));
1344 try r.discardAll(0);
1345 try testing.expectError(error.EndOfStream, r.discardAll(1));
1346}
1347
1348test discardRemaining {
1349 var r: Reader = .fixed("foobar");
1350 r.toss(1);
1351 try testing.expectEqual(5, try r.discardRemaining());
1352 try testing.expectEqual(0, try r.discardRemaining());
1353}
1354
1355test stream {
1356 var out_buffer: [10]u8 = undefined;
1357 var r: Reader = .fixed("foobar");
1358 var w: Writer = .fixed(&out_buffer);
1359 // Short streams are possible with this function but not with fixed.
1360 try testing.expectEqual(2, try r.stream(&w, .limited(2)));
1361 try testing.expectEqualStrings("fo", w.buffered());
1362 try testing.expectEqual(4, try r.stream(&w, .unlimited));
1363 try testing.expectEqualStrings("foobar", w.buffered());
1364}
1365
1366test takeSentinel {
1367 var r: Reader = .fixed("ab\nc");
1368 try testing.expectEqualStrings("ab", try r.takeSentinel('\n'));
1369 try testing.expectError(error.EndOfStream, r.takeSentinel('\n'));
1370 try testing.expectEqualStrings("c", try r.peek(1));
1371}
1372
1373test peekSentinel {
1374 var r: Reader = .fixed("ab\nc");
1375 try testing.expectEqualStrings("ab", try r.peekSentinel('\n'));
1376 try testing.expectEqualStrings("ab", try r.peekSentinel('\n'));
1377}
1378
1379test takeDelimiterInclusive {
1380 var r: Reader = .fixed("ab\nc");
1381 try testing.expectEqualStrings("ab\n", try r.takeDelimiterInclusive('\n'));
1382 try testing.expectError(error.EndOfStream, r.takeDelimiterInclusive('\n'));
1383}
1384
1385test peekDelimiterInclusive {
1386 var r: Reader = .fixed("ab\nc");
1387 try testing.expectEqualStrings("ab\n", try r.peekDelimiterInclusive('\n'));
1388 try testing.expectEqualStrings("ab\n", try r.peekDelimiterInclusive('\n'));
1389 r.toss(3);
1390 try testing.expectError(error.EndOfStream, r.peekDelimiterInclusive('\n'));
1391}
1392
1393test takeDelimiterExclusive {
1394 var r: Reader = .fixed("ab\nc");
1395 try testing.expectEqualStrings("ab", try r.takeDelimiterExclusive('\n'));
1396 try testing.expectEqualStrings("c", try r.takeDelimiterExclusive('\n'));
1397 try testing.expectError(error.EndOfStream, r.takeDelimiterExclusive('\n'));
1398}
1399
1400test peekDelimiterExclusive {
1401 var r: Reader = .fixed("ab\nc");
1402 try testing.expectEqualStrings("ab", try r.peekDelimiterExclusive('\n'));
1403 try testing.expectEqualStrings("ab", try r.peekDelimiterExclusive('\n'));
1404 r.toss(3);
1405 try testing.expectEqualStrings("c", try r.peekDelimiterExclusive('\n'));
1406}
1407
1408test streamDelimiter {
1409 var out_buffer: [10]u8 = undefined;
1410 var r: Reader = .fixed("foo\nbars");
1411 var w: Writer = .fixed(&out_buffer);
1412 try testing.expectEqual(3, try r.streamDelimiter(&w, '\n'));
1413 try testing.expectEqualStrings("foo", w.buffered());
1414 try testing.expectEqual(0, try r.streamDelimiter(&w, '\n'));
1415 r.toss(1);
1416 try testing.expectError(error.EndOfStream, r.streamDelimiter(&w, '\n'));
1417}
1418
1419test streamDelimiterEnding {
1420 var out_buffer: [10]u8 = undefined;
1421 var r: Reader = .fixed("foo\nbars");
1422 var w: Writer = .fixed(&out_buffer);
1423 try testing.expectEqual(3, try r.streamDelimiterEnding(&w, '\n'));
1424 try testing.expectEqualStrings("foo", w.buffered());
1425 r.toss(1);
1426 try testing.expectEqual(4, try r.streamDelimiterEnding(&w, '\n'));
1427 try testing.expectEqualStrings("foobars", w.buffered());
1428 try testing.expectEqual(0, try r.streamDelimiterEnding(&w, '\n'));
1429 try testing.expectEqual(0, try r.streamDelimiterEnding(&w, '\n'));
1430}
1431
1432test streamDelimiterLimit {
1433 var out_buffer: [10]u8 = undefined;
1434 var r: Reader = .fixed("foo\nbars");
1435 var w: Writer = .fixed(&out_buffer);
1436 try testing.expectError(error.StreamTooLong, r.streamDelimiterLimit(&w, '\n', .limited(2)));
1437 try testing.expectEqual(1, try r.streamDelimiterLimit(&w, '\n', .limited(3)));
1438 try testing.expectEqualStrings("\n", try r.take(1));
1439 try testing.expectEqual(4, try r.streamDelimiterLimit(&w, '\n', .unlimited));
1440 try testing.expectEqualStrings("foobars", w.buffered());
1441}
1442
1443test discardDelimiterExclusive {
1444 var r: Reader = .fixed("foob\nar");
1445 try testing.expectEqual(4, try r.discardDelimiterExclusive('\n'));
1446 try testing.expectEqualStrings("\n", try r.take(1));
1447 try testing.expectEqual(2, try r.discardDelimiterExclusive('\n'));
1448 try testing.expectEqual(0, try r.discardDelimiterExclusive('\n'));
1449}
1450
1451test discardDelimiterInclusive {
1452 var r: Reader = .fixed("foob\nar");
1453 try testing.expectEqual(5, try r.discardDelimiterInclusive('\n'));
1454 try testing.expectError(error.EndOfStream, r.discardDelimiterInclusive('\n'));
1455}
1456
1457test discardDelimiterLimit {
1458 var r: Reader = .fixed("foob\nar");
1459 try testing.expectError(error.StreamTooLong, r.discardDelimiterLimit('\n', .limited(4)));
1460 try testing.expectEqual(0, try r.discardDelimiterLimit('\n', .limited(2)));
1461 try testing.expectEqualStrings("\n", try r.take(1));
1462 try testing.expectEqual(2, try r.discardDelimiterLimit('\n', .unlimited));
1463 try testing.expectEqual(0, try r.discardDelimiterLimit('\n', .unlimited));
1464}
1465
1466test fill {
1467 var r: Reader = .fixed("abc");
1468 try r.fill(1);
1469 try r.fill(3);
1470}
1471
1472test takeByte {
1473 var r: Reader = .fixed("ab");
1474 try testing.expectEqual('a', try r.takeByte());
1475 try testing.expectEqual('b', try r.takeByte());
1476 try testing.expectError(error.EndOfStream, r.takeByte());
1477}
1478
1479test takeByteSigned {
1480 var r: Reader = .fixed(&.{ 255, 5 });
1481 try testing.expectEqual(-1, try r.takeByteSigned());
1482 try testing.expectEqual(5, try r.takeByteSigned());
1483 try testing.expectError(error.EndOfStream, r.takeByteSigned());
1484}
1485
1486test takeInt {
1487 var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 });
1488 try testing.expectEqual(0x1234, try r.takeInt(u16, .big));
1489 try testing.expectError(error.EndOfStream, r.takeInt(u16, .little));
1490}
1491
1492test takeVarInt {
1493 var r: Reader = .fixed(&.{ 0x12, 0x34, 0x56 });
1494 try testing.expectEqual(0x123456, try r.takeVarInt(u64, .big, 3));
1495 try testing.expectError(error.EndOfStream, r.takeVarInt(u16, .little, 1));
1496}
1497
1498test takeStruct {
1499 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1500 const S = extern struct { a: u8, b: u16 };
1501 switch (native_endian) {
1502 .little => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.takeStruct(S)).*),
1503 .big => try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.takeStruct(S)).*),
1504 }
1505 try testing.expectError(error.EndOfStream, r.takeStruct(S));
1506}
1507
1508test peekStruct {
1509 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1510 const S = extern struct { a: u8, b: u16 };
1511 switch (native_endian) {
1512 .little => {
1513 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*);
1514 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), (try r.peekStruct(S)).*);
1515 },
1516 .big => {
1517 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*);
1518 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), (try r.peekStruct(S)).*);
1519 },
1520 }
1521}
1522
1523test takeStructEndian {
1524 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1525 const S = extern struct { a: u8, b: u16 };
1526 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.takeStructEndian(S, .big));
1527 try testing.expectError(error.EndOfStream, r.takeStructEndian(S, .little));
1528}
1529
1530test peekStructEndian {
1531 var r: Reader = .fixed(&.{ 0x12, 0x00, 0x34, 0x56 });
1532 const S = extern struct { a: u8, b: u16 };
1533 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x3456 }), try r.peekStructEndian(S, .big));
1534 try testing.expectEqual(@as(S, .{ .a = 0x12, .b = 0x5634 }), try r.peekStructEndian(S, .little));
1535}
1536
1537test takeEnum {
1538 var r: Reader = .fixed(&.{ 2, 0, 1 });
1539 const E1 = enum(u8) { a, b, c };
1540 const E2 = enum(u16) { _ };
1541 try testing.expectEqual(E1.c, try r.takeEnum(E1, .little));
1542 try testing.expectEqual(@as(E2, @enumFromInt(0x0001)), try r.takeEnum(E2, .big));
1543}
1544
1545test takeLeb128 {
1546 var r: Reader = .fixed("\xc7\x9f\x7f\x80");
1547 try testing.expectEqual(-12345, try r.takeLeb128(i64));
1548 try testing.expectEqual(0x80, try r.peekByte());
1549 try testing.expectError(error.EndOfStream, r.takeLeb128(i64));
1550}
1551
1552test readSliceShort {
1553 var r: Reader = .fixed("HelloFren");
1554 var buf: [5]u8 = undefined;
1555 try testing.expectEqual(5, try r.readSliceShort(&buf));
1556 try testing.expectEqualStrings("Hello", buf[0..5]);
1557 try testing.expectEqual(4, try r.readSliceShort(&buf));
1558 try testing.expectEqualStrings("Fren", buf[0..4]);
1559 try testing.expectEqual(0, try r.readSliceShort(&buf));
1560}
1561
1562test readVec {
1563 var r: Reader = .fixed(std.ascii.letters);
1564 var flat_buffer: [52]u8 = undefined;
1565 var bufs: [2][]u8 = .{
1566 flat_buffer[0..26],
1567 flat_buffer[26..],
1568 };
1569 // Short reads are possible with this function but not with fixed.
1570 try testing.expectEqual(26 * 2, try r.readVec(&bufs));
1571 try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]);
1572 try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]);
1573}
1574
1575test readVecLimit {
1576 var r: Reader = .fixed(std.ascii.letters);
1577 var flat_buffer: [52]u8 = undefined;
1578 var bufs: [2][]u8 = .{
1579 flat_buffer[0..26],
1580 flat_buffer[26..],
1581 };
1582 // Short reads are possible with this function but not with fixed.
1583 try testing.expectEqual(50, try r.readVecLimit(&bufs, .limited(50)));
1584 try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]);
1585 try testing.expectEqualStrings(std.ascii.letters[26..50], bufs[1][0..24]);
1586}
1587
1588test "expected error.EndOfStream" {
1589 // Unit test inspired by https://github.com/ziglang/zig/issues/17733
1590 var buffer: [3]u8 = undefined;
1591 var r: std.io.Reader = .fixed(&buffer);
1592 r.end = 0; // capacity 3, but empty
1593 try std.testing.expectError(error.EndOfStream, r.takeEnum(enum(u8) { a, b }, .little));
1594 try std.testing.expectError(error.EndOfStream, r.take(3));
1595}
1596
1597fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1598 _ = r;
1599 _ = w;
1600 _ = limit;
1601 return error.EndOfStream;
1602}
1603
1604fn endingDiscard(r: *Reader, limit: Limit) Error!usize {
1605 _ = r;
1606 _ = limit;
1607 return error.EndOfStream;
1608}
1609
1610fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1611 _ = r;
1612 _ = w;
1613 _ = limit;
1614 return error.ReadFailed;
1615}
1616
1617fn failingDiscard(r: *Reader, limit: Limit) Error!usize {
1618 _ = r;
1619 _ = limit;
1620 return error.ReadFailed;
1621}
1622
1623test "readAlloc when the backing reader provides one byte at a time" {
1624 const OneByteReader = struct {
1625 str: []const u8,
1626 i: usize,
1627 reader: Reader,
1628
1629 fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1630 assert(@intFromEnum(limit) >= 1);
1631 const self: *@This() = @fieldParentPtr("reader", r);
1632 if (self.str.len - self.i == 0) return error.EndOfStream;
1633 try w.writeByte(self.str[self.i]);
1634 self.i += 1;
1635 return 1;
1636 }
1637 };
1638 const str = "This is a test";
1639 var one_byte_stream: OneByteReader = .{
1640 .str = str,
1641 .i = 0,
1642 .reader = .{
1643 .buffer = &.{},
1644 .vtable = &.{ .stream = OneByteReader.stream },
1645 .seek = 0,
1646 .end = 0,
1647 },
1648 };
1649 const res = try one_byte_stream.reader.allocRemaining(std.testing.allocator, .unlimited);
1650 defer std.testing.allocator.free(res);
1651 try std.testing.expectEqualStrings(str, res);
1652}
1653
1654test "takeDelimiterInclusive when it rebases" {
1655 const written_line = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n";
1656 var buffer: [128]u8 = undefined;
1657 var tr: std.testing.Reader = .init(&buffer, &.{
1658 .{ .buffer = written_line },
1659 .{ .buffer = written_line },
1660 .{ .buffer = written_line },
1661 .{ .buffer = written_line },
1662 .{ .buffer = written_line },
1663 .{ .buffer = written_line },
1664 });
1665 const r = &tr.interface;
1666 for (0..6) |_| {
1667 try std.testing.expectEqualStrings(written_line, try r.takeDelimiterInclusive('\n'));
1668 }
1669}
1670
1671/// Provides a `Reader` implementation by passing data from an underlying
1672/// reader through `Hasher.update`.
1673///
1674/// The underlying reader is best unbuffered.
1675///
1676/// This implementation makes suboptimal buffering decisions due to being
1677/// generic. A better solution will involve creating a reader for each hash
1678/// function, where the discard buffer can be tailored to the hash
1679/// implementation details.
1680pub fn Hashed(comptime Hasher: type) type {
1681 return struct {
1682 in: *Reader,
1683 hasher: Hasher,
1684 interface: Reader,
1685
1686 pub fn init(in: *Reader, hasher: Hasher, buffer: []u8) @This() {
1687 return .{
1688 .in = in,
1689 .hasher = hasher,
1690 .interface = .{
1691 .vtable = &.{
1692 .read = @This().read,
1693 .discard = @This().discard,
1694 },
1695 .buffer = buffer,
1696 .end = 0,
1697 .seek = 0,
1698 },
1699 };
1700 }
1701
1702 fn read(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1703 const this: *@This() = @alignCast(@fieldParentPtr("interface", r));
1704 const data = w.writableVector(limit);
1705 const n = try this.in.readVec(data);
1706 const result = w.advanceVector(n);
1707 var remaining: usize = n;
1708 for (data) |slice| {
1709 if (remaining < slice.len) {
1710 this.hasher.update(slice[0..remaining]);
1711 return result;
1712 } else {
1713 remaining -= slice.len;
1714 this.hasher.update(slice);
1715 }
1716 }
1717 assert(remaining == 0);
1718 return result;
1719 }
1720
1721 fn discard(r: *Reader, limit: Limit) Error!usize {
1722 const this: *@This() = @alignCast(@fieldParentPtr("interface", r));
1723 var w = this.hasher.writer(&.{});
1724 const n = this.in.stream(&w, limit) catch |err| switch (err) {
1725 error.WriteFailed => unreachable,
1726 else => |e| return e,
1727 };
1728 return n;
1729 }
1730 };
3861731}
lib/std/io/Reader/Limited.zig created+42
......@@ -0,0 +1,42 @@
1const Limited = @This();
2
3const std = @import("../../std.zig");
4const Reader = std.io.Reader;
5const Writer = std.io.Writer;
6const Limit = std.io.Limit;
7
8unlimited: *Reader,
9remaining: Limit,
10interface: Reader,
11
12pub fn init(reader: *Reader, limit: Limit, buffer: []u8) Limited {
13 return .{
14 .unlimited = reader,
15 .remaining = limit,
16 .interface = .{
17 .vtable = &.{
18 .stream = stream,
19 .discard = discard,
20 },
21 .buffer = buffer,
22 .seek = 0,
23 .end = 0,
24 },
25 };
26}
27
28fn stream(context: ?*anyopaque, w: *Writer, limit: Limit) Reader.StreamError!usize {
29 const l: *Limited = @alignCast(@ptrCast(context));
30 const combined_limit = limit.min(l.remaining);
31 const n = try l.unlimited_reader.read(w, combined_limit);
32 l.remaining = l.remaining.subtract(n).?;
33 return n;
34}
35
36fn discard(context: ?*anyopaque, limit: Limit) Reader.Error!usize {
37 const l: *Limited = @alignCast(@ptrCast(context));
38 const combined_limit = limit.min(l.remaining);
39 const n = try l.unlimited_reader.discard(combined_limit);
40 l.remaining = l.remaining.subtract(n).?;
41 return n;
42}
lib/std/io/Writer.zig+2449-46
......@@ -1,83 +1,2486 @@
1const builtin = @import("builtin");
2const native_endian = builtin.target.cpu.arch.endian();
3
4const Writer = @This();
15const std = @import("../std.zig");
26const assert = std.debug.assert;
3const mem = std.mem;
4const native_endian = @import("builtin").target.cpu.arch.endian();
7const Limit = std.io.Limit;
8const File = std.fs.File;
9const testing = std.testing;
10const Allocator = std.mem.Allocator;
11
12vtable: *const VTable,
13/// If this has length zero, the writer is unbuffered, and `flush` is a no-op.
14buffer: []u8,
15/// In `buffer` before this are buffered bytes, after this is `undefined`.
16end: usize = 0,
17
18pub const VTable = struct {
19 /// Sends bytes to the logical sink. A write will only be sent here if it
20 /// could not fit into `buffer`, or during a `flush` operation.
21 ///
22 /// `buffer[0..end]` is consumed first, followed by each slice of `data` in
23 /// order. Elements of `data` may alias each other but may not alias
24 /// `buffer`.
25 ///
26 /// This function modifies `Writer.end` and `Writer.buffer` in an
27 /// implementation-defined manner.
28 ///
29 /// `data.len` must be nonzero.
30 ///
31 /// The last element of `data` is repeated as necessary so that it is
32 /// written `splat` number of times, which may be zero.
33 ///
34 /// This function may not be called if the data to be written could have
35 /// been stored in `buffer` instead, including when the amount of data to
36 /// be written is zero and the buffer capacity is zero.
37 ///
38 /// Number of bytes consumed from `data` is returned, excluding bytes from
39 /// `buffer`.
40 ///
41 /// Number of bytes returned may be zero, which does not indicate stream
42 /// end. A subsequent call may return nonzero, or signal end of stream via
43 /// `error.WriteFailed`.
44 drain: *const fn (w: *Writer, data: []const []const u8, splat: usize) Error!usize,
45
46 /// Copies contents from an open file to the logical sink. `buffer[0..end]`
47 /// is consumed first, followed by `limit` bytes from `file_reader`.
48 ///
49 /// Number of bytes logically written is returned. This excludes bytes from
50 /// `buffer` because they have already been logically written. Number of
51 /// bytes consumed from `buffer` are tracked by modifying `end`.
52 ///
53 /// Number of bytes returned may be zero, which does not indicate stream
54 /// end. A subsequent call may return nonzero, or signal end of stream via
55 /// `error.WriteFailed`. Caller may check `file_reader` state
56 /// (`File.Reader.atEnd`) to disambiguate between a zero-length read or
57 /// write, and whether the file reached the end.
58 ///
59 /// `error.Unimplemented` indicates the callee cannot offer a more
60 /// efficient implementation than the caller performing its own reads.
61 sendFile: *const fn (
62 w: *Writer,
63 file_reader: *File.Reader,
64 /// Maximum amount of bytes to read from the file. Implementations may
65 /// assume that the file size does not exceed this amount. Data from
66 /// `buffer` does not count towards this limit.
67 limit: Limit,
68 ) FileError!usize = unimplementedSendFile,
69
70 /// Consumes all remaining buffer.
71 ///
72 /// The default flush implementation calls drain repeatedly until `end` is
73 /// zero, however it is legal for implementations to manage `end`
74 /// differently. For instance, `Allocating` flush is a no-op.
75 ///
76 /// There may be subsequent calls to `drain` and `sendFile` after a `flush`
77 /// operation.
78 flush: *const fn (w: *Writer) Error!void = defaultFlush,
79};
80
81pub const Error = error{
82 /// See the `Writer` implementation for detailed diagnostics.
83 WriteFailed,
84};
585
6context: *const anyopaque,
7writeFn: *const fn (context: *const anyopaque, bytes: []const u8) anyerror!usize,
86pub const FileAllError = error{
87 /// Detailed diagnostics are found on the `File.Reader` struct.
88 ReadFailed,
89 /// See the `Writer` implementation for detailed diagnostics.
90 WriteFailed,
91};
892
9const Self = @This();
10pub const Error = anyerror;
93pub const FileReadingError = error{
94 /// Detailed diagnostics are found on the `File.Reader` struct.
95 ReadFailed,
96 /// See the `Writer` implementation for detailed diagnostics.
97 WriteFailed,
98 /// Reached the end of the file being read.
99 EndOfStream,
100};
11101
12pub fn write(self: Self, bytes: []const u8) anyerror!usize {
13 return self.writeFn(self.context, bytes);
102pub const FileError = error{
103 /// Detailed diagnostics are found on the `File.Reader` struct.
104 ReadFailed,
105 /// See the `Writer` implementation for detailed diagnostics.
106 WriteFailed,
107 /// Reached the end of the file being read.
108 EndOfStream,
109 /// Indicates the caller should do its own file reading; the callee cannot
110 /// offer a more efficient implementation.
111 Unimplemented,
112};
113
114/// Writes to `buffer` and returns `error.WriteFailed` when it is full.
115pub fn fixed(buffer: []u8) Writer {
116 return .{
117 .vtable = &.{ .drain = fixedDrain },
118 .buffer = buffer,
119 };
14120}
15121
16pub fn writeAll(self: Self, bytes: []const u8) anyerror!void {
17 var index: usize = 0;
18 while (index != bytes.len) {
19 index += try self.write(bytes[index..]);
122pub fn hashed(w: *Writer, hasher: anytype, buffer: []u8) Hashed(@TypeOf(hasher)) {
123 return .initHasher(w, hasher, buffer);
124}
125
126pub const failing: Writer = .{
127 .vtable = &.{
128 .drain = failingDrain,
129 .sendFile = failingSendFile,
130 },
131};
132
133/// Returns the contents not yet drained.
134pub fn buffered(w: *const Writer) []u8 {
135 return w.buffer[0..w.end];
136}
137
138pub fn countSplat(data: []const []const u8, splat: usize) usize {
139 var total: usize = 0;
140 for (data[0 .. data.len - 1]) |buf| total += buf.len;
141 total += data[data.len - 1].len * splat;
142 return total;
143}
144
145pub fn countSendFileLowerBound(n: usize, file_reader: *File.Reader, limit: Limit) ?usize {
146 const total: u64 = @min(@intFromEnum(limit), file_reader.getSize() catch return null);
147 return std.math.lossyCast(usize, total + n);
148}
149
150/// If the total number of bytes of `data` fits inside `unusedCapacitySlice`,
151/// this function is guaranteed to not fail, not call into `VTable`, and return
152/// the total bytes inside `data`.
153pub fn writeVec(w: *Writer, data: []const []const u8) Error!usize {
154 return writeSplat(w, data, 1);
155}
156
157/// If the number of bytes to write based on `data` and `splat` fits inside
158/// `unusedCapacitySlice`, this function is guaranteed to not fail, not call
159/// into `VTable`, and return the full number of bytes.
160pub fn writeSplat(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
161 assert(data.len > 0);
162 const buffer = w.buffer;
163 const count = countSplat(data, splat);
164 if (w.end + count > buffer.len) return w.vtable.drain(w, data, splat);
165 for (data[0 .. data.len - 1]) |bytes| {
166 @memcpy(buffer[w.end..][0..bytes.len], bytes);
167 w.end += bytes.len;
168 }
169 const pattern = data[data.len - 1];
170 switch (pattern.len) {
171 0 => {},
172 1 => {
173 @memset(buffer[w.end..][0..splat], pattern[0]);
174 w.end += splat;
175 },
176 else => for (0..splat) |_| {
177 @memcpy(buffer[w.end..][0..pattern.len], pattern);
178 w.end += pattern.len;
179 },
180 }
181 return count;
182}
183
184/// Returns how many bytes were consumed from `header` and `data`.
185pub fn writeSplatHeader(
186 w: *Writer,
187 header: []const u8,
188 data: []const []const u8,
189 splat: usize,
190) Error!usize {
191 const new_end = w.end + header.len;
192 if (new_end <= w.buffer.len) {
193 @memcpy(w.buffer[w.end..][0..header.len], header);
194 w.end = new_end;
195 return header.len + try writeSplat(w, data, splat);
20196 }
197 var vecs: [8][]const u8 = undefined; // Arbitrarily chosen size.
198 var i: usize = 1;
199 vecs[0] = header;
200 for (data[0 .. data.len - 1]) |buf| {
201 if (buf.len == 0) continue;
202 vecs[i] = buf;
203 i += 1;
204 if (vecs.len - i == 0) break;
205 }
206 const pattern = data[data.len - 1];
207 const new_splat = s: {
208 if (pattern.len == 0 or vecs.len - i == 0) break :s 1;
209 vecs[i] = pattern;
210 i += 1;
211 break :s splat;
212 };
213 return w.vtable.drain(w, vecs[0..i], new_splat);
21214}
22215
23pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void {
24 return std.fmt.format(self, format, args);
216test "writeSplatHeader splatting avoids buffer aliasing temptation" {
217 const initial_buf = try testing.allocator.alloc(u8, 8);
218 var aw: std.io.Writer.Allocating = .initOwnedSlice(testing.allocator, initial_buf);
219 defer aw.deinit();
220 // This test assumes 8 vector buffer in this function.
221 const n = try aw.writer.writeSplatHeader("header which is longer than buf ", &.{
222 "1", "2", "3", "4", "5", "6", "foo", "bar", "foo",
223 }, 3);
224 try testing.expectEqual(41, n);
225 try testing.expectEqualStrings(
226 "header which is longer than buf 123456foo",
227 aw.writer.buffered(),
228 );
25229}
26230
27pub fn writeByte(self: Self, byte: u8) anyerror!void {
28 const array = [1]u8{byte};
29 return self.writeAll(&array);
231/// Drains all remaining buffered data.
232pub fn flush(w: *Writer) Error!void {
233 return w.vtable.flush(w);
30234}
31235
32pub fn writeByteNTimes(self: Self, byte: u8, n: usize) anyerror!void {
33 var bytes: [256]u8 = undefined;
34 @memset(bytes[0..], byte);
236/// Repeatedly calls `VTable.drain` until `end` is zero.
237pub fn defaultFlush(w: *Writer) Error!void {
238 const drainFn = w.vtable.drain;
239 while (w.end != 0) _ = try drainFn(w, &.{""}, 1);
240}
35241
36 var remaining: usize = n;
37 while (remaining > 0) {
38 const to_write = @min(remaining, bytes.len);
39 try self.writeAll(bytes[0..to_write]);
40 remaining -= to_write;
242/// Does nothing.
243pub fn noopFlush(w: *Writer) Error!void {
244 _ = w;
245}
246
247/// Calls `VTable.drain` but hides the last `preserve_length` bytes from the
248/// implementation, keeping them buffered.
249pub fn drainPreserve(w: *Writer, preserve_length: usize) Error!void {
250 const temp_end = w.end -| preserve_length;
251 const preserved = w.buffer[temp_end..w.end];
252 w.end = temp_end;
253 defer w.end += preserved.len;
254 assert(0 == try w.vtable.drain(w, &.{""}, 1));
255 assert(w.end <= temp_end + preserved.len);
256 @memmove(w.buffer[w.end..][0..preserved.len], preserved);
257}
258
259pub fn unusedCapacitySlice(w: *const Writer) []u8 {
260 return w.buffer[w.end..];
261}
262
263pub fn unusedCapacityLen(w: *const Writer) usize {
264 return w.buffer.len - w.end;
265}
266
267/// Asserts the provided buffer has total capacity enough for `len`.
268///
269/// Advances the buffer end position by `len`.
270pub fn writableArray(w: *Writer, comptime len: usize) Error!*[len]u8 {
271 const big_slice = try w.writableSliceGreedy(len);
272 advance(w, len);
273 return big_slice[0..len];
274}
275
276/// Asserts the provided buffer has total capacity enough for `len`.
277///
278/// Advances the buffer end position by `len`.
279pub fn writableSlice(w: *Writer, len: usize) Error![]u8 {
280 const big_slice = try w.writableSliceGreedy(len);
281 advance(w, len);
282 return big_slice[0..len];
283}
284
285/// Asserts the provided buffer has total capacity enough for `minimum_length`.
286///
287/// Does not `advance` the buffer end position.
288///
289/// If `minimum_length` is zero, this is equivalent to `unusedCapacitySlice`.
290pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 {
291 assert(w.buffer.len >= minimum_length);
292 while (w.buffer.len - w.end < minimum_length) {
293 assert(0 == try w.vtable.drain(w, &.{""}, 1));
294 } else {
295 @branchHint(.likely);
296 return w.buffer[w.end..];
41297 }
42298}
43299
44pub fn writeBytesNTimes(self: Self, bytes: []const u8, n: usize) anyerror!void {
300/// Asserts the provided buffer has total capacity enough for `minimum_length`
301/// and `preserve_length` combined.
302///
303/// Does not `advance` the buffer end position.
304///
305/// When draining the buffer, ensures that at least `preserve_length` bytes
306/// remain buffered.
307///
308/// If `preserve_length` is zero, this is equivalent to `writableSliceGreedy`.
309pub fn writableSliceGreedyPreserve(w: *Writer, preserve_length: usize, minimum_length: usize) Error![]u8 {
310 assert(w.buffer.len >= preserve_length + minimum_length);
311 while (w.buffer.len - w.end < minimum_length) {
312 try drainPreserve(w, preserve_length);
313 } else {
314 @branchHint(.likely);
315 return w.buffer[w.end..];
316 }
317}
318
319pub const WritableVectorIterator = struct {
320 first: []u8,
321 middle: []const []u8 = &.{},
322 last: []u8 = &.{},
323 index: usize = 0,
324
325 pub fn next(it: *WritableVectorIterator) ?[]u8 {
326 while (true) {
327 const i = it.index;
328 it.index += 1;
329 if (i == 0) {
330 if (it.first.len == 0) continue;
331 return it.first;
332 }
333 const middle_index = i - 1;
334 if (middle_index < it.middle.len) {
335 const middle = it.middle[middle_index];
336 if (middle.len == 0) continue;
337 return middle;
338 }
339 if (middle_index == it.middle.len) {
340 if (it.last.len == 0) continue;
341 return it.last;
342 }
343 return null;
344 }
345 }
346};
347
348pub const VectorWrapper = struct {
349 writer: Writer,
350 it: WritableVectorIterator,
351 /// Tracks whether the "writable vector" API was used.
352 used: bool = false,
353 pub const vtable: *const VTable = &unique_vtable_allocation;
354 /// This is intended to be constant but it must be a unique address for
355 /// `@fieldParentPtr` to work.
356 var unique_vtable_allocation: VTable = .{ .drain = fixedDrain };
357};
358
359pub fn writableVectorIterator(w: *Writer) Error!WritableVectorIterator {
360 if (w.vtable == VectorWrapper.vtable) {
361 const wrapper: *VectorWrapper = @fieldParentPtr("writer", w);
362 wrapper.used = true;
363 return wrapper.it;
364 }
365 return .{ .first = try writableSliceGreedy(w, 1) };
366}
367
368pub fn writableVectorPosix(w: *Writer, buffer: []std.posix.iovec, limit: Limit) Error![]std.posix.iovec {
369 var it = try writableVectorIterator(w);
45370 var i: usize = 0;
46 while (i < n) : (i += 1) {
47 try self.writeAll(bytes);
371 var remaining = limit;
372 while (it.next()) |full_buffer| {
373 if (!remaining.nonzero()) break;
374 if (buffer.len - i == 0) break;
375 const buf = remaining.slice(full_buffer);
376 if (buf.len == 0) continue;
377 buffer[i] = .{ .base = buf.ptr, .len = buf.len };
378 i += 1;
379 remaining = remaining.subtract(buf.len).?;
380 }
381 return buffer[0..i];
382}
383
384pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {
385 _ = try writableSliceGreedy(w, n);
386}
387
388pub fn undo(w: *Writer, n: usize) void {
389 w.end -= n;
390}
391
392/// After calling `writableSliceGreedy`, this function tracks how many bytes
393/// were written to it.
394///
395/// This is not needed when using `writableSlice` or `writableArray`.
396pub fn advance(w: *Writer, n: usize) void {
397 const new_end = w.end + n;
398 assert(new_end <= w.buffer.len);
399 w.end = new_end;
400}
401
402/// After calling `writableVector`, this function tracks how many bytes were
403/// written to it.
404pub fn advanceVector(w: *Writer, n: usize) usize {
405 return consume(w, n);
406}
407
408/// The `data` parameter is mutable because this function needs to mutate the
409/// fields in order to handle partial writes from `VTable.writeSplat`.
410pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void {
411 var index: usize = 0;
412 var truncate: usize = 0;
413 while (index < data.len) {
414 {
415 const untruncated = data[index];
416 data[index] = untruncated[truncate..];
417 defer data[index] = untruncated;
418 truncate += try w.writeVec(data[index..]);
419 }
420 while (index < data.len and truncate >= data[index].len) {
421 truncate -= data[index].len;
422 index += 1;
423 }
424 }
425}
426
427/// The `data` parameter is mutable because this function needs to mutate the
428/// fields in order to handle partial writes from `VTable.writeSplat`.
429pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void {
430 var index: usize = 0;
431 var truncate: usize = 0;
432 var remaining_splat = splat;
433 while (index + 1 < data.len) {
434 {
435 const untruncated = data[index];
436 data[index] = untruncated[truncate..];
437 defer data[index] = untruncated;
438 truncate += try w.writeSplat(data[index..], remaining_splat);
439 }
440 while (truncate >= data[index].len) {
441 if (index + 1 < data.len) {
442 truncate -= data[index].len;
443 index += 1;
444 } else {
445 const last = data[data.len - 1];
446 remaining_splat -= @divExact(truncate, last.len);
447 while (remaining_splat > 0) {
448 const n = try w.writeSplat(data[data.len - 1 ..][0..1], remaining_splat);
449 remaining_splat -= @divExact(n, last.len);
450 }
451 return;
452 }
453 }
454 }
455}
456
457pub fn write(w: *Writer, bytes: []const u8) Error!usize {
458 if (w.end + bytes.len <= w.buffer.len) {
459 @branchHint(.likely);
460 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);
461 w.end += bytes.len;
462 return bytes.len;
463 }
464 return w.vtable.drain(w, &.{bytes}, 1);
465}
466
467/// Asserts `buffer` capacity exceeds `preserve_length`.
468pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!usize {
469 assert(preserve_length <= w.buffer.len);
470 if (w.end + bytes.len <= w.buffer.len) {
471 @branchHint(.likely);
472 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);
473 w.end += bytes.len;
474 return bytes.len;
475 }
476 const temp_end = w.end -| preserve_length;
477 const preserved = w.buffer[temp_end..w.end];
478 w.end = temp_end;
479 defer w.end += preserved.len;
480 const n = try w.vtable.drain(w, &.{bytes}, 1);
481 assert(w.end <= temp_end + preserved.len);
482 @memmove(w.buffer[w.end..][0..preserved.len], preserved);
483 return n;
484}
485
486/// Calls `drain` as many times as necessary such that all of `bytes` are
487/// transferred.
488pub fn writeAll(w: *Writer, bytes: []const u8) Error!void {
489 var index: usize = 0;
490 while (index < bytes.len) index += try w.write(bytes[index..]);
491}
492
493/// Calls `drain` as many times as necessary such that all of `bytes` are
494/// transferred.
495///
496/// When draining the buffer, ensures that at least `preserve_length` bytes
497/// remain buffered.
498///
499/// Asserts `buffer` capacity exceeds `preserve_length`.
500pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!void {
501 var index: usize = 0;
502 while (index < bytes.len) index += try w.writePreserve(preserve_length, bytes[index..]);
503}
504
505/// Renders fmt string with args, calling `writer` with slices of bytes.
506/// If `writer` returns an error, the error is returned from `format` and
507/// `writer` is not called again.
508///
509/// The format string must be comptime-known and may contain placeholders following
510/// this format:
511/// `{[argument][specifier]:[fill][alignment][width].[precision]}`
512///
513/// Above, each word including its surrounding [ and ] is a parameter which you have to replace with something:
514///
515/// - *argument* is either the numeric index or the field name of the argument that should be inserted
516/// - when using a field name, you are required to enclose the field name (an identifier) in square
517/// brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...}
518/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
519/// - *fill* is a single byte which is used to pad formatted numbers.
520/// - *alignment* is one of the three bytes '<', '^', or '>' to make numbers
521/// left, center, or right-aligned, respectively.
522/// - Not all specifiers support alignment.
523/// - Alignment is not Unicode-aware; appropriate only when used with raw bytes or ASCII.
524/// - *width* is the total width of the field in bytes. This only applies to number formatting.
525/// - *precision* specifies how many decimals a formatted number should have.
526///
527/// Note that most of the parameters are optional and may be omitted. Also you
528/// can leave out separators like `:` and `.` when all parameters after the
529/// separator are omitted.
530///
531/// Only exception is the *fill* parameter. If a non-zero *fill* character is
532/// required at the same time as *width* is specified, one has to specify
533/// *alignment* as well, as otherwise the digit following `:` is interpreted as
534/// *width*, not *fill*.
535///
536/// The *specifier* has several options for types:
537/// - `x` and `X`: output numeric value in hexadecimal notation, or string in hexadecimal bytes
538/// - `s`:
539/// - for pointer-to-many and C pointers of u8, print as a C-string using zero-termination
540/// - for slices of u8, print the entire slice as a string without zero-termination
541/// - `t`:
542/// - for enums and tagged unions: prints the tag name
543/// - for error sets: prints the error name
544/// - `b64`: output string as standard base64
545/// - `e`: output floating point value in scientific notation
546/// - `d`: output numeric value in decimal notation
547/// - `b`: output integer value in binary notation
548/// - `o`: output integer value in octal notation
549/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
550/// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max.
551/// - `D`: output nanoseconds as duration
552/// - `B`: output bytes in SI units (decimal)
553/// - `Bi`: output bytes in IEC units (binary)
554/// - `?`: output optional value as either the unwrapped value, or `null`; may be followed by a format specifier for the underlying value.
555/// - `!`: 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.
556/// - `*`: output the address of the value instead of the value itself.
557/// - `any`: output a value of any type using its default format.
558/// - `f`: delegates to a method on the type named "format" with the signature `fn (*Writer, args: anytype) Writer.Error!void`.
559///
560/// A user type may be a `struct`, `vector`, `union` or `enum` type.
561///
562/// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`.
563pub fn print(w: *Writer, comptime fmt: []const u8, args: anytype) Error!void {
564 const ArgsType = @TypeOf(args);
565 const args_type_info = @typeInfo(ArgsType);
566 if (args_type_info != .@"struct") {
567 @compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
568 }
569
570 const fields_info = args_type_info.@"struct".fields;
571 const max_format_args = @typeInfo(std.fmt.ArgSetType).int.bits;
572 if (fields_info.len > max_format_args) {
573 @compileError("32 arguments max are supported per format call");
574 }
575
576 @setEvalBranchQuota(fmt.len * 1000);
577 comptime var arg_state: std.fmt.ArgState = .{ .args_len = fields_info.len };
578 comptime var i = 0;
579 comptime var literal: []const u8 = "";
580 inline while (true) {
581 const start_index = i;
582
583 inline while (i < fmt.len) : (i += 1) {
584 switch (fmt[i]) {
585 '{', '}' => break,
586 else => {},
587 }
588 }
589
590 comptime var end_index = i;
591 comptime var unescape_brace = false;
592
593 // Handle {{ and }}, those are un-escaped as single braces
594 if (i + 1 < fmt.len and fmt[i + 1] == fmt[i]) {
595 unescape_brace = true;
596 // Make the first brace part of the literal...
597 end_index += 1;
598 // ...and skip both
599 i += 2;
600 }
601
602 literal = literal ++ fmt[start_index..end_index];
603
604 // We've already skipped the other brace, restart the loop
605 if (unescape_brace) continue;
606
607 // Write out the literal
608 if (literal.len != 0) {
609 try w.writeAll(literal);
610 literal = "";
611 }
612
613 if (i >= fmt.len) break;
614
615 if (fmt[i] == '}') {
616 @compileError("missing opening {");
617 }
618
619 // Get past the {
620 comptime assert(fmt[i] == '{');
621 i += 1;
622
623 const fmt_begin = i;
624 // Find the closing brace
625 inline while (i < fmt.len and fmt[i] != '}') : (i += 1) {}
626 const fmt_end = i;
627
628 if (i >= fmt.len) {
629 @compileError("missing closing }");
630 }
631
632 // Get past the }
633 comptime assert(fmt[i] == '}');
634 i += 1;
635
636 const placeholder_array = fmt[fmt_begin..fmt_end].*;
637 const placeholder = comptime std.fmt.Placeholder.parse(&placeholder_array);
638 const arg_pos = comptime switch (placeholder.arg) {
639 .none => null,
640 .number => |pos| pos,
641 .named => |arg_name| std.meta.fieldIndex(ArgsType, arg_name) orelse
642 @compileError("no argument with name '" ++ arg_name ++ "'"),
643 };
644
645 const width = switch (placeholder.width) {
646 .none => null,
647 .number => |v| v,
648 .named => |arg_name| blk: {
649 const arg_i = comptime std.meta.fieldIndex(ArgsType, arg_name) orelse
650 @compileError("no argument with name '" ++ arg_name ++ "'");
651 _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments");
652 break :blk @field(args, arg_name);
653 },
654 };
655
656 const precision = switch (placeholder.precision) {
657 .none => null,
658 .number => |v| v,
659 .named => |arg_name| blk: {
660 const arg_i = comptime std.meta.fieldIndex(ArgsType, arg_name) orelse
661 @compileError("no argument with name '" ++ arg_name ++ "'");
662 _ = comptime arg_state.nextArg(arg_i) orelse @compileError("too few arguments");
663 break :blk @field(args, arg_name);
664 },
665 };
666
667 const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse
668 @compileError("too few arguments");
669
670 try w.printValue(
671 placeholder.specifier_arg,
672 .{
673 .fill = placeholder.fill,
674 .alignment = placeholder.alignment,
675 .width = width,
676 .precision = precision,
677 },
678 @field(args, fields_info[arg_to_print].name),
679 std.options.fmt_max_depth,
680 );
681 }
682
683 if (comptime arg_state.hasUnusedArgs()) {
684 const missing_count = arg_state.args_len - @popCount(arg_state.used_args);
685 switch (missing_count) {
686 0 => unreachable,
687 1 => @compileError("unused argument in '" ++ fmt ++ "'"),
688 else => @compileError(std.fmt.comptimePrint("{d}", .{missing_count}) ++ " unused arguments in '" ++ fmt ++ "'"),
689 }
690 }
691}
692
693/// Calls `drain` as many times as necessary such that `byte` is transferred.
694pub fn writeByte(w: *Writer, byte: u8) Error!void {
695 while (w.buffer.len - w.end == 0) {
696 const n = try w.vtable.drain(w, &.{&.{byte}}, 1);
697 if (n > 0) return;
698 } else {
699 @branchHint(.likely);
700 w.buffer[w.end] = byte;
701 w.end += 1;
702 }
703}
704
705/// When draining the buffer, ensures that at least `preserve_length` bytes
706/// remain buffered.
707pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!void {
708 while (w.buffer.len - w.end == 0) {
709 try drainPreserve(w, preserve_length);
710 } else {
711 @branchHint(.likely);
712 w.buffer[w.end] = byte;
713 w.end += 1;
714 }
715}
716
717/// Writes the same byte many times, performing the underlying write call as
718/// many times as necessary.
719pub fn splatByteAll(w: *Writer, byte: u8, n: usize) Error!void {
720 var remaining: usize = n;
721 while (remaining > 0) remaining -= try w.splatByte(byte, remaining);
722}
723
724/// Writes the same byte many times, allowing short writes.
725///
726/// Does maximum of one underlying `VTable.drain`.
727pub fn splatByte(w: *Writer, byte: u8, n: usize) Error!usize {
728 return writeSplat(w, &.{&.{byte}}, n);
729}
730
731/// Writes the same slice many times, performing the underlying write call as
732/// many times as necessary.
733pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {
734 var remaining_bytes: usize = bytes.len * splat;
735 remaining_bytes -= try w.splatBytes(bytes, splat);
736 while (remaining_bytes > 0) {
737 const leftover = remaining_bytes % bytes.len;
738 const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes };
739 remaining_bytes -= try w.splatBytes(&buffers, splat);
48740 }
49741}
50742
51pub inline fn writeInt(self: Self, comptime T: type, value: T, endian: std.builtin.Endian) anyerror!void {
743/// Writes the same slice many times, allowing short writes.
744///
745/// Does maximum of one underlying `VTable.writeSplat`.
746pub fn splatBytes(w: *Writer, bytes: []const u8, n: usize) Error!usize {
747 return writeSplat(w, &.{bytes}, n);
748}
749
750/// Asserts the `buffer` was initialized with a capacity of at least `@sizeOf(T)` bytes.
751pub inline fn writeInt(w: *Writer, comptime T: type, value: T, endian: std.builtin.Endian) Error!void {
52752 var bytes: [@divExact(@typeInfo(T).int.bits, 8)]u8 = undefined;
53 mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
54 return self.writeAll(&bytes);
753 std.mem.writeInt(std.math.ByteAlignedInt(@TypeOf(value)), &bytes, value, endian);
754 return w.writeAll(&bytes);
55755}
56756
57pub fn writeStruct(self: Self, value: anytype) anyerror!void {
757pub fn writeStruct(w: *Writer, value: anytype) Error!void {
58758 // Only extern and packed structs have defined in-memory layout.
59759 comptime assert(@typeInfo(@TypeOf(value)).@"struct".layout != .auto);
60 return self.writeAll(mem.asBytes(&value));
760 return w.writeAll(std.mem.asBytes(&value));
761}
762
763/// The function is inline to avoid the dead code in case `endian` is
764/// comptime-known and matches host endianness.
765/// TODO: make sure this value is not a reference type
766pub inline fn writeStructEndian(w: *Writer, value: anytype, endian: std.builtin.Endian) Error!void {
767 switch (@typeInfo(@TypeOf(value))) {
768 .@"struct" => |info| switch (info.layout) {
769 .auto => @compileError("ill-defined memory layout"),
770 .@"extern" => {
771 if (native_endian == endian) {
772 return w.writeStruct(value);
773 } else {
774 var copy = value;
775 std.mem.byteSwapAllFields(@TypeOf(value), &copy);
776 return w.writeStruct(copy);
777 }
778 },
779 .@"packed" => {
780 return writeInt(w, info.backing_integer.?, @bitCast(value), endian);
781 },
782 },
783 else => @compileError("not a struct"),
784 }
61785}
62786
63pub fn writeStructEndian(self: Self, value: anytype, endian: std.builtin.Endian) anyerror!void {
64 // TODO: make sure this value is not a reference type
787pub inline fn writeSliceEndian(
788 w: *Writer,
789 Elem: type,
790 slice: []const Elem,
791 endian: std.builtin.Endian,
792) Error!void {
65793 if (native_endian == endian) {
66 return self.writeStruct(value);
794 return writeAll(w, @ptrCast(slice));
795 } else {
796 return w.writeArraySwap(w, Elem, slice);
797 }
798}
799
800/// Unlike `writeSplat` and `writeVec`, this function will call into `VTable`
801/// even if there is enough buffer capacity for the file contents.
802///
803/// Although it would be possible to eliminate `error.Unimplemented` from the
804/// error set by reading directly into the buffer in such case, this is not
805/// done because it is more efficient to do it higher up the call stack so that
806/// the error does not occur with each write.
807///
808/// See `sendFileReading` for an alternative that does not have
809/// `error.Unimplemented` in the error set.
810pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
811 return w.vtable.sendFile(w, file_reader, limit);
812}
813
814/// Returns how many bytes from `header` and `file_reader` were consumed.
815pub fn sendFileHeader(
816 w: *Writer,
817 header: []const u8,
818 file_reader: *File.Reader,
819 limit: Limit,
820) FileError!usize {
821 const new_end = w.end + header.len;
822 if (new_end <= w.buffer.len) {
823 @memcpy(w.buffer[w.end..][0..header.len], header);
824 w.end = new_end;
825 return header.len + try w.vtable.sendFile(w, file_reader, limit);
826 }
827 const buffered_contents = limit.slice(file_reader.interface.buffered());
828 const n = try w.vtable.drain(w, &.{ header, buffered_contents }, 1);
829 file_reader.interface.toss(n - header.len);
830 return n;
831}
832
833/// Asserts nonzero buffer capacity.
834pub fn sendFileReading(w: *Writer, file_reader: *File.Reader, limit: Limit) FileReadingError!usize {
835 const dest = limit.slice(try w.writableSliceGreedy(1));
836 const n = try file_reader.read(dest);
837 w.advance(n);
838 return n;
839}
840
841/// Number of bytes logically written is returned. This excludes bytes from
842/// `buffer` because they have already been logically written.
843pub fn sendFileAll(w: *Writer, file_reader: *File.Reader, limit: Limit) FileAllError!usize {
844 var remaining = @intFromEnum(limit);
845 while (remaining > 0) {
846 const n = sendFile(w, file_reader, .limited(remaining)) catch |err| switch (err) {
847 error.EndOfStream => break,
848 error.Unimplemented => {
849 file_reader.mode = file_reader.mode.toReading();
850 remaining -= try w.sendFileReadingAll(file_reader, .limited(remaining));
851 break;
852 },
853 else => |e| return e,
854 };
855 remaining -= n;
856 }
857 return @intFromEnum(limit) - remaining;
858}
859
860/// Equivalent to `sendFileAll` but uses direct `pread` and `read` calls on
861/// `file` rather than `sendFile`. This is generally used as a fallback when
862/// the underlying implementation returns `error.Unimplemented`, which is why
863/// that error code does not appear in this function's error set.
864///
865/// Asserts nonzero buffer capacity.
866pub fn sendFileReadingAll(w: *Writer, file_reader: *File.Reader, limit: Limit) FileAllError!usize {
867 var remaining = @intFromEnum(limit);
868 while (remaining > 0) {
869 remaining -= sendFileReading(w, file_reader, .limited(remaining)) catch |err| switch (err) {
870 error.EndOfStream => break,
871 else => |e| return e,
872 };
873 }
874 return @intFromEnum(limit) - remaining;
875}
876
877pub fn alignBuffer(
878 w: *Writer,
879 buffer: []const u8,
880 width: usize,
881 alignment: std.fmt.Alignment,
882 fill: u8,
883) Error!void {
884 const padding = if (buffer.len < width) width - buffer.len else 0;
885 if (padding == 0) {
886 @branchHint(.likely);
887 return w.writeAll(buffer);
888 }
889 switch (alignment) {
890 .left => {
891 try w.writeAll(buffer);
892 try w.splatByteAll(fill, padding);
893 },
894 .center => {
895 const left_padding = padding / 2;
896 const right_padding = (padding + 1) / 2;
897 try w.splatByteAll(fill, left_padding);
898 try w.writeAll(buffer);
899 try w.splatByteAll(fill, right_padding);
900 },
901 .right => {
902 try w.splatByteAll(fill, padding);
903 try w.writeAll(buffer);
904 },
905 }
906}
907
908pub fn alignBufferOptions(w: *Writer, buffer: []const u8, options: std.fmt.Options) Error!void {
909 return w.alignBuffer(buffer, options.width orelse buffer.len, options.alignment, options.fill);
910}
911
912pub fn printAddress(w: *Writer, value: anytype) Error!void {
913 const T = @TypeOf(value);
914 switch (@typeInfo(T)) {
915 .pointer => |info| {
916 try w.writeAll(@typeName(info.child) ++ "@");
917 const int = if (info.size == .slice) @intFromPtr(value.ptr) else @intFromPtr(value);
918 return w.printInt(int, 16, .lower, .{});
919 },
920 .optional => |info| {
921 if (@typeInfo(info.child) == .pointer) {
922 try w.writeAll(@typeName(info.child) ++ "@");
923 try w.printInt(@intFromPtr(value), 16, .lower, .{});
924 return;
925 }
926 },
927 else => {},
928 }
929
930 @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier");
931}
932
933pub fn printValue(
934 w: *Writer,
935 comptime fmt: []const u8,
936 options: std.fmt.Options,
937 value: anytype,
938 max_depth: usize,
939) Error!void {
940 const T = @TypeOf(value);
941
942 switch (fmt.len) {
943 1 => switch (fmt[0]) {
944 '*' => return w.printAddress(value),
945 'f' => return value.format(w),
946 'd' => switch (@typeInfo(T)) {
947 .float, .comptime_float => return printFloat(w, value, options.toNumber(.decimal, .lower)),
948 .int, .comptime_int => return printInt(w, value, 10, .lower, options),
949 .@"struct" => return value.formatNumber(w, options.toNumber(.decimal, .lower)),
950 .@"enum" => return printInt(w, @intFromEnum(value), 10, .lower, options),
951 .vector => return printVector(w, fmt, options, value, max_depth),
952 else => invalidFmtError(fmt, value),
953 },
954 'c' => return w.printAsciiChar(value, options),
955 'u' => return w.printUnicodeCodepoint(value),
956 'b' => switch (@typeInfo(T)) {
957 .int, .comptime_int => return printInt(w, value, 2, .lower, options),
958 .@"enum" => return printInt(w, @intFromEnum(value), 2, .lower, options),
959 .@"struct" => return value.formatNumber(w, options.toNumber(.binary, .lower)),
960 .vector => return printVector(w, fmt, options, value, max_depth),
961 else => invalidFmtError(fmt, value),
962 },
963 'o' => switch (@typeInfo(T)) {
964 .int, .comptime_int => return printInt(w, value, 8, .lower, options),
965 .@"enum" => return printInt(w, @intFromEnum(value), 8, .lower, options),
966 .@"struct" => return value.formatNumber(w, options.toNumber(.octal, .lower)),
967 .vector => return printVector(w, fmt, options, value, max_depth),
968 else => invalidFmtError(fmt, value),
969 },
970 'x' => switch (@typeInfo(T)) {
971 .float, .comptime_float => return printFloatHexOptions(w, value, options.toNumber(.hex, .lower)),
972 .int, .comptime_int => return printInt(w, value, 16, .lower, options),
973 .@"enum" => return printInt(w, @intFromEnum(value), 16, .lower, options),
974 .@"struct" => return value.formatNumber(w, options.toNumber(.hex, .lower)),
975 .pointer => |info| switch (info.size) {
976 .one, .slice => {
977 const slice: []const u8 = value;
978 optionsForbidden(options);
979 return printHex(w, slice, .lower);
980 },
981 .many, .c => {
982 const slice: [:0]const u8 = std.mem.span(value);
983 optionsForbidden(options);
984 return printHex(w, slice, .lower);
985 },
986 },
987 .array => {
988 const slice: []const u8 = &value;
989 optionsForbidden(options);
990 return printHex(w, slice, .lower);
991 },
992 .vector => return printVector(w, fmt, options, value, max_depth),
993 else => invalidFmtError(fmt, value),
994 },
995 'X' => switch (@typeInfo(T)) {
996 .float, .comptime_float => return printFloatHexOptions(w, value, options.toNumber(.hex, .lower)),
997 .int, .comptime_int => return printInt(w, value, 16, .upper, options),
998 .@"enum" => return printInt(w, @intFromEnum(value), 16, .upper, options),
999 .@"struct" => return value.formatNumber(w, options.toNumber(.hex, .upper)),
1000 .pointer => |info| switch (info.size) {
1001 .one, .slice => {
1002 const slice: []const u8 = value;
1003 optionsForbidden(options);
1004 return printHex(w, slice, .upper);
1005 },
1006 .many, .c => {
1007 const slice: [:0]const u8 = std.mem.span(value);
1008 optionsForbidden(options);
1009 return printHex(w, slice, .upper);
1010 },
1011 },
1012 .array => {
1013 const slice: []const u8 = &value;
1014 optionsForbidden(options);
1015 return printHex(w, slice, .upper);
1016 },
1017 .vector => return printVector(w, fmt, options, value, max_depth),
1018 else => invalidFmtError(fmt, value),
1019 },
1020 's' => switch (@typeInfo(T)) {
1021 .pointer => |info| switch (info.size) {
1022 .one, .slice => {
1023 const slice: []const u8 = value;
1024 return w.alignBufferOptions(slice, options);
1025 },
1026 .many, .c => {
1027 const slice: [:0]const u8 = std.mem.span(value);
1028 return w.alignBufferOptions(slice, options);
1029 },
1030 },
1031 .array => {
1032 const slice: []const u8 = &value;
1033 return w.alignBufferOptions(slice, options);
1034 },
1035 else => invalidFmtError(fmt, value),
1036 },
1037 'B' => switch (@typeInfo(T)) {
1038 .int, .comptime_int => return w.printByteSize(value, .decimal, options),
1039 .@"struct" => return value.formatByteSize(w, .decimal),
1040 else => invalidFmtError(fmt, value),
1041 },
1042 'D' => switch (@typeInfo(T)) {
1043 .int, .comptime_int => return w.printDuration(value, options),
1044 .@"struct" => return value.formatDuration(w),
1045 else => invalidFmtError(fmt, value),
1046 },
1047 'e' => switch (@typeInfo(T)) {
1048 .float, .comptime_float => return printFloat(w, value, options.toNumber(.scientific, .lower)),
1049 .@"struct" => return value.formatNumber(w, options.toNumber(.scientific, .lower)),
1050 else => invalidFmtError(fmt, value),
1051 },
1052 'E' => switch (@typeInfo(T)) {
1053 .float, .comptime_float => return printFloat(w, value, options.toNumber(.scientific, .upper)),
1054 .@"struct" => return value.formatNumber(w, options.toNumber(.scientific, .upper)),
1055 else => invalidFmtError(fmt, value),
1056 },
1057 't' => switch (@typeInfo(T)) {
1058 .error_set => return w.writeAll(@errorName(value)),
1059 .@"enum", .@"union" => return w.writeAll(@tagName(value)),
1060 else => invalidFmtError(fmt, value),
1061 },
1062 else => {},
1063 },
1064 2 => switch (fmt[0]) {
1065 'B' => switch (fmt[1]) {
1066 'i' => switch (@typeInfo(T)) {
1067 .int, .comptime_int => return w.printByteSize(value, .binary, options),
1068 .@"struct" => return value.formatByteSize(w, .binary),
1069 else => invalidFmtError(fmt, value),
1070 },
1071 else => {},
1072 },
1073 else => {},
1074 },
1075 3 => if (fmt[0] == 'b' and fmt[1] == '6' and fmt[2] == '4') switch (@typeInfo(T)) {
1076 .pointer => |info| switch (info.size) {
1077 .one, .slice => {
1078 const slice: []const u8 = value;
1079 optionsForbidden(options);
1080 return w.printBase64(slice);
1081 },
1082 .many, .c => {
1083 const slice: [:0]const u8 = std.mem.span(value);
1084 optionsForbidden(options);
1085 return w.printBase64(slice);
1086 },
1087 },
1088 .array => {
1089 const slice: []const u8 = &value;
1090 optionsForbidden(options);
1091 return w.printBase64(slice);
1092 },
1093 else => invalidFmtError(fmt, value),
1094 },
1095 else => {},
1096 }
1097
1098 const is_any = comptime std.mem.eql(u8, fmt, ANY);
1099 if (!is_any and std.meta.hasMethod(T, "format") and fmt.len == 0) {
1100 // after 0.15.0 is tagged, delete this compile error and its condition
1101 @compileError("ambiguous format string; specify {f} to call format method, or {any} to skip it");
1102 }
1103
1104 switch (@typeInfo(T)) {
1105 .float, .comptime_float => {
1106 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1107 return printFloat(w, value, options.toNumber(.decimal, .lower));
1108 },
1109 .int, .comptime_int => {
1110 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1111 return printInt(w, value, 10, .lower, options);
1112 },
1113 .bool => {
1114 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1115 const string: []const u8 = if (value) "true" else "false";
1116 return w.alignBufferOptions(string, options);
1117 },
1118 .void => {
1119 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1120 return w.alignBufferOptions("void", options);
1121 },
1122 .optional => {
1123 const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '?')
1124 stripOptionalOrErrorUnionSpec(fmt)
1125 else if (is_any)
1126 ANY
1127 else
1128 @compileError("cannot print optional without a specifier (i.e. {?} or {any})");
1129 if (value) |payload| {
1130 return w.printValue(remaining_fmt, options, payload, max_depth);
1131 } else {
1132 return w.alignBufferOptions("null", options);
1133 }
1134 },
1135 .error_union => {
1136 const remaining_fmt = comptime if (fmt.len > 0 and fmt[0] == '!')
1137 stripOptionalOrErrorUnionSpec(fmt)
1138 else if (is_any)
1139 ANY
1140 else
1141 @compileError("cannot print error union without a specifier (i.e. {!} or {any})");
1142 if (value) |payload| {
1143 return w.printValue(remaining_fmt, options, payload, max_depth);
1144 } else |err| {
1145 return w.printValue("", options, err, max_depth);
1146 }
1147 },
1148 .error_set => {
1149 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1150 optionsForbidden(options);
1151 return printErrorSet(w, value);
1152 },
1153 .@"enum" => |info| {
1154 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1155 optionsForbidden(options);
1156 if (info.is_exhaustive) {
1157 return printEnumExhaustive(w, value);
1158 } else {
1159 return printEnumNonexhaustive(w, value);
1160 }
1161 },
1162 .@"union" => |info| {
1163 if (!is_any) {
1164 if (fmt.len != 0) invalidFmtError(fmt, value);
1165 return printValue(w, ANY, options, value, max_depth);
1166 }
1167 if (max_depth == 0) {
1168 try w.writeAll(".{ ... }");
1169 return;
1170 }
1171 if (info.tag_type) |UnionTagType| {
1172 try w.writeAll(".{ .");
1173 try w.writeAll(@tagName(@as(UnionTagType, value)));
1174 try w.writeAll(" = ");
1175 inline for (info.fields) |u_field| {
1176 if (value == @field(UnionTagType, u_field.name)) {
1177 try w.printValue(ANY, options, @field(value, u_field.name), max_depth - 1);
1178 }
1179 }
1180 try w.writeAll(" }");
1181 } else switch (info.layout) {
1182 .auto => {
1183 return w.writeAll(".{ ... }");
1184 },
1185 .@"extern", .@"packed" => {
1186 if (info.fields.len == 0) return w.writeAll(".{}");
1187 try w.writeAll(".{ ");
1188 inline for (info.fields) |field| {
1189 try w.writeByte('.');
1190 try w.writeAll(field.name);
1191 try w.writeAll(" = ");
1192 try w.printValue(ANY, options, @field(value, field.name), max_depth - 1);
1193 (try w.writableArray(2)).* = ", ".*;
1194 }
1195 w.buffer[w.end - 2 ..][0..2].* = " }".*;
1196 },
1197 }
1198 },
1199 .@"struct" => |info| {
1200 if (!is_any) {
1201 if (fmt.len != 0) invalidFmtError(fmt, value);
1202 return printValue(w, ANY, options, value, max_depth);
1203 }
1204 if (info.is_tuple) {
1205 // Skip the type and field names when formatting tuples.
1206 if (max_depth == 0) {
1207 try w.writeAll(".{ ... }");
1208 return;
1209 }
1210 try w.writeAll(".{");
1211 inline for (info.fields, 0..) |f, i| {
1212 if (i == 0) {
1213 try w.writeAll(" ");
1214 } else {
1215 try w.writeAll(", ");
1216 }
1217 try w.printValue(ANY, options, @field(value, f.name), max_depth - 1);
1218 }
1219 try w.writeAll(" }");
1220 return;
1221 }
1222 if (max_depth == 0) {
1223 try w.writeAll(".{ ... }");
1224 return;
1225 }
1226 try w.writeAll(".{");
1227 inline for (info.fields, 0..) |f, i| {
1228 if (i == 0) {
1229 try w.writeAll(" .");
1230 } else {
1231 try w.writeAll(", .");
1232 }
1233 try w.writeAll(f.name);
1234 try w.writeAll(" = ");
1235 try w.printValue(ANY, options, @field(value, f.name), max_depth - 1);
1236 }
1237 try w.writeAll(" }");
1238 },
1239 .pointer => |ptr_info| switch (ptr_info.size) {
1240 .one => switch (@typeInfo(ptr_info.child)) {
1241 .array => |array_info| return w.printValue(fmt, options, @as([]const array_info.child, value), max_depth),
1242 .@"enum", .@"union", .@"struct" => return w.printValue(fmt, options, value.*, max_depth),
1243 else => {
1244 var buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" };
1245 try w.writeVecAll(&buffers);
1246 try w.printInt(@intFromPtr(value), 16, .lower, options);
1247 return;
1248 },
1249 },
1250 .many, .c => {
1251 if (!is_any) @compileError("cannot format pointer without a specifier (i.e. {s} or {*})");
1252 optionsForbidden(options);
1253 try w.printAddress(value);
1254 },
1255 .slice => {
1256 if (!is_any)
1257 @compileError("cannot format slice without a specifier (i.e. {s}, {x}, {b64}, or {any})");
1258 if (max_depth == 0) return w.writeAll("{ ... }");
1259 try w.writeAll("{ ");
1260 for (value, 0..) |elem, i| {
1261 try w.printValue(fmt, options, elem, max_depth - 1);
1262 if (i != value.len - 1) {
1263 try w.writeAll(", ");
1264 }
1265 }
1266 try w.writeAll(" }");
1267 },
1268 },
1269 .array => {
1270 if (!is_any) @compileError("cannot format array without a specifier (i.e. {s} or {any})");
1271 if (max_depth == 0) return w.writeAll("{ ... }");
1272 try w.writeAll("{ ");
1273 for (value, 0..) |elem, i| {
1274 try w.printValue(fmt, options, elem, max_depth - 1);
1275 if (i < value.len - 1) {
1276 try w.writeAll(", ");
1277 }
1278 }
1279 try w.writeAll(" }");
1280 },
1281 .vector => {
1282 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1283 return printVector(w, fmt, options, value, max_depth);
1284 },
1285 .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"),
1286 .type => {
1287 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1288 return w.alignBufferOptions(@typeName(value), options);
1289 },
1290 .enum_literal => {
1291 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1292 optionsForbidden(options);
1293 var vecs: [2][]const u8 = .{ ".", @tagName(value) };
1294 return w.writeVecAll(&vecs);
1295 },
1296 .null => {
1297 if (!is_any and fmt.len != 0) invalidFmtError(fmt, value);
1298 return w.alignBufferOptions("null", options);
1299 },
1300 else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"),
1301 }
1302}
1303
1304fn optionsForbidden(options: std.fmt.Options) void {
1305 assert(options.precision == null);
1306 assert(options.width == null);
1307}
1308
1309fn printErrorSet(w: *Writer, error_set: anyerror) Error!void {
1310 var vecs: [2][]const u8 = .{ "error.", @errorName(error_set) };
1311 try w.writeVecAll(&vecs);
1312}
1313
1314fn printEnumExhaustive(w: *Writer, value: anytype) Error!void {
1315 var vecs: [2][]const u8 = .{ ".", @tagName(value) };
1316 try w.writeVecAll(&vecs);
1317}
1318
1319fn printEnumNonexhaustive(w: *Writer, value: anytype) Error!void {
1320 if (std.enums.tagName(@TypeOf(value), value)) |tag_name| {
1321 var vecs: [2][]const u8 = .{ ".", tag_name };
1322 try w.writeVecAll(&vecs);
1323 return;
1324 }
1325 try w.writeAll("@enumFromInt(");
1326 try w.printInt(@intFromEnum(value), 10, .lower, .{});
1327 try w.writeByte(')');
1328}
1329
1330pub fn printVector(
1331 w: *Writer,
1332 comptime fmt: []const u8,
1333 options: std.fmt.Options,
1334 value: anytype,
1335 max_depth: usize,
1336) Error!void {
1337 const len = @typeInfo(@TypeOf(value)).vector.len;
1338 if (max_depth == 0) return w.writeAll("{ ... }");
1339 try w.writeAll("{ ");
1340 inline for (0..len) |i| {
1341 try w.printValue(fmt, options, value[i], max_depth - 1);
1342 if (i < len - 1) try w.writeAll(", ");
1343 }
1344 try w.writeAll(" }");
1345}
1346
1347// A wrapper around `printIntAny` to avoid the generic explosion of this
1348// function by funneling smaller integer types through `isize` and `usize`.
1349pub inline fn printInt(
1350 w: *Writer,
1351 value: anytype,
1352 base: u8,
1353 case: std.fmt.Case,
1354 options: std.fmt.Options,
1355) Error!void {
1356 switch (@TypeOf(value)) {
1357 isize, usize => {},
1358 comptime_int => {
1359 if (comptime std.math.cast(usize, value)) |x| return printIntAny(w, x, base, case, options);
1360 if (comptime std.math.cast(isize, value)) |x| return printIntAny(w, x, base, case, options);
1361 const Int = std.math.IntFittingRange(value, value);
1362 return printIntAny(w, @as(Int, value), base, case, options);
1363 },
1364 else => switch (@typeInfo(@TypeOf(value)).int.signedness) {
1365 .signed => if (std.math.cast(isize, value)) |x| return printIntAny(w, x, base, case, options),
1366 .unsigned => if (std.math.cast(usize, value)) |x| return printIntAny(w, x, base, case, options),
1367 },
1368 }
1369 return printIntAny(w, value, base, case, options);
1370}
1371
1372/// In general, prefer `printInt` to avoid generic explosion. However this
1373/// function may be used when optimal codegen for a particular integer type is
1374/// desired.
1375pub fn printIntAny(
1376 w: *Writer,
1377 value: anytype,
1378 base: u8,
1379 case: std.fmt.Case,
1380 options: std.fmt.Options,
1381) Error!void {
1382 assert(base >= 2);
1383 const value_info = @typeInfo(@TypeOf(value)).int;
1384
1385 // The type must have the same size as `base` or be wider in order for the
1386 // division to work
1387 const min_int_bits = comptime @max(value_info.bits, 8);
1388 const MinInt = std.meta.Int(.unsigned, min_int_bits);
1389
1390 const abs_value = @abs(value);
1391 // The worst case in terms of space needed is base 2, plus 1 for the sign
1392 var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined;
1393
1394 var a: MinInt = abs_value;
1395 var index: usize = buf.len;
1396
1397 if (base == 10) {
1398 while (a >= 100) : (a = @divTrunc(a, 100)) {
1399 index -= 2;
1400 buf[index..][0..2].* = std.fmt.digits2(@intCast(a % 100));
1401 }
1402
1403 if (a < 10) {
1404 index -= 1;
1405 buf[index] = '0' + @as(u8, @intCast(a));
1406 } else {
1407 index -= 2;
1408 buf[index..][0..2].* = std.fmt.digits2(@intCast(a));
1409 }
1410 } else {
1411 while (true) {
1412 const digit = a % base;
1413 index -= 1;
1414 buf[index] = std.fmt.digitToChar(@intCast(digit), case);
1415 a /= base;
1416 if (a == 0) break;
1417 }
1418 }
1419
1420 if (value_info.signedness == .signed) {
1421 if (value < 0) {
1422 // Negative integer
1423 index -= 1;
1424 buf[index] = '-';
1425 } else if (options.width == null or options.width.? == 0) {
1426 // Positive integer, omit the plus sign
1427 } else {
1428 // Positive integer
1429 index -= 1;
1430 buf[index] = '+';
1431 }
1432 }
1433
1434 return w.alignBufferOptions(buf[index..], options);
1435}
1436
1437pub fn printAsciiChar(w: *Writer, c: u8, options: std.fmt.Options) Error!void {
1438 return w.alignBufferOptions(@as(*const [1]u8, &c), options);
1439}
1440
1441pub fn printAscii(w: *Writer, bytes: []const u8, options: std.fmt.Options) Error!void {
1442 return w.alignBufferOptions(bytes, options);
1443}
1444
1445pub fn printUnicodeCodepoint(w: *Writer, c: u21) Error!void {
1446 var buf: [4]u8 = undefined;
1447 const len = std.unicode.utf8Encode(c, &buf) catch |err| switch (err) {
1448 error.Utf8CannotEncodeSurrogateHalf, error.CodepointTooLarge => l: {
1449 buf[0..3].* = std.unicode.replacement_character_utf8;
1450 break :l 3;
1451 },
1452 };
1453 return w.writeAll(buf[0..len]);
1454}
1455
1456/// Uses a larger stack buffer; asserts mode is decimal or scientific.
1457pub fn printFloat(w: *Writer, value: anytype, options: std.fmt.Number) Error!void {
1458 const mode: std.fmt.float.Mode = switch (options.mode) {
1459 .decimal => .decimal,
1460 .scientific => .scientific,
1461 .binary, .octal, .hex => unreachable,
1462 };
1463 var buf: [std.fmt.float.bufferSize(.decimal, f64)]u8 = undefined;
1464 const s = std.fmt.float.render(&buf, value, .{
1465 .mode = mode,
1466 .precision = options.precision,
1467 }) catch |err| switch (err) {
1468 error.BufferTooSmall => "(float)",
1469 };
1470 return w.alignBuffer(s, options.width orelse s.len, options.alignment, options.fill);
1471}
1472
1473/// Uses a smaller stack buffer; asserts mode is not decimal or scientific.
1474pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number) Error!void {
1475 var buf: [50]u8 = undefined; // for aligning
1476 var sub_writer: Writer = .fixed(&buf);
1477 switch (options.mode) {
1478 .decimal => unreachable,
1479 .scientific => unreachable,
1480 .binary => @panic("TODO"),
1481 .octal => @panic("TODO"),
1482 .hex => {},
1483 }
1484 printFloatHex(&sub_writer, value, options.case, options.precision) catch unreachable; // buf is large enough
1485
1486 const printed = sub_writer.buffered();
1487 return w.alignBuffer(printed, options.width orelse printed.len, options.alignment, options.fill);
1488}
1489
1490pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
1491 if (std.math.signbit(value)) try w.writeByte('-');
1492 if (std.math.isNan(value)) return w.writeAll(switch (case) {
1493 .lower => "nan",
1494 .upper => "NAN",
1495 });
1496 if (std.math.isInf(value)) return w.writeAll(switch (case) {
1497 .lower => "inf",
1498 .upper => "INF",
1499 });
1500
1501 const T = @TypeOf(value);
1502 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
1503
1504 const mantissa_bits = std.math.floatMantissaBits(T);
1505 const fractional_bits = std.math.floatFractionalBits(T);
1506 const exponent_bits = std.math.floatExponentBits(T);
1507 const mantissa_mask = (1 << mantissa_bits) - 1;
1508 const exponent_mask = (1 << exponent_bits) - 1;
1509 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
1510
1511 const as_bits: TU = @bitCast(value);
1512 var mantissa = as_bits & mantissa_mask;
1513 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
1514
1515 const is_denormal = exponent == 0 and mantissa != 0;
1516 const is_zero = exponent == 0 and mantissa == 0;
1517
1518 if (is_zero) {
1519 // Handle this case here to simplify the logic below.
1520 try w.writeAll("0x0");
1521 if (opt_precision) |precision| {
1522 if (precision > 0) {
1523 try w.writeAll(".");
1524 try w.splatByteAll('0', precision);
1525 }
1526 } else {
1527 try w.writeAll(".0");
1528 }
1529 try w.writeAll("p0");
1530 return;
1531 }
1532
1533 if (is_denormal) {
1534 // Adjust the exponent for printing.
1535 exponent += 1;
671536 } else {
68 var copy = value;
69 mem.byteSwapAllFields(@TypeOf(value), &copy);
70 return self.writeStruct(copy);
1537 if (fractional_bits == mantissa_bits)
1538 mantissa |= 1 << fractional_bits; // Add the implicit integer bit.
1539 }
1540
1541 const mantissa_digits = (fractional_bits + 3) / 4;
1542 // Fill in zeroes to round the fraction width to a multiple of 4.
1543 mantissa <<= mantissa_digits * 4 - fractional_bits;
1544
1545 if (opt_precision) |precision| {
1546 // Round if needed.
1547 if (precision < mantissa_digits) {
1548 // We always have at least 4 extra bits.
1549 var extra_bits = (mantissa_digits - precision) * 4;
1550 // The result LSB is the Guard bit, we need two more (Round and
1551 // Sticky) to round the value.
1552 while (extra_bits > 2) {
1553 mantissa = (mantissa >> 1) | (mantissa & 1);
1554 extra_bits -= 1;
1555 }
1556 // Round to nearest, tie to even.
1557 mantissa |= @intFromBool(mantissa & 0b100 != 0);
1558 mantissa += 1;
1559 // Drop the excess bits.
1560 mantissa >>= 2;
1561 // Restore the alignment.
1562 mantissa <<= @as(std.math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4));
1563
1564 const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0;
1565 // Prefer a normalized result in case of overflow.
1566 if (overflow) {
1567 mantissa >>= 1;
1568 exponent += 1;
1569 }
1570 }
1571 }
1572
1573 // +1 for the decimal part.
1574 var buf: [1 + mantissa_digits]u8 = undefined;
1575 assert(std.fmt.printInt(&buf, mantissa, 16, case, .{ .fill = '0', .width = 1 + mantissa_digits }) == buf.len);
1576
1577 try w.writeAll("0x");
1578 try w.writeByte(buf[0]);
1579 const trimmed = std.mem.trimRight(u8, buf[1..], "0");
1580 if (opt_precision) |precision| {
1581 if (precision > 0) try w.writeAll(".");
1582 } else if (trimmed.len > 0) {
1583 try w.writeAll(".");
711584 }
1585 try w.writeAll(trimmed);
1586 // Add trailing zeros if explicitly requested.
1587 if (opt_precision) |precision| if (precision > 0) {
1588 if (precision > trimmed.len)
1589 try w.splatByteAll('0', precision - trimmed.len);
1590 };
1591 try w.writeAll("p");
1592 try w.printInt(exponent - exponent_bias, 10, case, .{});
1593}
1594
1595pub const ByteSizeUnits = enum {
1596 /// This formatter represents the number as multiple of 1000 and uses the SI
1597 /// measurement units (kB, MB, GB, ...).
1598 decimal,
1599 /// This formatter represents the number as multiple of 1024 and uses the IEC
1600 /// measurement units (KiB, MiB, GiB, ...).
1601 binary,
1602};
1603
1604/// Format option `precision` is ignored when `value` is less than 1kB
1605pub fn printByteSize(
1606 w: *std.io.Writer,
1607 value: u64,
1608 comptime units: ByteSizeUnits,
1609 options: std.fmt.Options,
1610) Error!void {
1611 if (value == 0) return w.alignBufferOptions("0B", options);
1612 // The worst case in terms of space needed is 32 bytes + 3 for the suffix.
1613 var buf: [std.fmt.float.min_buffer_size + 3]u8 = undefined;
1614
1615 const mags_si = " kMGTPEZY";
1616 const mags_iec = " KMGTPEZY";
1617
1618 const log2 = std.math.log2(value);
1619 const base = switch (units) {
1620 .decimal => 1000,
1621 .binary => 1024,
1622 };
1623 const magnitude = switch (units) {
1624 .decimal => @min(log2 / comptime std.math.log2(1000), mags_si.len - 1),
1625 .binary => @min(log2 / 10, mags_iec.len - 1),
1626 };
1627 const new_value = std.math.lossyCast(f64, value) / std.math.pow(f64, std.math.lossyCast(f64, base), std.math.lossyCast(f64, magnitude));
1628 const suffix = switch (units) {
1629 .decimal => mags_si[magnitude],
1630 .binary => mags_iec[magnitude],
1631 };
1632
1633 const s = switch (magnitude) {
1634 0 => buf[0..std.fmt.printInt(&buf, value, 10, .lower, .{})],
1635 else => std.fmt.float.render(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) {
1636 error.BufferTooSmall => unreachable,
1637 },
1638 };
1639
1640 var i: usize = s.len;
1641 if (suffix == ' ') {
1642 buf[i] = 'B';
1643 i += 1;
1644 } else switch (units) {
1645 .decimal => {
1646 buf[i..][0..2].* = [_]u8{ suffix, 'B' };
1647 i += 2;
1648 },
1649 .binary => {
1650 buf[i..][0..3].* = [_]u8{ suffix, 'i', 'B' };
1651 i += 3;
1652 },
1653 }
1654
1655 return w.alignBufferOptions(buf[0..i], options);
1656}
1657
1658// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948
1659const ANY = "any";
1660
1661fn stripOptionalOrErrorUnionSpec(comptime fmt: []const u8) []const u8 {
1662 return if (std.mem.eql(u8, fmt[1..], ANY))
1663 ANY
1664 else
1665 fmt[1..];
721666}
731667
74pub fn writeFile(self: Self, file: std.fs.File) anyerror!void {
75 // TODO: figure out how to adjust std lib abstractions so that this ends up
76 // doing sendfile or maybe even copy_file_range under the right conditions.
77 var buf: [4000]u8 = undefined;
1668pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) noreturn {
1669 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
1670}
1671
1672pub fn printDurationSigned(w: *Writer, ns: i64) Error!void {
1673 if (ns < 0) try w.writeByte('-');
1674 return w.printDurationUnsigned(@abs(ns));
1675}
1676
1677pub fn printDurationUnsigned(w: *Writer, ns: u64) Error!void {
1678 var ns_remaining = ns;
1679 inline for (.{
1680 .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' },
1681 .{ .ns = std.time.ns_per_week, .sep = 'w' },
1682 .{ .ns = std.time.ns_per_day, .sep = 'd' },
1683 .{ .ns = std.time.ns_per_hour, .sep = 'h' },
1684 .{ .ns = std.time.ns_per_min, .sep = 'm' },
1685 }) |unit| {
1686 if (ns_remaining >= unit.ns) {
1687 const units = ns_remaining / unit.ns;
1688 try w.printInt(units, 10, .lower, .{});
1689 try w.writeByte(unit.sep);
1690 ns_remaining -= units * unit.ns;
1691 if (ns_remaining == 0) return;
1692 }
1693 }
1694
1695 inline for (.{
1696 .{ .ns = std.time.ns_per_s, .sep = "s" },
1697 .{ .ns = std.time.ns_per_ms, .sep = "ms" },
1698 .{ .ns = std.time.ns_per_us, .sep = "us" },
1699 }) |unit| {
1700 const kunits = ns_remaining * 1000 / unit.ns;
1701 if (kunits >= 1000) {
1702 try w.printInt(kunits / 1000, 10, .lower, .{});
1703 const frac = kunits % 1000;
1704 if (frac > 0) {
1705 // Write up to 3 decimal places
1706 var decimal_buf = [_]u8{ '.', 0, 0, 0 };
1707 var inner: Writer = .fixed(decimal_buf[1..]);
1708 inner.printInt(frac, 10, .lower, .{ .fill = '0', .width = 3 }) catch unreachable;
1709 var end: usize = 4;
1710 while (end > 1) : (end -= 1) {
1711 if (decimal_buf[end - 1] != '0') break;
1712 }
1713 try w.writeAll(decimal_buf[0..end]);
1714 }
1715 return w.writeAll(unit.sep);
1716 }
1717 }
1718
1719 try w.printInt(ns_remaining, 10, .lower, .{});
1720 try w.writeAll("ns");
1721}
1722
1723/// Writes number of nanoseconds according to its signed magnitude:
1724/// `[#y][#w][#d][#h][#m]#[.###][n|u|m]s`
1725/// `nanoseconds` must be an integer that coerces into `u64` or `i64`.
1726pub fn printDuration(w: *Writer, nanoseconds: anytype, options: std.fmt.Options) Error!void {
1727 // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24
1728 var buf: [24]u8 = undefined;
1729 var sub_writer: Writer = .fixed(&buf);
1730 if (@TypeOf(nanoseconds) == comptime_int) {
1731 if (nanoseconds >= 0) {
1732 sub_writer.printDurationUnsigned(nanoseconds) catch unreachable;
1733 } else {
1734 sub_writer.printDurationSigned(nanoseconds) catch unreachable;
1735 }
1736 } else switch (@typeInfo(@TypeOf(nanoseconds)).int.signedness) {
1737 .signed => sub_writer.printDurationSigned(nanoseconds) catch unreachable,
1738 .unsigned => sub_writer.printDurationUnsigned(nanoseconds) catch unreachable,
1739 }
1740 return w.alignBufferOptions(sub_writer.buffered(), options);
1741}
1742
1743pub fn printHex(w: *Writer, bytes: []const u8, case: std.fmt.Case) Error!void {
1744 const charset = switch (case) {
1745 .upper => "0123456789ABCDEF",
1746 .lower => "0123456789abcdef",
1747 };
1748 for (bytes) |c| {
1749 try w.writeByte(charset[c >> 4]);
1750 try w.writeByte(charset[c & 15]);
1751 }
1752}
1753
1754pub fn printBase64(w: *Writer, bytes: []const u8) Error!void {
1755 var chunker = std.mem.window(u8, bytes, 3, 3);
1756 var temp: [5]u8 = undefined;
1757 while (chunker.next()) |chunk| {
1758 try w.writeAll(std.base64.standard.Encoder.encode(&temp, chunk));
1759 }
1760}
1761
1762/// Write a single unsigned integer as LEB128 to the given writer.
1763pub fn writeUleb128(w: *Writer, value: anytype) Error!void {
1764 try w.writeLeb128(switch (@typeInfo(@TypeOf(value))) {
1765 .comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value),
1766 .int => |value_info| switch (value_info.signedness) {
1767 .signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)),
1768 .unsigned => value,
1769 },
1770 else => comptime unreachable,
1771 });
1772}
1773
1774/// Write a single signed integer as LEB128 to the given writer.
1775pub fn writeSleb128(w: *Writer, value: anytype) Error!void {
1776 try w.writeLeb128(switch (@typeInfo(@TypeOf(value))) {
1777 .comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value),
1778 .int => |value_info| switch (value_info.signedness) {
1779 .signed => value,
1780 .unsigned => @as(@Type(.{ .int = .{ .signedness = .signed, .bits = value_info.bits + 1 } }), value),
1781 },
1782 else => comptime unreachable,
1783 });
1784}
1785
1786/// Write a single integer as LEB128 to the given writer.
1787pub fn writeLeb128(w: *Writer, value: anytype) Error!void {
1788 const value_info = @typeInfo(@TypeOf(value)).int;
1789 try w.writeMultipleOf7Leb128(@as(@Type(.{ .int = .{
1790 .signedness = value_info.signedness,
1791 .bits = std.mem.alignForwardAnyAlign(u16, value_info.bits, 7),
1792 } }), value));
1793}
1794
1795fn writeMultipleOf7Leb128(w: *Writer, value: anytype) Error!void {
1796 const value_info = @typeInfo(@TypeOf(value)).int;
1797 comptime assert(value_info.bits % 7 == 0);
1798 var remaining = value;
781799 while (true) {
79 const n = try file.readAll(&buf);
80 try self.writeAll(buf[0..n]);
81 if (n < buf.len) return;
1800 const buffer: []packed struct(u8) { bits: u7, more: bool } = @ptrCast(try w.writableSliceGreedy(1));
1801 for (buffer, 1..) |*byte, len| {
1802 const more = switch (value_info.signedness) {
1803 .signed => remaining >> 6 != remaining >> (value_info.bits - 1),
1804 .unsigned => remaining > std.math.maxInt(u7),
1805 };
1806 byte.* = if (@inComptime()) @typeInfo(@TypeOf(buffer)).pointer.child{
1807 .bits = @bitCast(@as(@Type(.{ .int = .{
1808 .signedness = value_info.signedness,
1809 .bits = 7,
1810 } }), @truncate(remaining))),
1811 .more = more,
1812 } else .{
1813 .bits = @bitCast(@as(@Type(.{ .int = .{
1814 .signedness = value_info.signedness,
1815 .bits = 7,
1816 } }), @truncate(remaining))),
1817 .more = more,
1818 };
1819 if (value_info.bits > 7) remaining >>= 7;
1820 if (!more) return w.advance(len);
1821 }
1822 w.advance(buffer.len);
1823 }
1824}
1825
1826test "printValue max_depth" {
1827 const Vec2 = struct {
1828 const SelfType = @This();
1829 x: f32,
1830 y: f32,
1831
1832 pub fn format(self: SelfType, w: *Writer) Error!void {
1833 return w.print("({d:.3},{d:.3})", .{ self.x, self.y });
1834 }
1835 };
1836 const E = enum {
1837 One,
1838 Two,
1839 Three,
1840 };
1841 const TU = union(enum) {
1842 const SelfType = @This();
1843 float: f32,
1844 int: u32,
1845 ptr: ?*SelfType,
1846 };
1847 const S = struct {
1848 const SelfType = @This();
1849 a: ?*SelfType,
1850 tu: TU,
1851 e: E,
1852 vec: Vec2,
1853 };
1854
1855 var inst = S{
1856 .a = null,
1857 .tu = TU{ .ptr = null },
1858 .e = E.Two,
1859 .vec = Vec2{ .x = 10.2, .y = 2.22 },
1860 };
1861 inst.a = &inst;
1862 inst.tu.ptr = &inst.tu;
1863
1864 var buf: [1000]u8 = undefined;
1865 var w: Writer = .fixed(&buf);
1866 try w.printValue("", .{}, inst, 0);
1867 try testing.expectEqualStrings(".{ ... }", w.buffered());
1868
1869 w = .fixed(&buf);
1870 try w.printValue("", .{}, inst, 1);
1871 try testing.expectEqualStrings(".{ .a = .{ ... }, .tu = .{ ... }, .e = .Two, .vec = .{ ... } }", w.buffered());
1872
1873 w = .fixed(&buf);
1874 try w.printValue("", .{}, inst, 2);
1875 try testing.expectEqualStrings(".{ .a = .{ .a = .{ ... }, .tu = .{ ... }, .e = .Two, .vec = .{ ... } }, .tu = .{ .ptr = .{ ... } }, .e = .Two, .vec = .{ .x = 10.2, .y = 2.22 } }", w.buffered());
1876
1877 w = .fixed(&buf);
1878 try w.printValue("", .{}, inst, 3);
1879 try testing.expectEqualStrings(".{ .a = .{ .a = .{ .a = .{ ... }, .tu = .{ ... }, .e = .Two, .vec = .{ ... } }, .tu = .{ .ptr = .{ ... } }, .e = .Two, .vec = .{ .x = 10.2, .y = 2.22 } }, .tu = .{ .ptr = .{ .ptr = .{ ... } } }, .e = .Two, .vec = .{ .x = 10.2, .y = 2.22 } }", w.buffered());
1880
1881 const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 };
1882 w = .fixed(&buf);
1883 try w.printValue("", .{}, vec, 0);
1884 try testing.expectEqualStrings("{ ... }", w.buffered());
1885
1886 w = .fixed(&buf);
1887 try w.printValue("", .{}, vec, 1);
1888 try testing.expectEqualStrings("{ 1, 2, 3, 4 }", w.buffered());
1889}
1890
1891test printDuration {
1892 try testDurationCase("0ns", 0);
1893 try testDurationCase("1ns", 1);
1894 try testDurationCase("999ns", std.time.ns_per_us - 1);
1895 try testDurationCase("1us", std.time.ns_per_us);
1896 try testDurationCase("1.45us", 1450);
1897 try testDurationCase("1.5us", 3 * std.time.ns_per_us / 2);
1898 try testDurationCase("14.5us", 14500);
1899 try testDurationCase("145us", 145000);
1900 try testDurationCase("999.999us", std.time.ns_per_ms - 1);
1901 try testDurationCase("1ms", std.time.ns_per_ms + 1);
1902 try testDurationCase("1.5ms", 3 * std.time.ns_per_ms / 2);
1903 try testDurationCase("1.11ms", 1110000);
1904 try testDurationCase("1.111ms", 1111000);
1905 try testDurationCase("1.111ms", 1111100);
1906 try testDurationCase("999.999ms", std.time.ns_per_s - 1);
1907 try testDurationCase("1s", std.time.ns_per_s);
1908 try testDurationCase("59.999s", std.time.ns_per_min - 1);
1909 try testDurationCase("1m", std.time.ns_per_min);
1910 try testDurationCase("1h", std.time.ns_per_hour);
1911 try testDurationCase("1d", std.time.ns_per_day);
1912 try testDurationCase("1w", std.time.ns_per_week);
1913 try testDurationCase("1y", 365 * std.time.ns_per_day);
1914 try testDurationCase("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1
1915 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);
1916 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);
1917 try testDurationCase("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1);
1918 try testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms);
1919 try testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1);
1920 try testDurationCase("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999);
1921 try testDurationCase("584y49w23h34m33.709s", std.math.maxInt(u64));
1922
1923 try testing.expectFmt("=======0ns", "{D:=>10}", .{0});
1924 try testing.expectFmt("1ns=======", "{D:=<10}", .{1});
1925 try testing.expectFmt(" 999ns ", "{D:^10}", .{std.time.ns_per_us - 1});
1926}
1927
1928test printDurationSigned {
1929 try testDurationCaseSigned("0ns", 0);
1930 try testDurationCaseSigned("1ns", 1);
1931 try testDurationCaseSigned("-1ns", -(1));
1932 try testDurationCaseSigned("999ns", std.time.ns_per_us - 1);
1933 try testDurationCaseSigned("-999ns", -(std.time.ns_per_us - 1));
1934 try testDurationCaseSigned("1us", std.time.ns_per_us);
1935 try testDurationCaseSigned("-1us", -(std.time.ns_per_us));
1936 try testDurationCaseSigned("1.45us", 1450);
1937 try testDurationCaseSigned("-1.45us", -(1450));
1938 try testDurationCaseSigned("1.5us", 3 * std.time.ns_per_us / 2);
1939 try testDurationCaseSigned("-1.5us", -(3 * std.time.ns_per_us / 2));
1940 try testDurationCaseSigned("14.5us", 14500);
1941 try testDurationCaseSigned("-14.5us", -(14500));
1942 try testDurationCaseSigned("145us", 145000);
1943 try testDurationCaseSigned("-145us", -(145000));
1944 try testDurationCaseSigned("999.999us", std.time.ns_per_ms - 1);
1945 try testDurationCaseSigned("-999.999us", -(std.time.ns_per_ms - 1));
1946 try testDurationCaseSigned("1ms", std.time.ns_per_ms + 1);
1947 try testDurationCaseSigned("-1ms", -(std.time.ns_per_ms + 1));
1948 try testDurationCaseSigned("1.5ms", 3 * std.time.ns_per_ms / 2);
1949 try testDurationCaseSigned("-1.5ms", -(3 * std.time.ns_per_ms / 2));
1950 try testDurationCaseSigned("1.11ms", 1110000);
1951 try testDurationCaseSigned("-1.11ms", -(1110000));
1952 try testDurationCaseSigned("1.111ms", 1111000);
1953 try testDurationCaseSigned("-1.111ms", -(1111000));
1954 try testDurationCaseSigned("1.111ms", 1111100);
1955 try testDurationCaseSigned("-1.111ms", -(1111100));
1956 try testDurationCaseSigned("999.999ms", std.time.ns_per_s - 1);
1957 try testDurationCaseSigned("-999.999ms", -(std.time.ns_per_s - 1));
1958 try testDurationCaseSigned("1s", std.time.ns_per_s);
1959 try testDurationCaseSigned("-1s", -(std.time.ns_per_s));
1960 try testDurationCaseSigned("59.999s", std.time.ns_per_min - 1);
1961 try testDurationCaseSigned("-59.999s", -(std.time.ns_per_min - 1));
1962 try testDurationCaseSigned("1m", std.time.ns_per_min);
1963 try testDurationCaseSigned("-1m", -(std.time.ns_per_min));
1964 try testDurationCaseSigned("1h", std.time.ns_per_hour);
1965 try testDurationCaseSigned("-1h", -(std.time.ns_per_hour));
1966 try testDurationCaseSigned("1d", std.time.ns_per_day);
1967 try testDurationCaseSigned("-1d", -(std.time.ns_per_day));
1968 try testDurationCaseSigned("1w", std.time.ns_per_week);
1969 try testDurationCaseSigned("-1w", -(std.time.ns_per_week));
1970 try testDurationCaseSigned("1y", 365 * std.time.ns_per_day);
1971 try testDurationCaseSigned("-1y", -(365 * std.time.ns_per_day));
1972 try testDurationCaseSigned("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1d
1973 try testDurationCaseSigned("-1y52w23h59m59.999s", -(730 * std.time.ns_per_day - 1)); // 365d = 52w1d
1974 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);
1975 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));
1976 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);
1977 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));
1978 try testDurationCaseSigned("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1);
1979 try testDurationCaseSigned("-1y1h999.999us", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1));
1980 try testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms);
1981 try testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms));
1982 try testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1);
1983 try testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1));
1984 try testDurationCaseSigned("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999);
1985 try testDurationCaseSigned("-1y1m999ns", -(365 * std.time.ns_per_day + std.time.ns_per_min + 999));
1986 try testDurationCaseSigned("292y24w3d23h47m16.854s", std.math.maxInt(i64));
1987 try testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64) + 1);
1988 try testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64));
1989
1990 try testing.expectFmt("=======0ns", "{D:=>10}", .{0});
1991 try testing.expectFmt("1ns=======", "{D:=<10}", .{1});
1992 try testing.expectFmt("-1ns======", "{D:=<10}", .{-(1)});
1993 try testing.expectFmt(" -999ns ", "{D:^10}", .{-(std.time.ns_per_us - 1)});
1994}
1995
1996fn testDurationCase(expected: []const u8, input: u64) !void {
1997 var buf: [24]u8 = undefined;
1998 var w: Writer = .fixed(&buf);
1999 try w.printDurationUnsigned(input);
2000 try testing.expectEqualStrings(expected, w.buffered());
2001}
2002
2003fn testDurationCaseSigned(expected: []const u8, input: i64) !void {
2004 var buf: [24]u8 = undefined;
2005 var w: Writer = .fixed(&buf);
2006 try w.printDurationSigned(input);
2007 try testing.expectEqualStrings(expected, w.buffered());
2008}
2009
2010test printInt {
2011 try testPrintIntCase("-1", @as(i1, -1), 10, .lower, .{});
2012
2013 try testPrintIntCase("-101111000110000101001110", @as(i32, -12345678), 2, .lower, .{});
2014 try testPrintIntCase("-12345678", @as(i32, -12345678), 10, .lower, .{});
2015 try testPrintIntCase("-bc614e", @as(i32, -12345678), 16, .lower, .{});
2016 try testPrintIntCase("-BC614E", @as(i32, -12345678), 16, .upper, .{});
2017
2018 try testPrintIntCase("12345678", @as(u32, 12345678), 10, .upper, .{});
2019
2020 try testPrintIntCase(" 666", @as(u32, 666), 10, .lower, .{ .width = 6 });
2021 try testPrintIntCase(" 1234", @as(u32, 0x1234), 16, .lower, .{ .width = 6 });
2022 try testPrintIntCase("1234", @as(u32, 0x1234), 16, .lower, .{ .width = 1 });
2023
2024 try testPrintIntCase("+42", @as(i32, 42), 10, .lower, .{ .width = 3 });
2025 try testPrintIntCase("-42", @as(i32, -42), 10, .lower, .{ .width = 3 });
2026
2027 try testPrintIntCase("123456789123456789", @as(comptime_int, 123456789123456789), 10, .lower, .{});
2028}
2029
2030test "printFloat with comptime_float" {
2031 var buf: [20]u8 = undefined;
2032 var w: Writer = .fixed(&buf);
2033 try w.printFloat(@as(comptime_float, 1.0), std.fmt.Options.toNumber(.{}, .scientific, .lower));
2034 try testing.expectEqualStrings(w.buffered(), "1e0");
2035 try testing.expectFmt("1", "{}", .{1.0});
2036}
2037
2038fn testPrintIntCase(expected: []const u8, value: anytype, base: u8, case: std.fmt.Case, options: std.fmt.Options) !void {
2039 var buffer: [100]u8 = undefined;
2040 var w: Writer = .fixed(&buffer);
2041 try w.printInt(value, base, case, options);
2042 try testing.expectEqualStrings(expected, w.buffered());
2043}
2044
2045test printByteSize {
2046 try testing.expectFmt("file size: 42B\n", "file size: {B}\n", .{42});
2047 try testing.expectFmt("file size: 42B\n", "file size: {Bi}\n", .{42});
2048 try testing.expectFmt("file size: 63MB\n", "file size: {B}\n", .{63 * 1000 * 1000});
2049 try testing.expectFmt("file size: 63MiB\n", "file size: {Bi}\n", .{63 * 1024 * 1024});
2050 try testing.expectFmt("file size: 42B\n", "file size: {B:.2}\n", .{42});
2051 try testing.expectFmt("file size: 42B\n", "file size: {B:>9.2}\n", .{42});
2052 try testing.expectFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{63 * 1024 * 1024});
2053 try testing.expectFmt("file size: 60.08MiB\n", "file size: {Bi:.2}\n", .{63 * 1000 * 1000});
2054 try testing.expectFmt("file size: =66.06MB=\n", "file size: {B:=^9.2}\n", .{63 * 1024 * 1024});
2055 try testing.expectFmt("file size: 66.06MB\n", "file size: {B: >9.2}\n", .{63 * 1024 * 1024});
2056 try testing.expectFmt("file size: 66.06MB \n", "file size: {B: <9.2}\n", .{63 * 1024 * 1024});
2057 try testing.expectFmt("file size: 0.01844674407370955ZB\n", "file size: {B}\n", .{std.math.maxInt(u64)});
2058}
2059
2060test "bytes.hex" {
2061 const some_bytes = "\xCA\xFE\xBA\xBE";
2062 try testing.expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
2063 try testing.expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
2064 try testing.expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
2065 try testing.expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
2066 const bytes_with_zeros = "\x00\x0E\xBA\xBE";
2067 try testing.expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
2068}
2069
2070test fixed {
2071 {
2072 var buf: [255]u8 = undefined;
2073 var w: Writer = .fixed(&buf);
2074 try w.print("{s}{s}!", .{ "Hello", "World" });
2075 try testing.expectEqualStrings("HelloWorld!", w.buffered());
2076 }
2077
2078 comptime {
2079 var buf: [255]u8 = undefined;
2080 var w: Writer = .fixed(&buf);
2081 try w.print("{s}{s}!", .{ "Hello", "World" });
2082 try testing.expectEqualStrings("HelloWorld!", w.buffered());
2083 }
2084}
2085
2086test "fixed output" {
2087 var buffer: [10]u8 = undefined;
2088 var w: Writer = .fixed(&buffer);
2089
2090 try w.writeAll("Hello");
2091 try testing.expect(std.mem.eql(u8, w.buffered(), "Hello"));
2092
2093 try w.writeAll("world");
2094 try testing.expect(std.mem.eql(u8, w.buffered(), "Helloworld"));
2095
2096 try testing.expectError(error.WriteFailed, w.writeAll("!"));
2097 try testing.expect(std.mem.eql(u8, w.buffered(), "Helloworld"));
2098
2099 w = .fixed(&buffer);
2100
2101 try testing.expect(w.buffered().len == 0);
2102
2103 try testing.expectError(error.WriteFailed, w.writeAll("Hello world!"));
2104 try testing.expect(std.mem.eql(u8, w.buffered(), "Hello worl"));
2105}
2106
2107test "writeSplat 0 len splat larger than capacity" {
2108 var buf: [8]u8 = undefined;
2109 var w: std.io.Writer = .fixed(&buf);
2110 const n = try w.writeSplat(&.{"something that overflows buf"}, 0);
2111 try testing.expectEqual(0, n);
2112}
2113
2114pub fn failingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2115 _ = w;
2116 _ = data;
2117 _ = splat;
2118 return error.WriteFailed;
2119}
2120
2121pub fn failingSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
2122 _ = w;
2123 _ = file_reader;
2124 _ = limit;
2125 return error.WriteFailed;
2126}
2127
2128pub const Discarding = struct {
2129 count: u64,
2130 writer: Writer,
2131
2132 pub fn init(buffer: []u8) Discarding {
2133 return .{
2134 .count = 0,
2135 .writer = .{
2136 .vtable = &.{
2137 .drain = Discarding.drain,
2138 .sendFile = Discarding.sendFile,
2139 },
2140 .buffer = buffer,
2141 },
2142 };
822143 }
2144
2145 pub fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2146 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
2147 const slice = data[0 .. data.len - 1];
2148 const pattern = data[slice.len..];
2149 var written: usize = pattern.len * splat;
2150 for (slice) |bytes| written += bytes.len;
2151 d.count += w.end + written;
2152 w.end = 0;
2153 return written;
2154 }
2155
2156 pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
2157 if (File.Handle == void) return error.Unimplemented;
2158 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
2159 d.count += w.end;
2160 w.end = 0;
2161 if (file_reader.getSize()) |size| {
2162 const n = limit.minInt64(size - file_reader.pos);
2163 file_reader.seekBy(@intCast(n)) catch return error.Unimplemented;
2164 w.end = 0;
2165 d.count += n;
2166 return n;
2167 } else |_| {
2168 // Error is observable on `file_reader` instance, and it is better to
2169 // treat the file as a pipe.
2170 return error.Unimplemented;
2171 }
2172 }
2173};
2174
2175/// Removes the first `n` bytes from `buffer` by shifting buffer contents,
2176/// returning how many bytes are left after consuming the entire buffer, or
2177/// zero if the entire buffer was not consumed.
2178///
2179/// Useful for `VTable.drain` function implementations to implement partial
2180/// drains.
2181pub fn consume(w: *Writer, n: usize) usize {
2182 if (n < w.end) {
2183 const remaining = w.buffer[n..w.end];
2184 @memmove(w.buffer[0..remaining.len], remaining);
2185 w.end = remaining.len;
2186 return 0;
2187 }
2188 defer w.end = 0;
2189 return n - w.end;
2190}
2191
2192/// Shortcut for setting `end` to zero and returning zero. Equivalent to
2193/// calling `consume` with `end`.
2194pub fn consumeAll(w: *Writer) usize {
2195 w.end = 0;
2196 return 0;
832197}
2198
2199/// For use when the `Writer` implementation can cannot offer a more efficient
2200/// implementation than a basic read/write loop on the file.
2201pub fn unimplementedSendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
2202 _ = w;
2203 _ = file_reader;
2204 _ = limit;
2205 return error.Unimplemented;
2206}
2207
2208/// When this function is called it usually means the buffer got full, so it's
2209/// time to return an error. However, we still need to make sure all of the
2210/// available buffer has been filled. Also, it may be called from `flush` in
2211/// which case it should return successfully.
2212pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2213 if (data.len == 0) return 0;
2214 for (data[0 .. data.len - 1]) |bytes| {
2215 const dest = w.buffer[w.end..];
2216 const len = @min(bytes.len, dest.len);
2217 @memcpy(dest[0..len], bytes[0..len]);
2218 w.end += len;
2219 if (bytes.len > dest.len) return error.WriteFailed;
2220 }
2221 const pattern = data[data.len - 1];
2222 const dest = w.buffer[w.end..];
2223 switch (pattern.len) {
2224 0 => return w.end,
2225 1 => {
2226 assert(splat >= dest.len);
2227 @memset(dest, pattern[0]);
2228 w.end += dest.len;
2229 return error.WriteFailed;
2230 },
2231 else => {
2232 for (0..splat) |i| {
2233 const remaining = dest[i * pattern.len ..];
2234 const len = @min(pattern.len, remaining.len);
2235 @memcpy(remaining[0..len], pattern[0..len]);
2236 w.end += len;
2237 if (pattern.len > remaining.len) return error.WriteFailed;
2238 }
2239 unreachable;
2240 },
2241 }
2242}
2243
2244/// Provides a `Writer` implementation based on calling `Hasher.update`, sending
2245/// all data also to an underlying `Writer`.
2246///
2247/// When using this, the underlying writer is best unbuffered because all
2248/// writes are passed on directly to it.
2249///
2250/// This implementation makes suboptimal buffering decisions due to being
2251/// generic. A better solution will involve creating a writer for each hash
2252/// function, where the splat buffer can be tailored to the hash implementation
2253/// details.
2254pub fn Hashed(comptime Hasher: type) type {
2255 return struct {
2256 out: *Writer,
2257 hasher: Hasher,
2258 writer: Writer,
2259
2260 pub fn init(out: *Writer, buffer: []u8) @This() {
2261 return .initHasher(out, .{}, buffer);
2262 }
2263
2264 pub fn initHasher(out: *Writer, hasher: Hasher, buffer: []u8) @This() {
2265 return .{
2266 .out = out,
2267 .hasher = hasher,
2268 .writer = .{
2269 .buffer = buffer,
2270 .vtable = &.{ .drain = @This().drain },
2271 },
2272 };
2273 }
2274
2275 fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2276 const this: *@This() = @alignCast(@fieldParentPtr("writer", w));
2277 const aux = w.buffered();
2278 const aux_n = try this.out.writeSplatHeader(aux, data, splat);
2279 if (aux_n < w.end) {
2280 this.hasher.update(w.buffer[0..aux_n]);
2281 const remaining = w.buffer[aux_n..w.end];
2282 @memmove(w.buffer[0..remaining.len], remaining);
2283 w.end = remaining.len;
2284 return 0;
2285 }
2286 this.hasher.update(aux);
2287 const n = aux_n - w.end;
2288 w.end = 0;
2289 var remaining: usize = n;
2290 for (data[0 .. data.len - 1]) |slice| {
2291 if (remaining <= slice.len) {
2292 this.hasher.update(slice[0..remaining]);
2293 return n;
2294 }
2295 remaining -= slice.len;
2296 this.hasher.update(slice);
2297 }
2298 const pattern = data[data.len - 1];
2299 assert(remaining == splat * pattern.len);
2300 switch (pattern.len) {
2301 0 => {
2302 assert(remaining == 0);
2303 },
2304 1 => {
2305 var buffer: [64]u8 = undefined;
2306 @memset(&buffer, pattern[0]);
2307 while (remaining > 0) {
2308 const update_len = @min(remaining, buffer.len);
2309 this.hasher.update(buffer[0..update_len]);
2310 remaining -= update_len;
2311 }
2312 },
2313 else => {
2314 while (remaining > 0) {
2315 const update_len = @min(remaining, pattern.len);
2316 this.hasher.update(pattern[0..update_len]);
2317 remaining -= update_len;
2318 }
2319 },
2320 }
2321 return n;
2322 }
2323 };
2324}
2325
2326/// Maintains `Writer` state such that it writes to the unused capacity of an
2327/// array list, filling it up completely before making a call through the
2328/// vtable, causing a resize. Consequently, the same, optimized, non-generic
2329/// machine code that uses `std.io.Reader`, such as formatted printing, takes
2330/// the hot paths when using this API.
2331///
2332/// When using this API, it is not necessary to call `flush`.
2333pub const Allocating = struct {
2334 allocator: Allocator,
2335 writer: Writer,
2336
2337 pub fn init(allocator: Allocator) Allocating {
2338 return .{
2339 .allocator = allocator,
2340 .writer = .{
2341 .buffer = &.{},
2342 .vtable = &vtable,
2343 },
2344 };
2345 }
2346
2347 pub fn initCapacity(allocator: Allocator, capacity: usize) error{OutOfMemory}!Allocating {
2348 return .{
2349 .allocator = allocator,
2350 .writer = .{
2351 .buffer = try allocator.alloc(u8, capacity),
2352 .vtable = &vtable,
2353 },
2354 };
2355 }
2356
2357 pub fn initOwnedSlice(allocator: Allocator, slice: []u8) Allocating {
2358 return .{
2359 .allocator = allocator,
2360 .writer = .{
2361 .buffer = slice,
2362 .vtable = &vtable,
2363 },
2364 };
2365 }
2366
2367 /// Replaces `array_list` with empty, taking ownership of the memory.
2368 pub fn fromArrayList(allocator: Allocator, array_list: *std.ArrayListUnmanaged(u8)) Allocating {
2369 defer array_list.* = .empty;
2370 return .{
2371 .allocator = allocator,
2372 .writer = .{
2373 .vtable = &vtable,
2374 .buffer = array_list.allocatedSlice(),
2375 .end = array_list.items.len,
2376 },
2377 };
2378 }
2379
2380 const vtable: VTable = .{
2381 .drain = Allocating.drain,
2382 .sendFile = Allocating.sendFile,
2383 .flush = noopFlush,
2384 };
2385
2386 pub fn deinit(a: *Allocating) void {
2387 a.allocator.free(a.writer.buffer);
2388 a.* = undefined;
2389 }
2390
2391 /// Returns an array list that takes ownership of the allocated memory.
2392 /// Resets the `Allocating` to an empty state.
2393 pub fn toArrayList(a: *Allocating) std.ArrayListUnmanaged(u8) {
2394 const w = &a.writer;
2395 const result: std.ArrayListUnmanaged(u8) = .{
2396 .items = w.buffer[0..w.end],
2397 .capacity = w.buffer.len,
2398 };
2399 w.buffer = &.{};
2400 w.end = 0;
2401 return result;
2402 }
2403
2404 pub fn toOwnedSlice(a: *Allocating) error{OutOfMemory}![]u8 {
2405 var list = a.toArrayList();
2406 return list.toOwnedSlice(a.allocator);
2407 }
2408
2409 pub fn toOwnedSliceSentinel(a: *Allocating, comptime sentinel: u8) error{OutOfMemory}![:sentinel]u8 {
2410 const gpa = a.allocator;
2411 var list = toArrayList(a);
2412 return list.toOwnedSliceSentinel(gpa, sentinel);
2413 }
2414
2415 pub fn getWritten(a: *Allocating) []u8 {
2416 return a.writer.buffered();
2417 }
2418
2419 pub fn shrinkRetainingCapacity(a: *Allocating, new_len: usize) void {
2420 a.writer.end = new_len;
2421 }
2422
2423 pub fn clearRetainingCapacity(a: *Allocating) void {
2424 a.shrinkRetainingCapacity(0);
2425 }
2426
2427 fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2428 const a: *Allocating = @fieldParentPtr("writer", w);
2429 const gpa = a.allocator;
2430 const pattern = data[data.len - 1];
2431 const splat_len = pattern.len * splat;
2432 var list = a.toArrayList();
2433 defer setArrayList(a, list);
2434 const start_len = list.items.len;
2435 // Even if we append no data, this function needs to ensure there is more
2436 // capacity in the buffer to avoid infinite loop, hence the +1 in this loop.
2437 assert(data.len != 0);
2438 for (data) |bytes| {
2439 list.ensureUnusedCapacity(gpa, bytes.len + splat_len + 1) catch return error.WriteFailed;
2440 list.appendSliceAssumeCapacity(bytes);
2441 }
2442 if (splat == 0) {
2443 list.items.len -= pattern.len;
2444 } else switch (pattern.len) {
2445 0 => {},
2446 1 => list.appendNTimesAssumeCapacity(pattern[0], splat - 1),
2447 else => for (0..splat - 1) |_| list.appendSliceAssumeCapacity(pattern),
2448 }
2449 return list.items.len - start_len;
2450 }
2451
2452 fn sendFile(w: *Writer, file_reader: *File.Reader, limit: std.io.Limit) FileError!usize {
2453 if (File.Handle == void) return error.Unimplemented;
2454 const a: *Allocating = @fieldParentPtr("writer", w);
2455 const gpa = a.allocator;
2456 var list = a.toArrayList();
2457 defer setArrayList(a, list);
2458 const pos = file_reader.pos;
2459 const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line;
2460 list.ensureUnusedCapacity(gpa, limit.minInt64(additional)) catch return error.WriteFailed;
2461 const dest = limit.slice(list.unusedCapacitySlice());
2462 const n = file_reader.read(dest) catch |err| switch (err) {
2463 error.ReadFailed => return error.ReadFailed,
2464 error.EndOfStream => 0,
2465 };
2466 list.items.len += n;
2467 return n;
2468 }
2469
2470 fn setArrayList(a: *Allocating, list: std.ArrayListUnmanaged(u8)) void {
2471 a.writer.buffer = list.allocatedSlice();
2472 a.writer.end = list.items.len;
2473 }
2474
2475 test Allocating {
2476 var a: Allocating = .init(testing.allocator);
2477 defer a.deinit();
2478 const w = &a.writer;
2479
2480 const x: i32 = 42;
2481 const y: i32 = 1234;
2482 try w.print("x: {}\ny: {}\n", .{ x, y });
2483
2484 try testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", a.getWritten());
2485 }
2486};
lib/std/io/buffered_atomic_file.zig+2-2
......@@ -11,7 +11,7 @@ pub const BufferedAtomicFile = struct {
1111
1212 pub const buffer_size = 4096;
1313 pub const BufferedWriter = std.io.BufferedWriter(buffer_size, File.Writer);
14 pub const Writer = std.io.Writer(*BufferedWriter, BufferedWriter.Error, BufferedWriter.write);
14 pub const Writer = std.io.GenericWriter(*BufferedWriter, BufferedWriter.Error, BufferedWriter.write);
1515
1616 /// TODO when https://github.com/ziglang/zig/issues/2761 is solved
1717 /// this API will not need an allocator
......@@ -33,7 +33,7 @@ pub const BufferedAtomicFile = struct {
3333 self.atomic_file = try dir.atomicFile(dest_path, atomic_file_options);
3434 errdefer self.atomic_file.deinit();
3535
36 self.file_writer = self.atomic_file.file.writer();
36 self.file_writer = self.atomic_file.file.deprecatedWriter();
3737 self.buffered_writer = .{ .unbuffered_writer = self.file_writer };
3838 return self;
3939 }
lib/std/io/buffered_reader.zig+3-3
......@@ -12,7 +12,7 @@ pub fn BufferedReader(comptime buffer_size: usize, comptime ReaderType: type) ty
1212 end: usize = 0,
1313
1414 pub const Error = ReaderType.Error;
15 pub const Reader = io.Reader(*Self, Error, read);
15 pub const Reader = io.GenericReader(*Self, Error, read);
1616
1717 const Self = @This();
1818
......@@ -61,7 +61,7 @@ test "OneByte" {
6161
6262 const Error = error{NoError};
6363 const Self = @This();
64 const Reader = io.Reader(*Self, Error, read);
64 const Reader = io.GenericReader(*Self, Error, read);
6565
6666 fn init(str: []const u8) Self {
6767 return Self{
......@@ -105,7 +105,7 @@ test "Block" {
105105
106106 const Error = error{NoError};
107107 const Self = @This();
108 const Reader = io.Reader(*Self, Error, read);
108 const Reader = io.GenericReader(*Self, Error, read);
109109
110110 fn init(block: []const u8, reads_allowed: usize) Self {
111111 return Self{
lib/std/io/buffered_writer.zig+1-1
......@@ -10,7 +10,7 @@ pub fn BufferedWriter(comptime buffer_size: usize, comptime WriterType: type) ty
1010 end: usize = 0,
1111
1212 pub const Error = WriterType.Error;
13 pub const Writer = io.Writer(*Self, Error, write);
13 pub const Writer = io.GenericWriter(*Self, Error, write);
1414
1515 const Self = @This();
1616
lib/std/io/c_writer.zig+1-1
......@@ -3,7 +3,7 @@ const builtin = @import("builtin");
33const io = std.io;
44const testing = std.testing;
55
6pub const CWriter = io.Writer(*std.c.FILE, std.fs.File.WriteError, cWriterWrite);
6pub const CWriter = io.GenericWriter(*std.c.FILE, std.fs.File.WriteError, cWriterWrite);
77
88pub fn cWriter(c_file: *std.c.FILE) CWriter {
99 return .{ .context = c_file };
lib/std/io/change_detection_stream.zig+1-1
......@@ -8,7 +8,7 @@ pub fn ChangeDetectionStream(comptime WriterType: type) type {
88 return struct {
99 const Self = @This();
1010 pub const Error = WriterType.Error;
11 pub const Writer = io.Writer(*Self, Error, write);
11 pub const Writer = io.GenericWriter(*Self, Error, write);
1212
1313 anything_changed: bool,
1414 underlying_writer: WriterType,
lib/std/io/counting_reader.zig+1-1
......@@ -9,7 +9,7 @@ pub fn CountingReader(comptime ReaderType: anytype) type {
99 bytes_read: u64 = 0,
1010
1111 pub const Error = ReaderType.Error;
12 pub const Reader = io.Reader(*@This(), Error, read);
12 pub const Reader = io.GenericReader(*@This(), Error, read);
1313
1414 pub fn read(self: *@This(), buf: []u8) Error!usize {
1515 const amt = try self.child_reader.read(buf);
lib/std/io/counting_writer.zig+1-1
......@@ -9,7 +9,7 @@ pub fn CountingWriter(comptime WriterType: type) type {
99 child_stream: WriterType,
1010
1111 pub const Error = WriterType.Error;
12 pub const Writer = io.Writer(*Self, Error, write);
12 pub const Writer = io.GenericWriter(*Self, Error, write);
1313
1414 const Self = @This();
1515
lib/std/io/find_byte_writer.zig+1-1
......@@ -8,7 +8,7 @@ pub fn FindByteWriter(comptime UnderlyingWriter: type) type {
88 return struct {
99 const Self = @This();
1010 pub const Error = UnderlyingWriter.Error;
11 pub const Writer = io.Writer(*Self, Error, write);
11 pub const Writer = io.GenericWriter(*Self, Error, write);
1212
1313 underlying_writer: UnderlyingWriter,
1414 byte_found: bool,
lib/std/io/fixed_buffer_stream.zig+4-4
......@@ -4,8 +4,8 @@ const testing = std.testing;
44const mem = std.mem;
55const assert = std.debug.assert;
66
7/// This turns a byte buffer into an `io.Writer`, `io.Reader`, or `io.SeekableStream`.
8/// If the supplied byte buffer is const, then `io.Writer` is not available.
7/// This turns a byte buffer into an `io.GenericWriter`, `io.GenericReader`, or `io.SeekableStream`.
8/// If the supplied byte buffer is const, then `io.GenericWriter` is not available.
99pub fn FixedBufferStream(comptime Buffer: type) type {
1010 return struct {
1111 /// `Buffer` is either a `[]u8` or `[]const u8`.
......@@ -17,8 +17,8 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
1717 pub const SeekError = error{};
1818 pub const GetSeekPosError = error{};
1919
20 pub const Reader = io.Reader(*Self, ReadError, read);
21 pub const Writer = io.Writer(*Self, WriteError, write);
20 pub const Reader = io.GenericReader(*Self, ReadError, read);
21 pub const Writer = io.GenericWriter(*Self, WriteError, write);
2222
2323 pub const SeekableStream = io.SeekableStream(
2424 *Self,
lib/std/io/limited_reader.zig+1-1
......@@ -9,7 +9,7 @@ pub fn LimitedReader(comptime ReaderType: type) type {
99 bytes_left: u64,
1010
1111 pub const Error = ReaderType.Error;
12 pub const Reader = io.Reader(*Self, Error, read);
12 pub const Reader = io.GenericReader(*Self, Error, read);
1313
1414 const Self = @This();
1515
lib/std/io/multi_writer.zig+1-1
......@@ -15,7 +15,7 @@ pub fn MultiWriter(comptime Writers: type) type {
1515 streams: Writers,
1616
1717 pub const Error = ErrSet;
18 pub const Writer = io.Writer(*Self, Error, write);
18 pub const Writer = io.GenericWriter(*Self, Error, write);
1919
2020 pub fn writer(self: *Self) Writer {
2121 return .{ .context = self };
lib/std/io/stream_source.zig+4-4
......@@ -2,9 +2,9 @@ const std = @import("../std.zig");
22const builtin = @import("builtin");
33const io = std.io;
44
5/// Provides `io.Reader`, `io.Writer`, and `io.SeekableStream` for in-memory buffers as
5/// Provides `io.GenericReader`, `io.GenericWriter`, and `io.SeekableStream` for in-memory buffers as
66/// well as files.
7/// For memory sources, if the supplied byte buffer is const, then `io.Writer` is not available.
7/// For memory sources, if the supplied byte buffer is const, then `io.GenericWriter` is not available.
88/// The error set of the stream functions is the error set of the corresponding file functions.
99pub const StreamSource = union(enum) {
1010 // TODO: expose UEFI files to std.os in a way that allows this to be true
......@@ -26,8 +26,8 @@ pub const StreamSource = union(enum) {
2626 pub const SeekError = io.FixedBufferStream([]u8).SeekError || (if (has_file) std.fs.File.SeekError else error{});
2727 pub const GetSeekPosError = io.FixedBufferStream([]u8).GetSeekPosError || (if (has_file) std.fs.File.GetSeekPosError else error{});
2828
29 pub const Reader = io.Reader(*StreamSource, ReadError, read);
30 pub const Writer = io.Writer(*StreamSource, WriteError, write);
29 pub const Reader = io.GenericReader(*StreamSource, ReadError, read);
30 pub const Writer = io.GenericWriter(*StreamSource, WriteError, write);
3131 pub const SeekableStream = io.SeekableStream(
3232 *StreamSource,
3333 SeekError,
lib/std/io/test.zig+4-4
......@@ -24,7 +24,7 @@ test "write a file, read it, then delete it" {
2424 var file = try tmp.dir.createFile(tmp_file_name, .{});
2525 defer file.close();
2626
27 var buf_stream = io.bufferedWriter(file.writer());
27 var buf_stream = io.bufferedWriter(file.deprecatedWriter());
2828 const st = buf_stream.writer();
2929 try st.print("begin", .{});
3030 try st.writeAll(data[0..]);
......@@ -45,7 +45,7 @@ test "write a file, read it, then delete it" {
4545 const expected_file_size: u64 = "begin".len + data.len + "end".len;
4646 try expectEqual(expected_file_size, file_size);
4747
48 var buf_stream = io.bufferedReader(file.reader());
48 var buf_stream = io.bufferedReader(file.deprecatedReader());
4949 const st = buf_stream.reader();
5050 const contents = try st.readAllAlloc(std.testing.allocator, 2 * 1024);
5151 defer std.testing.allocator.free(contents);
......@@ -66,7 +66,7 @@ test "BitStreams with File Stream" {
6666 var file = try tmp.dir.createFile(tmp_file_name, .{});
6767 defer file.close();
6868
69 var bit_stream = io.bitWriter(native_endian, file.writer());
69 var bit_stream = io.bitWriter(native_endian, file.deprecatedWriter());
7070
7171 try bit_stream.writeBits(@as(u2, 1), 1);
7272 try bit_stream.writeBits(@as(u5, 2), 2);
......@@ -80,7 +80,7 @@ test "BitStreams with File Stream" {
8080 var file = try tmp.dir.openFile(tmp_file_name, .{});
8181 defer file.close();
8282
83 var bit_stream = io.bitReader(native_endian, file.reader());
83 var bit_stream = io.bitReader(native_endian, file.deprecatedReader());
8484
8585 var out_bits: u16 = undefined;
8686
lib/std/io/tty.zig+39-36
......@@ -5,36 +5,9 @@ const process = std.process;
55const windows = std.os.windows;
66const native_os = builtin.os.tag;
77
8/// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
9/// This includes feature checks for ANSI escape codes and the Windows console API, as well as
10/// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default.
11/// Will attempt to enable ANSI escape code support if necessary/possible.
8/// Deprecated in favor of `Config.detect`.
129pub fn detectConfig(file: File) Config {
13 const force_color: ?bool = if (builtin.os.tag == .wasi)
14 null // wasi does not support environment variables
15 else if (process.hasNonEmptyEnvVarConstant("NO_COLOR"))
16 false
17 else if (process.hasNonEmptyEnvVarConstant("CLICOLOR_FORCE"))
18 true
19 else
20 null;
21
22 if (force_color == false) return .no_color;
23
24 if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;
25
26 if (native_os == .windows and file.isTty()) {
27 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
28 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) {
29 return if (force_color == true) .escape_codes else .no_color;
30 }
31 return .{ .windows_api = .{
32 .handle = file.handle,
33 .reset_attributes = info.wAttributes,
34 } };
35 }
36
37 return if (force_color == true) .escape_codes else .no_color;
10 return .detect(file);
3811}
3912
4013pub const Color = enum {
......@@ -66,17 +39,46 @@ pub const Config = union(enum) {
6639 escape_codes,
6740 windows_api: if (native_os == .windows) WindowsContext else void,
6841
42 /// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
43 /// This includes feature checks for ANSI escape codes and the Windows console API, as well as
44 /// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default.
45 /// Will attempt to enable ANSI escape code support if necessary/possible.
46 pub fn detect(file: File) Config {
47 const force_color: ?bool = if (builtin.os.tag == .wasi)
48 null // wasi does not support environment variables
49 else if (process.hasNonEmptyEnvVarConstant("NO_COLOR"))
50 false
51 else if (process.hasNonEmptyEnvVarConstant("CLICOLOR_FORCE"))
52 true
53 else
54 null;
55
56 if (force_color == false) return .no_color;
57
58 if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;
59
60 if (native_os == .windows and file.isTty()) {
61 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
62 if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) {
63 return if (force_color == true) .escape_codes else .no_color;
64 }
65 return .{ .windows_api = .{
66 .handle = file.handle,
67 .reset_attributes = info.wAttributes,
68 } };
69 }
70
71 return if (force_color == true) .escape_codes else .no_color;
72 }
73
6974 pub const WindowsContext = struct {
7075 handle: File.Handle,
7176 reset_attributes: u16,
7277 };
7378
74 pub fn setColor(
75 conf: Config,
76 writer: anytype,
77 color: Color,
78 ) (@typeInfo(@TypeOf(writer.writeAll(""))).error_union.error_set ||
79 windows.SetConsoleTextAttributeError)!void {
79 pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || std.io.Writer.Error;
80
81 pub fn setColor(conf: Config, w: *std.io.Writer, color: Color) SetColorError!void {
8082 nosuspend switch (conf) {
8183 .no_color => return,
8284 .escape_codes => {
......@@ -101,7 +103,7 @@ pub const Config = union(enum) {
101103 .dim => "\x1b[2m",
102104 .reset => "\x1b[0m",
103105 };
104 try writer.writeAll(color_string);
106 try w.writeAll(color_string);
105107 },
106108 .windows_api => |ctx| if (native_os == .windows) {
107109 const attributes = switch (color) {
......@@ -126,6 +128,7 @@ pub const Config = union(enum) {
126128 .dim => windows.FOREGROUND_INTENSITY,
127129 .reset => ctx.reset_attributes,
128130 };
131 try w.flush();
129132 try windows.SetConsoleTextAttribute(ctx.handle, attributes);
130133 } else {
131134 unreachable;
lib/std/json.zig+2-2
......@@ -1,12 +1,12 @@
11//! JSON parsing and stringification conforming to RFC 8259. https://datatracker.ietf.org/doc/html/rfc8259
22//!
33//! The low-level `Scanner` API produces `Token`s from an input slice or successive slices of inputs,
4//! The `Reader` API connects a `std.io.Reader` to a `Scanner`.
4//! The `Reader` API connects a `std.io.GenericReader` to a `Scanner`.
55//!
66//! The high-level `parseFromSlice` and `parseFromTokenSource` deserialize a JSON document into a Zig type.
77//! Parse into a dynamically-typed `Value` to load any JSON value for runtime inspection.
88//!
9//! The low-level `writeStream` emits syntax-conformant JSON tokens to a `std.io.Writer`.
9//! The low-level `writeStream` emits syntax-conformant JSON tokens to a `std.io.GenericWriter`.
1010//! The high-level `stringify` serializes a Zig or `Value` type into JSON.
1111
1212const builtin = @import("builtin");
lib/std/json/dynamic.zig+1-1
......@@ -56,7 +56,7 @@ pub const Value = union(enum) {
5656 std.debug.lockStdErr();
5757 defer std.debug.unlockStdErr();
5858
59 const stderr = std.io.getStdErr().writer();
59 const stderr = std.fs.File.stderr().deprecatedWriter();
6060 stringify(self, .{}, stderr) catch return;
6161 }
6262
lib/std/json/dynamic_test.zig+2-2
......@@ -254,7 +254,7 @@ test "Value.jsonStringify" {
254254 \\ true,
255255 \\ 42,
256256 \\ 43,
257 \\ 4.2e1,
257 \\ 42,
258258 \\ "weeee",
259259 \\ [
260260 \\ 1,
......@@ -266,7 +266,7 @@ test "Value.jsonStringify" {
266266 \\ }
267267 \\]
268268 ;
269 try testing.expectEqualSlices(u8, expected, fbs.getWritten());
269 try testing.expectEqualStrings(expected, fbs.getWritten());
270270}
271271
272272test "parseFromValue(std.json.Value,...)" {
lib/std/json/fmt.zig+3-9
......@@ -1,4 +1,5 @@
1const std = @import("std");
1const std = @import("../std.zig");
2const assert = std.debug.assert;
23
34const stringify = @import("stringify.zig").stringify;
45const StringifyOptions = @import("stringify.zig").StringifyOptions;
......@@ -14,14 +15,7 @@ pub fn Formatter(comptime T: type) type {
1415 value: T,
1516 options: StringifyOptions,
1617
17 pub fn format(
18 self: @This(),
19 comptime fmt_spec: []const u8,
20 options: std.fmt.FormatOptions,
21 writer: anytype,
22 ) !void {
23 _ = fmt_spec;
24 _ = options;
18 pub fn format(self: @This(), writer: *std.io.Writer) std.io.Writer.Error!void {
2519 try stringify(self.value, self.options, writer);
2620 }
2721 };
lib/std/json/scanner.zig+1-1
......@@ -219,7 +219,7 @@ pub const AllocWhen = enum { alloc_if_needed, alloc_always };
219219/// This limit can be specified by calling `nextAllocMax()` instead of `nextAlloc()`.
220220pub const default_max_value_len = 4 * 1024 * 1024;
221221
222/// Connects a `std.io.Reader` to a `std.json.Scanner`.
222/// Connects a `std.io.GenericReader` to a `std.json.Scanner`.
223223/// All `next*()` methods here handle `error.BufferUnderrun` from `std.json.Scanner`, and then read from the reader.
224224pub fn Reader(comptime buffer_size: usize, comptime ReaderType: type) type {
225225 return struct {
lib/std/json/stringify.zig+8-6
......@@ -38,7 +38,7 @@ pub const StringifyOptions = struct {
3838 emit_nonportable_numbers_as_strings: bool = false,
3939};
4040
41/// Writes the given value to the `std.io.Writer` stream.
41/// Writes the given value to the `std.io.GenericWriter` stream.
4242/// See `WriteStream` for how the given value is serialized into JSON.
4343/// The maximum nesting depth of the output JSON document is 256.
4444/// See also `stringifyMaxDepth` and `stringifyArbitraryDepth`.
......@@ -81,7 +81,7 @@ pub fn stringifyArbitraryDepth(
8181}
8282
8383/// Calls `stringifyArbitraryDepth` and stores the result in dynamically allocated memory
84/// instead of taking a `std.io.Writer`.
84/// instead of taking a `std.io.GenericWriter`.
8585///
8686/// Caller owns returned memory.
8787pub fn stringifyAlloc(
......@@ -469,7 +469,6 @@ pub fn WriteStream(
469469 /// * When option `emit_nonportable_numbers_as_strings` is true, if the value is outside the range `+-1<<53` (the precise integer range of f64), it is rendered as a JSON string in base 10. Otherwise, it is rendered as JSON number.
470470 /// * Zig floats -> JSON number or string.
471471 /// * If the value cannot be precisely represented by an f64, it is rendered as a JSON string. Otherwise, it is rendered as JSON number.
472 /// * TODO: Float rendering will likely change in the future, e.g. to remove the unnecessary "e+00".
473472 /// * Zig `[]const u8`, `[]u8`, `*[N]u8`, `@Vector(N, u8)`, and similar -> JSON string.
474473 /// * See `StringifyOptions.emit_strings_as_arrays`.
475474 /// * If the content is not valid UTF-8, rendered as an array of numbers instead.
......@@ -689,7 +688,8 @@ fn outputUnicodeEscape(codepoint: u21, out_stream: anytype) !void {
689688 // then it may be represented as a six-character sequence: a reverse solidus, followed
690689 // by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point.
691690 try out_stream.writeAll("\\u");
692 try std.fmt.formatIntValue(codepoint, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
691 //try w.printInt("x", .{ .width = 4, .fill = '0' }, codepoint);
692 try std.fmt.format(out_stream, "{x:0>4}", .{codepoint});
693693 } else {
694694 assert(codepoint <= 0x10FFFF);
695695 // To escape an extended character that is not in the Basic Multilingual Plane,
......@@ -697,9 +697,11 @@ fn outputUnicodeEscape(codepoint: u21, out_stream: anytype) !void {
697697 const high = @as(u16, @intCast((codepoint - 0x10000) >> 10)) + 0xD800;
698698 const low = @as(u16, @intCast(codepoint & 0x3FF)) + 0xDC00;
699699 try out_stream.writeAll("\\u");
700 try std.fmt.formatIntValue(high, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
700 //try w.printInt("x", .{ .width = 4, .fill = '0' }, high);
701 try std.fmt.format(out_stream, "{x:0>4}", .{high});
701702 try out_stream.writeAll("\\u");
702 try std.fmt.formatIntValue(low, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
703 //try w.printInt("x", .{ .width = 4, .fill = '0' }, low);
704 try std.fmt.format(out_stream, "{x:0>4}", .{low});
703705 }
704706}
705707
lib/std/json/stringify_test.zig+7-7
......@@ -74,16 +74,16 @@ fn testBasicWriteStream(w: anytype, slice_stream: anytype) !void {
7474 \\{
7575 \\ "object": {
7676 \\ "one": 1,
77 \\ "two": 2e0
77 \\ "two": 2
7878 \\ },
7979 \\ "string": "This is a string",
8080 \\ "array": [
8181 \\ "Another string",
8282 \\ 1,
83 \\ 3.5e0
83 \\ 3.5
8484 \\ ],
8585 \\ "int": 10,
86 \\ "float": 3.5e0
86 \\ "float": 3.5
8787 \\}
8888 ;
8989 try std.testing.expectEqualStrings(expected, result);
......@@ -123,12 +123,12 @@ test "stringify basic types" {
123123 try testStringify("null", @as(?u8, null), .{});
124124 try testStringify("null", @as(?*u32, null), .{});
125125 try testStringify("42", 42, .{});
126 try testStringify("4.2e1", 42.0, .{});
126 try testStringify("42", 42.0, .{});
127127 try testStringify("42", @as(u8, 42), .{});
128128 try testStringify("42", @as(u128, 42), .{});
129129 try testStringify("9999999999999999", 9999999999999999, .{});
130 try testStringify("4.2e1", @as(f32, 42), .{});
131 try testStringify("4.2e1", @as(f64, 42), .{});
130 try testStringify("42", @as(f32, 42), .{});
131 try testStringify("42", @as(f64, 42), .{});
132132 try testStringify("\"ItBroke\"", @as(anyerror, error.ItBroke), .{});
133133 try testStringify("\"ItBroke\"", error.ItBroke, .{});
134134}
......@@ -307,7 +307,7 @@ test "stringify tuple" {
307307fn testStringify(expected: []const u8, value: anytype, options: StringifyOptions) !void {
308308 const ValidationWriter = struct {
309309 const Self = @This();
310 pub const Writer = std.io.Writer(*Self, Error, write);
310 pub const Writer = std.io.GenericWriter(*Self, Error, write);
311311 pub const Error = error{
312312 TooMuchData,
313313 DifferentData,
lib/std/log.zig+2-2
......@@ -47,7 +47,7 @@
4747//! // Print the message to stderr, silently ignoring any errors
4848//! std.debug.lockStdErr();
4949//! defer std.debug.unlockStdErr();
50//! const stderr = std.io.getStdErr().writer();
50//! const stderr = std.fs.File.stderr().deprecatedWriter();
5151//! nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return;
5252//! }
5353//!
......@@ -148,7 +148,7 @@ pub fn defaultLog(
148148) void {
149149 const level_txt = comptime message_level.asText();
150150 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
151 const stderr = std.io.getStdErr().writer();
151 const stderr = std.fs.File.stderr().deprecatedWriter();
152152 var bw = std.io.bufferedWriter(stderr);
153153 const writer = bw.writer();
154154
lib/std/math/big/int.zig+21-39
......@@ -2028,6 +2028,14 @@ pub const Mutable = struct {
20282028 pub fn normalize(r: *Mutable, length: usize) void {
20292029 r.len = llnormalize(r.limbs[0..length]);
20302030 }
2031
2032 pub fn format(self: Mutable, w: *std.io.Writer) std.io.Writer.Error!void {
2033 return formatNumber(self, w, .{});
2034 }
2035
2036 pub fn formatNumber(self: Const, w: *std.io.Writer, n: std.fmt.Number) std.io.Writer.Error!void {
2037 return self.toConst().formatNumber(w, n);
2038 }
20312039};
20322040
20332041/// A arbitrary-precision big integer, with a fixed set of immutable limbs.
......@@ -2317,50 +2325,25 @@ pub const Const = struct {
23172325 return .{ normalized_res.reconstruct(if (self.positive) .positive else .negative), exactness };
23182326 }
23192327
2320 /// To allow `std.fmt.format` to work with this type.
23212328 /// If the absolute value of integer is greater than or equal to `pow(2, 64 * @sizeOf(usize) * 8)`,
23222329 /// this function will fail to print the string, printing "(BigInt)" instead of a number.
23232330 /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory.
23242331 /// See `toString` and `toStringAlloc` for a way to print big integers without failure.
2325 pub fn format(
2326 self: Const,
2327 comptime fmt: []const u8,
2328 options: std.fmt.FormatOptions,
2329 out_stream: anytype,
2330 ) !void {
2331 _ = options;
2332 comptime var base = 10;
2333 comptime var case: std.fmt.Case = .lower;
2334
2335 if (fmt.len == 0 or comptime mem.eql(u8, fmt, "d")) {
2336 base = 10;
2337 case = .lower;
2338 } else if (comptime mem.eql(u8, fmt, "b")) {
2339 base = 2;
2340 case = .lower;
2341 } else if (comptime mem.eql(u8, fmt, "x")) {
2342 base = 16;
2343 case = .lower;
2344 } else if (comptime mem.eql(u8, fmt, "X")) {
2345 base = 16;
2346 case = .upper;
2347 } else {
2348 std.fmt.invalidFmtError(fmt, self);
2349 }
2350
2332 pub fn formatNumber(self: Const, w: *std.io.Writer, number: std.fmt.Number) std.io.Writer.Error!void {
23512333 const available_len = 64;
23522334 if (self.limbs.len > available_len)
2353 return out_stream.writeAll("(BigInt)");
2335 return w.writeAll("(BigInt)");
23542336
2355 var limbs: [calcToStringLimbsBufferLen(available_len, base)]Limb = undefined;
2337 var limbs: [calcToStringLimbsBufferLen(available_len, 10)]Limb = undefined;
23562338
23572339 const biggest: Const = .{
23582340 .limbs = &([1]Limb{comptime math.maxInt(Limb)} ** available_len),
23592341 .positive = false,
23602342 };
2361 var buf: [biggest.sizeInBaseUpperBound(base)]u8 = undefined;
2362 const len = self.toString(&buf, base, case, &limbs);
2363 return out_stream.writeAll(buf[0..len]);
2343 var buf: [biggest.sizeInBaseUpperBound(2)]u8 = undefined;
2344 const base: u8 = number.mode.base() orelse @panic("TODO print big int in scientific form");
2345 const len = self.toString(&buf, base, number.case, &limbs);
2346 return w.writeAll(buf[0..len]);
23642347 }
23652348
23662349 /// Converts self to a string in the requested base.
......@@ -2930,17 +2913,16 @@ pub const Managed = struct {
29302913 }
29312914
29322915 /// To allow `std.fmt.format` to work with `Managed`.
2916 pub fn format(self: Managed, w: *std.io.Writer) std.io.Writer.Error!void {
2917 return formatNumber(self, w, .{});
2918 }
2919
29332920 /// If the absolute value of integer is greater than or equal to `pow(2, 64 * @sizeOf(usize) * 8)`,
29342921 /// this function will fail to print the string, printing "(BigInt)" instead of a number.
29352922 /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory.
29362923 /// See `toString` and `toStringAlloc` for a way to print big integers without failure.
2937 pub fn format(
2938 self: Managed,
2939 comptime fmt: []const u8,
2940 options: std.fmt.FormatOptions,
2941 out_stream: anytype,
2942 ) !void {
2943 return self.toConst().format(fmt, options, out_stream);
2924 pub fn formatNumber(self: Managed, w: *std.io.Writer, n: std.fmt.Number) std.io.Writer.Error!void {
2925 return self.toConst().formatNumber(w, n);
29442926 }
29452927
29462928 /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
lib/std/math/big/int_test.zig+4-7
......@@ -3813,13 +3813,10 @@ test "(BigInt) positive" {
38133813 try a.pow(&a, 64 * @sizeOf(Limb) * 8);
38143814 try b.sub(&a, &c);
38153815
3816 const a_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{a});
3817 defer testing.allocator.free(a_fmt);
3816 try testing.expectFmt("(BigInt)", "{d}", .{a});
38183817
3819 const b_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{b});
3818 const b_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{b});
38203819 defer testing.allocator.free(b_fmt);
3821
3822 try testing.expect(mem.eql(u8, a_fmt, "(BigInt)"));
38233820 try testing.expect(!mem.eql(u8, b_fmt, "(BigInt)"));
38243821}
38253822
......@@ -3838,10 +3835,10 @@ test "(BigInt) negative" {
38383835 a.negate();
38393836 try b.add(&a, &c);
38403837
3841 const a_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{a});
3838 const a_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{a});
38423839 defer testing.allocator.free(a_fmt);
38433840
3844 const b_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{b});
3841 const b_fmt = try std.fmt.allocPrint(testing.allocator, "{d}", .{b});
38453842 defer testing.allocator.free(b_fmt);
38463843
38473844 try testing.expect(mem.eql(u8, a_fmt, "(BigInt)"));
lib/std/mem.zig+4-2
......@@ -1714,7 +1714,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: Endian)
17141714 }
17151715 },
17161716 }
1717 return @as(ReturnType, @truncate(result));
1717 return @truncate(result);
17181718}
17191719
17201720test readVarInt {
......@@ -2196,7 +2196,9 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
21962196 }
21972197 }
21982198 },
2199 else => @compileError("byteSwapAllFields expects a struct or array as the first argument"),
2199 else => {
2200 ptr.* = @byteSwap(ptr.*);
2201 },
22002202 }
22012203}
22022204
lib/std/multi_array_list.zig+1
......@@ -991,6 +991,7 @@ test "0 sized struct" {
991991test "struct with many fields" {
992992 const ManyFields = struct {
993993 fn Type(count: comptime_int) type {
994 @setEvalBranchQuota(50000);
994995 var fields: [count]std.builtin.Type.StructField = undefined;
995996 for (0..count) |i| {
996997 fields[i] = .{
lib/std/net.zig+21-50
......@@ -161,22 +161,13 @@ pub const Address = extern union {
161161 }
162162 }
163163
164 pub fn format(
165 self: Address,
166 comptime fmt: []const u8,
167 options: std.fmt.FormatOptions,
168 out_stream: anytype,
169 ) !void {
170 if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
164 pub fn format(self: Address, w: *std.io.Writer) std.io.Writer.Error!void {
171165 switch (self.any.family) {
172 posix.AF.INET => try self.in.format(fmt, options, out_stream),
173 posix.AF.INET6 => try self.in6.format(fmt, options, out_stream),
166 posix.AF.INET => try self.in.format(w),
167 posix.AF.INET6 => try self.in6.format(w),
174168 posix.AF.UNIX => {
175 if (!has_unix_sockets) {
176 unreachable;
177 }
178
179 try std.fmt.format(out_stream, "{s}", .{std.mem.sliceTo(&self.un.path, 0)});
169 if (!has_unix_sockets) unreachable;
170 try w.writeAll(std.mem.sliceTo(&self.un.path, 0));
180171 },
181172 else => unreachable,
182173 }
......@@ -349,22 +340,9 @@ pub const Ip4Address = extern struct {
349340 self.sa.port = mem.nativeToBig(u16, port);
350341 }
351342
352 pub fn format(
353 self: Ip4Address,
354 comptime fmt: []const u8,
355 options: std.fmt.FormatOptions,
356 out_stream: anytype,
357 ) !void {
358 if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
359 _ = options;
360 const bytes = @as(*const [4]u8, @ptrCast(&self.sa.addr));
361 try std.fmt.format(out_stream, "{}.{}.{}.{}:{}", .{
362 bytes[0],
363 bytes[1],
364 bytes[2],
365 bytes[3],
366 self.getPort(),
367 });
343 pub fn format(self: Ip4Address, w: *std.io.Writer) std.io.Writer.Error!void {
344 const bytes: *const [4]u8 = @ptrCast(&self.sa.addr);
345 try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], self.getPort() });
368346 }
369347
370348 pub fn getOsSockLen(self: Ip4Address) posix.socklen_t {
......@@ -653,17 +631,10 @@ pub const Ip6Address = extern struct {
653631 self.sa.port = mem.nativeToBig(u16, port);
654632 }
655633
656 pub fn format(
657 self: Ip6Address,
658 comptime fmt: []const u8,
659 options: std.fmt.FormatOptions,
660 out_stream: anytype,
661 ) !void {
662 if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
663 _ = options;
634 pub fn format(self: Ip6Address, w: *std.io.Writer) std.io.Writer.Error!void {
664635 const port = mem.bigToNative(u16, self.sa.port);
665636 if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {
666 try std.fmt.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{
637 try w.print("[::ffff:{d}.{d}.{d}.{d}]:{d}", .{
667638 self.sa.addr[12],
668639 self.sa.addr[13],
669640 self.sa.addr[14],
......@@ -711,14 +682,14 @@ pub const Ip6Address = extern struct {
711682 longest_len = 0;
712683 }
713684
714 try out_stream.writeAll("[");
685 try w.writeAll("[");
715686 var i: usize = 0;
716687 var abbrv = false;
717688 while (i < native_endian_parts.len) : (i += 1) {
718689 if (i == longest_start) {
719690 // Emit "::" for the longest zero run
720691 if (!abbrv) {
721 try out_stream.writeAll(if (i == 0) "::" else ":");
692 try w.writeAll(if (i == 0) "::" else ":");
722693 abbrv = true;
723694 }
724695 i += longest_len - 1; // Skip the compressed range
......@@ -727,12 +698,12 @@ pub const Ip6Address = extern struct {
727698 if (abbrv) {
728699 abbrv = false;
729700 }
730 try std.fmt.format(out_stream, "{x}", .{native_endian_parts[i]});
701 try w.print("{x}", .{native_endian_parts[i]});
731702 if (i != native_endian_parts.len - 1) {
732 try out_stream.writeAll(":");
703 try w.writeAll(":");
733704 }
734705 }
735 try std.fmt.format(out_stream, "]:{}", .{port});
706 try w.print("]:{}", .{port});
736707 }
737708
738709 pub fn getOsSockLen(self: Ip6Address) posix.socklen_t {
......@@ -894,7 +865,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get
894865 const name_c = try allocator.dupeZ(u8, name);
895866 defer allocator.free(name_c);
896867
897 const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port});
868 const port_c = try std.fmt.allocPrintSentinel(allocator, "{}", .{port}, 0);
898869 defer allocator.free(port_c);
899870
900871 const ws2_32 = windows.ws2_32;
......@@ -966,7 +937,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get
966937 const name_c = try allocator.dupeZ(u8, name);
967938 defer allocator.free(name_c);
968939
969 const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port});
940 const port_c = try std.fmt.allocPrintSentinel(allocator, "{}", .{port}, 0);
970941 defer allocator.free(port_c);
971942
972943 const hints: posix.addrinfo = .{
......@@ -1356,7 +1327,7 @@ fn linuxLookupNameFromHosts(
13561327 };
13571328 defer file.close();
13581329
1359 var buffered_reader = std.io.bufferedReader(file.reader());
1330 var buffered_reader = std.io.bufferedReader(file.deprecatedReader());
13601331 const reader = buffered_reader.reader();
13611332 var line_buf: [512]u8 = undefined;
13621333 while (reader.readUntilDelimiterOrEof(&line_buf, '\n') catch |err| switch (err) {
......@@ -1557,7 +1528,7 @@ fn getResolvConf(allocator: mem.Allocator, rc: *ResolvConf) !void {
15571528 };
15581529 defer file.close();
15591530
1560 var buf_reader = std.io.bufferedReader(file.reader());
1531 var buf_reader = std.io.bufferedReader(file.deprecatedReader());
15611532 const stream = buf_reader.reader();
15621533 var line_buf: [512]u8 = undefined;
15631534 while (stream.readUntilDelimiterOrEof(&line_buf, '\n') catch |err| switch (err) {
......@@ -1845,8 +1816,8 @@ pub const Stream = struct {
18451816 pub const ReadError = posix.ReadError;
18461817 pub const WriteError = posix.WriteError;
18471818
1848 pub const Reader = io.Reader(Stream, ReadError, read);
1849 pub const Writer = io.Writer(Stream, WriteError, write);
1819 pub const Reader = io.GenericReader(Stream, ReadError, read);
1820 pub const Writer = io.GenericWriter(Stream, WriteError, write);
18501821
18511822 pub fn reader(self: Stream) Reader {
18521823 return .{ .context = self };
lib/std/net/test.zig+16-53
......@@ -5,20 +5,13 @@ const mem = std.mem;
55const testing = std.testing;
66
77test "parse and render IP addresses at comptime" {
8 if (builtin.os.tag == .wasi) return error.SkipZigTest;
98 comptime {
10 var ipAddrBuffer: [16]u8 = undefined;
11 // Parses IPv6 at comptime
129 const ipv6addr = net.Address.parseIp("::1", 0) catch unreachable;
13 var ipv6 = std.fmt.bufPrint(ipAddrBuffer[0..], "{}", .{ipv6addr}) catch unreachable;
14 try std.testing.expect(std.mem.eql(u8, "::1", ipv6[1 .. ipv6.len - 3]));
10 try std.testing.expectFmt("[::1]:0", "{f}", .{ipv6addr});
1511
16 // Parses IPv4 at comptime
1712 const ipv4addr = net.Address.parseIp("127.0.0.1", 0) catch unreachable;
18 var ipv4 = std.fmt.bufPrint(ipAddrBuffer[0..], "{}", .{ipv4addr}) catch unreachable;
19 try std.testing.expect(std.mem.eql(u8, "127.0.0.1", ipv4[0 .. ipv4.len - 2]));
13 try std.testing.expectFmt("127.0.0.1:0", "{f}", .{ipv4addr});
2014
21 // Returns error for invalid IP addresses at comptime
2215 try testing.expectError(error.InvalidIPAddressFormat, net.Address.parseIp("::123.123.123.123", 0));
2316 try testing.expectError(error.InvalidIPAddressFormat, net.Address.parseIp("127.01.0.1", 0));
2417 try testing.expectError(error.InvalidIPAddressFormat, net.Address.resolveIp("::123.123.123.123", 0));
......@@ -27,47 +20,23 @@ test "parse and render IP addresses at comptime" {
2720}
2821
2922test "format IPv6 address with no zero runs" {
30 if (builtin.os.tag == .wasi) return error.SkipZigTest;
31
3223 const addr = try std.net.Address.parseIp6("2001:db8:1:2:3:4:5:6", 0);
33
34 var buffer: [50]u8 = undefined;
35 const result = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
36
37 try std.testing.expectEqualStrings("[2001:db8:1:2:3:4:5:6]:0", result);
24 try std.testing.expectFmt("[2001:db8:1:2:3:4:5:6]:0", "{f}", .{addr});
3825}
3926
4027test "parse IPv6 addresses and check compressed form" {
41 if (builtin.os.tag == .wasi) return error.SkipZigTest;
42
43 const alloc = testing.allocator;
44
45 // 1) Parse an IPv6 address that should compress to [2001:db8::1:0:0:2]:0
46 const addr1 = try std.net.Address.parseIp6("2001:0db8:0000:0000:0001:0000:0000:0002", 0);
47
48 // 2) Parse an IPv6 address that should compress to [2001:db8::1:2]:0
49 const addr2 = try std.net.Address.parseIp6("2001:0db8:0000:0000:0000:0000:0001:0002", 0);
50
51 // 3) Parse an IPv6 address that should compress to [2001:db8:1:0:1::2]:0
52 const addr3 = try std.net.Address.parseIp6("2001:0db8:0001:0000:0001:0000:0000:0002", 0);
53
54 // Print each address in Zig's default "[ipv6]:port" form.
55 const printed1 = try std.fmt.allocPrint(alloc, "{any}", .{addr1});
56 defer testing.allocator.free(printed1);
57 const printed2 = try std.fmt.allocPrint(alloc, "{any}", .{addr2});
58 defer testing.allocator.free(printed2);
59 const printed3 = try std.fmt.allocPrint(alloc, "{any}", .{addr3});
60 defer testing.allocator.free(printed3);
61
62 // Check the exact compressed forms we expect.
63 try std.testing.expectEqualStrings("[2001:db8::1:0:0:2]:0", printed1);
64 try std.testing.expectEqualStrings("[2001:db8::1:2]:0", printed2);
65 try std.testing.expectEqualStrings("[2001:db8:1:0:1::2]:0", printed3);
28 try std.testing.expectFmt("[2001:db8::1:0:0:2]:0", "{f}", .{
29 try std.net.Address.parseIp6("2001:0db8:0000:0000:0001:0000:0000:0002", 0),
30 });
31 try std.testing.expectFmt("[2001:db8::1:2]:0", "{f}", .{
32 try std.net.Address.parseIp6("2001:0db8:0000:0000:0000:0000:0001:0002", 0),
33 });
34 try std.testing.expectFmt("[2001:db8:1:0:1::2]:0", "{f}", .{
35 try std.net.Address.parseIp6("2001:0db8:0001:0000:0001:0000:0000:0002", 0),
36 });
6637}
6738
6839test "parse IPv6 address, check raw bytes" {
69 if (builtin.os.tag == .wasi) return error.SkipZigTest;
70
7140 const expected_raw: [16]u8 = .{
7241 0x20, 0x01, 0x0d, 0xb8, // 2001:db8
7342 0x00, 0x00, 0x00, 0x00, // :0000:0000
......@@ -82,8 +51,6 @@ test "parse IPv6 address, check raw bytes" {
8251}
8352
8453test "parse and render IPv6 addresses" {
85 if (builtin.os.tag == .wasi) return error.SkipZigTest;
86
8754 var buffer: [100]u8 = undefined;
8855 const ips = [_][]const u8{
8956 "FF01:0:0:0:0:0:0:FB",
......@@ -111,12 +78,12 @@ test "parse and render IPv6 addresses" {
11178 };
11279 for (ips, 0..) |ip, i| {
11380 const addr = net.Address.parseIp6(ip, 0) catch unreachable;
114 var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
81 var newIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr}) catch unreachable;
11582 try std.testing.expect(std.mem.eql(u8, printed[i], newIp[1 .. newIp.len - 3]));
11683
11784 if (builtin.os.tag == .linux) {
11885 const addr_via_resolve = net.Address.resolveIp6(ip, 0) catch unreachable;
119 var newResolvedIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr_via_resolve}) catch unreachable;
86 var newResolvedIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr_via_resolve}) catch unreachable;
12087 try std.testing.expect(std.mem.eql(u8, printed[i], newResolvedIp[1 .. newResolvedIp.len - 3]));
12188 }
12289 }
......@@ -148,8 +115,6 @@ test "invalid but parseable IPv6 scope ids" {
148115}
149116
150117test "parse and render IPv4 addresses" {
151 if (builtin.os.tag == .wasi) return error.SkipZigTest;
152
153118 var buffer: [18]u8 = undefined;
154119 for ([_][]const u8{
155120 "0.0.0.0",
......@@ -159,7 +124,7 @@ test "parse and render IPv4 addresses" {
159124 "127.0.0.1",
160125 }) |ip| {
161126 const addr = net.Address.parseIp4(ip, 0) catch unreachable;
162 var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
127 var newIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr}) catch unreachable;
163128 try std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
164129 }
165130
......@@ -175,10 +140,8 @@ test "parse and render UNIX addresses" {
175140 if (builtin.os.tag == .wasi) return error.SkipZigTest;
176141 if (!net.has_unix_sockets) return error.SkipZigTest;
177142
178 var buffer: [14]u8 = undefined;
179143 const addr = net.Address.initUnix("/tmp/testpath") catch unreachable;
180 const fmt_addr = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
181 try std.testing.expectEqualSlices(u8, "/tmp/testpath", fmt_addr);
144 try std.testing.expectFmt("/tmp/testpath", "{f}", .{addr});
182145
183146 const too_long = [_]u8{'a'} ** 200;
184147 try testing.expectError(error.NameTooLong, net.Address.initUnix(too_long[0..]));
lib/std/os.zig+1
......@@ -31,6 +31,7 @@ pub const uefi = @import("os/uefi.zig");
3131pub const wasi = @import("os/wasi.zig");
3232pub const emscripten = @import("os/emscripten.zig");
3333pub const windows = @import("os/windows.zig");
34pub const freebsd = @import("os/freebsd.zig");
3435
3536test {
3637 _ = linux;
lib/std/os/freebsd.zig created+49
......@@ -0,0 +1,49 @@
1const std = @import("../std.zig");
2const fd_t = std.c.fd_t;
3const off_t = std.c.off_t;
4const unexpectedErrno = std.posix.unexpectedErrno;
5const errno = std.posix.errno;
6
7pub const CopyFileRangeError = std.posix.UnexpectedError || error{
8 /// If infd is not open for reading or outfd is not open for writing, or
9 /// opened for writing with O_APPEND, or if infd and outfd refer to the
10 /// same file.
11 BadFileFlags,
12 /// If the copy exceeds the process's file size limit or the maximum
13 /// file size for the file system outfd re- sides on.
14 FileTooBig,
15 /// A signal interrupted the system call before it could be completed.
16 /// This may happen for files on some NFS mounts. When this happens,
17 /// the values pointed to by inoffp and outoffp are reset to the
18 /// initial values for the system call.
19 Interrupted,
20 /// One of:
21 /// * infd and outfd refer to the same file and the byte ranges overlap.
22 /// * The flags argument is not zero.
23 /// * Either infd or outfd refers to a file object that is not a regular file.
24 InvalidArguments,
25 /// An I/O error occurred while reading/writing the files.
26 InputOutput,
27 /// Corrupted data was detected while reading from a file system.
28 CorruptedData,
29 /// Either infd or outfd refers to a directory.
30 IsDir,
31 /// File system that stores outfd is full.
32 NoSpaceLeft,
33};
34
35pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, len: usize, flags: u32) CopyFileRangeError!usize {
36 const rc = std.c.copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
37 switch (errno(rc)) {
38 .SUCCESS => return @intCast(rc),
39 .BADF => return error.BadFileFlags,
40 .FBIG => return error.FileTooBig,
41 .INTR => return error.Interrupted,
42 .INVAL => return error.InvalidArguments,
43 .IO => return error.InputOutput,
44 .INTEGRITY => return error.CorruptedData,
45 .ISDIR => return error.IsDir,
46 .NOSPC => return error.NoSpaceLeft,
47 else => |err| return unexpectedErrno(err),
48 }
49}
lib/std/os/linux.zig+148-2
......@@ -103,8 +103,6 @@ pub const dev_t = arch_bits.dev_t;
103103pub const ino_t = arch_bits.ino_t;
104104pub const mcontext_t = arch_bits.mcontext_t;
105105pub const mode_t = arch_bits.mode_t;
106pub const msghdr = arch_bits.msghdr;
107pub const msghdr_const = arch_bits.msghdr_const;
108106pub const nlink_t = arch_bits.nlink_t;
109107pub const off_t = arch_bits.off_t;
110108pub const time_t = arch_bits.time_t;
......@@ -9403,3 +9401,151 @@ pub const SHADOW_STACK = struct {
94039401 /// Set up a restore token in the shadow stack.
94049402 pub const SET_TOKEN: u64 = 1 << 0;
94059403};
9404
9405pub const msghdr = extern struct {
9406 name: ?*sockaddr,
9407 namelen: socklen_t,
9408 iov: [*]iovec,
9409 iovlen: usize,
9410 control: ?*anyopaque,
9411 controllen: usize,
9412 flags: u32,
9413};
9414
9415pub const msghdr_const = extern struct {
9416 name: ?*const sockaddr,
9417 namelen: socklen_t,
9418 iov: [*]const iovec_const,
9419 iovlen: usize,
9420 control: ?*const anyopaque,
9421 controllen: usize,
9422 flags: u32,
9423};
9424
9425/// The syscalls, but with Zig error sets, going through libc if linking libc,
9426/// and with some footguns eliminated.
9427pub const wrapped = struct {
9428 pub const lfs64_abi = builtin.link_libc and (builtin.abi.isGnu() or builtin.abi.isAndroid());
9429 const system = if (builtin.link_libc) std.c else std.os.linux;
9430
9431 pub const SendfileError = std.posix.UnexpectedError || error{
9432 /// `out_fd` is an unconnected socket, or out_fd closed its read end.
9433 BrokenPipe,
9434 /// Descriptor is not valid or locked, or an mmap(2)-like operation is not available for in_fd.
9435 UnsupportedOperation,
9436 /// Nonblocking I/O has been selected but the write would block.
9437 WouldBlock,
9438 /// Unspecified error while reading from in_fd.
9439 InputOutput,
9440 /// Insufficient kernel memory to read from in_fd.
9441 SystemResources,
9442 /// `offset` is not `null` but the input file is not seekable.
9443 Unseekable,
9444 };
9445
9446 pub fn sendfile(
9447 out_fd: fd_t,
9448 in_fd: fd_t,
9449 in_offset: ?*off_t,
9450 in_len: usize,
9451 ) SendfileError!usize {
9452 const adjusted_len = @min(in_len, 0x7ffff000); // Prevents EOVERFLOW.
9453 const sendfileSymbol = if (lfs64_abi) system.sendfile64 else system.sendfile;
9454 const rc = sendfileSymbol(out_fd, in_fd, in_offset, adjusted_len);
9455 switch (errno(rc)) {
9456 .SUCCESS => return @intCast(rc),
9457 .BADF => return invalidApiUsage(), // Always a race condition.
9458 .FAULT => return invalidApiUsage(), // Segmentation fault.
9459 .OVERFLOW => return unexpectedErrno(.OVERFLOW), // We avoid passing too large of a `count`.
9460 .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket
9461 .INVAL => return error.UnsupportedOperation,
9462 .AGAIN => return error.WouldBlock,
9463 .IO => return error.InputOutput,
9464 .PIPE => return error.BrokenPipe,
9465 .NOMEM => return error.SystemResources,
9466 .NXIO => return error.Unseekable,
9467 .SPIPE => return error.Unseekable,
9468 else => |err| return unexpectedErrno(err),
9469 }
9470 }
9471
9472 pub const CopyFileRangeError = std.posix.UnexpectedError || error{
9473 /// One of:
9474 /// * One or more file descriptors are not valid.
9475 /// * fd_in is not open for reading; or fd_out is not open for writing.
9476 /// * The O_APPEND flag is set for the open file description referred
9477 /// to by the file descriptor fd_out.
9478 BadFileFlags,
9479 /// One of:
9480 /// * An attempt was made to write at a position past the maximum file
9481 /// offset the kernel supports.
9482 /// * An attempt was made to write a range that exceeds the allowed
9483 /// maximum file size. The maximum file size differs between
9484 /// filesystem implementations and can be different from the maximum
9485 /// allowed file offset.
9486 /// * An attempt was made to write beyond the process's file size
9487 /// resource limit. This may also result in the process receiving a
9488 /// SIGXFSZ signal.
9489 FileTooBig,
9490 /// One of:
9491 /// * either fd_in or fd_out is not a regular file
9492 /// * flags argument is not zero
9493 /// * fd_in and fd_out refer to the same file and the source and target ranges overlap.
9494 InvalidArguments,
9495 /// A low-level I/O error occurred while copying.
9496 InputOutput,
9497 /// Either fd_in or fd_out refers to a directory.
9498 IsDir,
9499 OutOfMemory,
9500 /// There is not enough space on the target filesystem to complete the copy.
9501 NoSpaceLeft,
9502 /// (since Linux 5.19) the filesystem does not support this operation.
9503 OperationNotSupported,
9504 /// The requested source or destination range is too large to represent
9505 /// in the specified data types.
9506 Overflow,
9507 /// fd_out refers to an immutable file.
9508 PermissionDenied,
9509 /// Either fd_in or fd_out refers to an active swap file.
9510 SwapFile,
9511 /// The files referred to by fd_in and fd_out are not on the same
9512 /// filesystem, and the source and target filesystems are not of the
9513 /// same type, or do not support cross-filesystem copy.
9514 NotSameFileSystem,
9515 };
9516
9517 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 {
9518 const rc = system.copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
9519 switch (errno(rc)) {
9520 .SUCCESS => return @intCast(rc),
9521 .BADF => return error.BadFileFlags,
9522 .FBIG => return error.FileTooBig,
9523 .INVAL => return error.InvalidArguments,
9524 .IO => return error.InputOutput,
9525 .ISDIR => return error.IsDir,
9526 .NOMEM => return error.OutOfMemory,
9527 .NOSPC => return error.NoSpaceLeft,
9528 .OPNOTSUPP => return error.OperationNotSupported,
9529 .OVERFLOW => return error.Overflow,
9530 .PERM => return error.PermissionDenied,
9531 .TXTBSY => return error.SwapFile,
9532 .XDEV => return error.NotSameFileSystem,
9533 else => |err| return unexpectedErrno(err),
9534 }
9535 }
9536
9537 const unexpectedErrno = std.posix.unexpectedErrno;
9538
9539 fn invalidApiUsage() error{Unexpected} {
9540 if (builtin.mode == .Debug) @panic("invalid API usage");
9541 return error.Unexpected;
9542 }
9543
9544 fn errno(rc: anytype) E {
9545 if (builtin.link_libc) {
9546 return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS;
9547 } else {
9548 return errnoFromSyscall(rc);
9549 }
9550 }
9551};
lib/std/os/linux/aarch64.zig-24
......@@ -199,30 +199,6 @@ pub const Flock = extern struct {
199199 __unused: [4]u8,
200200};
201201
202pub const msghdr = extern struct {
203 name: ?*sockaddr,
204 namelen: socklen_t,
205 iov: [*]iovec,
206 iovlen: i32,
207 __pad1: i32 = 0,
208 control: ?*anyopaque,
209 controllen: socklen_t,
210 __pad2: socklen_t = 0,
211 flags: i32,
212};
213
214pub const msghdr_const = extern struct {
215 name: ?*const sockaddr,
216 namelen: socklen_t,
217 iov: [*]const iovec_const,
218 iovlen: i32,
219 __pad1: i32 = 0,
220 control: ?*const anyopaque,
221 controllen: socklen_t,
222 __pad2: socklen_t = 0,
223 flags: i32,
224};
225
226202pub const blksize_t = i32;
227203pub const nlink_t = u32;
228204pub const time_t = isize;
lib/std/os/linux/arm.zig-20
......@@ -237,26 +237,6 @@ pub const Flock = extern struct {
237237 __unused: [4]u8,
238238};
239239
240pub const msghdr = extern struct {
241 name: ?*sockaddr,
242 namelen: socklen_t,
243 iov: [*]iovec,
244 iovlen: i32,
245 control: ?*anyopaque,
246 controllen: socklen_t,
247 flags: i32,
248};
249
250pub const msghdr_const = extern struct {
251 name: ?*const sockaddr,
252 namelen: socklen_t,
253 iov: [*]const iovec_const,
254 iovlen: i32,
255 control: ?*const anyopaque,
256 controllen: socklen_t,
257 flags: i32,
258};
259
260240pub const blksize_t = i32;
261241pub const nlink_t = u32;
262242pub const time_t = isize;
lib/std/os/linux/mips.zig-20
......@@ -309,26 +309,6 @@ pub const Flock = extern struct {
309309 __unused: [4]u8,
310310};
311311
312pub const msghdr = extern struct {
313 name: ?*sockaddr,
314 namelen: socklen_t,
315 iov: [*]iovec,
316 iovlen: i32,
317 control: ?*anyopaque,
318 controllen: socklen_t,
319 flags: i32,
320};
321
322pub const msghdr_const = extern struct {
323 name: ?*const sockaddr,
324 namelen: socklen_t,
325 iov: [*]const iovec_const,
326 iovlen: i32,
327 control: ?*const anyopaque,
328 controllen: socklen_t,
329 flags: i32,
330};
331
332312pub const blksize_t = u32;
333313pub const nlink_t = u32;
334314pub const time_t = i32;
lib/std/os/linux/mips64.zig-20
......@@ -288,26 +288,6 @@ pub const Flock = extern struct {
288288 __unused: [4]u8,
289289};
290290
291pub const msghdr = extern struct {
292 name: ?*sockaddr,
293 namelen: socklen_t,
294 iov: [*]iovec,
295 iovlen: i32,
296 control: ?*anyopaque,
297 controllen: socklen_t,
298 flags: i32,
299};
300
301pub const msghdr_const = extern struct {
302 name: ?*const sockaddr,
303 namelen: socklen_t,
304 iov: [*]const iovec_const,
305 iovlen: i32,
306 control: ?*const anyopaque,
307 controllen: socklen_t,
308 flags: i32,
309};
310
311291pub const blksize_t = u32;
312292pub const nlink_t = u32;
313293pub const time_t = i32;
lib/std/os/linux/powerpc.zig-20
......@@ -247,26 +247,6 @@ pub const Flock = extern struct {
247247 pid: pid_t,
248248};
249249
250pub const msghdr = extern struct {
251 name: ?*sockaddr,
252 namelen: socklen_t,
253 iov: [*]iovec,
254 iovlen: usize,
255 control: ?*anyopaque,
256 controllen: socklen_t,
257 flags: i32,
258};
259
260pub const msghdr_const = extern struct {
261 name: ?*const sockaddr,
262 namelen: socklen_t,
263 iov: [*]const iovec_const,
264 iovlen: usize,
265 control: ?*const anyopaque,
266 controllen: socklen_t,
267 flags: i32,
268};
269
270250pub const blksize_t = i32;
271251pub const nlink_t = u32;
272252pub const time_t = isize;
lib/std/os/linux/powerpc64.zig-20
......@@ -233,26 +233,6 @@ pub const Flock = extern struct {
233233 __unused: [4]u8,
234234};
235235
236pub const msghdr = extern struct {
237 name: ?*sockaddr,
238 namelen: socklen_t,
239 iov: [*]iovec,
240 iovlen: usize,
241 control: ?*anyopaque,
242 controllen: usize,
243 flags: i32,
244};
245
246pub const msghdr_const = extern struct {
247 name: ?*const sockaddr,
248 namelen: socklen_t,
249 iov: [*]const iovec_const,
250 iovlen: usize,
251 control: ?*const anyopaque,
252 controllen: usize,
253 flags: i32,
254};
255
256236pub const blksize_t = i64;
257237pub const nlink_t = u64;
258238pub const time_t = i64;
lib/std/os/linux/riscv32.zig-24
......@@ -200,30 +200,6 @@ pub const Flock = extern struct {
200200 __unused: [4]u8,
201201};
202202
203pub const msghdr = extern struct {
204 name: ?*sockaddr,
205 namelen: socklen_t,
206 iov: [*]iovec,
207 iovlen: i32,
208 __pad1: i32 = 0,
209 control: ?*anyopaque,
210 controllen: socklen_t,
211 __pad2: socklen_t = 0,
212 flags: i32,
213};
214
215pub const msghdr_const = extern struct {
216 name: ?*const sockaddr,
217 namelen: socklen_t,
218 iov: [*]const iovec_const,
219 iovlen: i32,
220 __pad1: i32 = 0,
221 control: ?*const anyopaque,
222 controllen: socklen_t,
223 __pad2: socklen_t = 0,
224 flags: i32,
225};
226
227203// The `stat` definition used by the Linux kernel.
228204pub const Stat = extern struct {
229205 dev: dev_t,
lib/std/os/linux/riscv64.zig-24
......@@ -200,30 +200,6 @@ pub const Flock = extern struct {
200200 __unused: [4]u8,
201201};
202202
203pub const msghdr = extern struct {
204 name: ?*sockaddr,
205 namelen: socklen_t,
206 iov: [*]iovec,
207 iovlen: i32,
208 __pad1: i32 = 0,
209 control: ?*anyopaque,
210 controllen: socklen_t,
211 __pad2: socklen_t = 0,
212 flags: i32,
213};
214
215pub const msghdr_const = extern struct {
216 name: ?*const sockaddr,
217 namelen: socklen_t,
218 iov: [*]const iovec_const,
219 iovlen: i32,
220 __pad1: i32 = 0,
221 control: ?*const anyopaque,
222 controllen: socklen_t,
223 __pad2: socklen_t = 0,
224 flags: i32,
225};
226
227203// The `stat` definition used by the Linux kernel.
228204pub const Stat = extern struct {
229205 dev: dev_t,
lib/std/os/linux/sparc64.zig-20
......@@ -282,26 +282,6 @@ pub const Flock = extern struct {
282282 pid: pid_t,
283283};
284284
285pub const msghdr = extern struct {
286 name: ?*sockaddr,
287 namelen: socklen_t,
288 iov: [*]iovec,
289 iovlen: u64,
290 control: ?*anyopaque,
291 controllen: u64,
292 flags: i32,
293};
294
295pub const msghdr_const = extern struct {
296 name: ?*const sockaddr,
297 namelen: socklen_t,
298 iov: [*]const iovec_const,
299 iovlen: u64,
300 control: ?*const anyopaque,
301 controllen: u64,
302 flags: i32,
303};
304
305285pub const off_t = i64;
306286pub const ino_t = u64;
307287pub const time_t = isize;
lib/std/os/linux/x86.zig-20
......@@ -245,26 +245,6 @@ pub const Flock = extern struct {
245245 pid: pid_t,
246246};
247247
248pub const msghdr = extern struct {
249 name: ?*sockaddr,
250 namelen: socklen_t,
251 iov: [*]iovec,
252 iovlen: i32,
253 control: ?*anyopaque,
254 controllen: socklen_t,
255 flags: i32,
256};
257
258pub const msghdr_const = extern struct {
259 name: ?*const sockaddr,
260 namelen: socklen_t,
261 iov: [*]const iovec_const,
262 iovlen: i32,
263 control: ?*const anyopaque,
264 controllen: socklen_t,
265 flags: i32,
266};
267
268248pub const blksize_t = i32;
269249pub const nlink_t = u32;
270250pub const time_t = isize;
lib/std/os/linux/x86_64.zig-24
......@@ -233,30 +233,6 @@ pub const Flock = extern struct {
233233 pid: pid_t,
234234};
235235
236pub const msghdr = extern struct {
237 name: ?*sockaddr,
238 namelen: socklen_t,
239 iov: [*]iovec,
240 iovlen: i32,
241 __pad1: i32 = 0,
242 control: ?*anyopaque,
243 controllen: socklen_t,
244 __pad2: socklen_t = 0,
245 flags: i32,
246};
247
248pub const msghdr_const = extern struct {
249 name: ?*const sockaddr,
250 namelen: socklen_t,
251 iov: [*]const iovec_const,
252 iovlen: i32,
253 __pad1: i32 = 0,
254 control: ?*const anyopaque,
255 controllen: socklen_t,
256 __pad2: socklen_t = 0,
257 flags: i32,
258};
259
260236pub const off_t = i64;
261237pub const ino_t = u64;
262238pub const dev_t = u64;
lib/std/os/uefi.zig+14-25
......@@ -1,4 +1,5 @@
11const std = @import("../std.zig");
2const assert = std.debug.assert;
23
34/// A protocol is an interface identified by a GUID.
45pub const protocol = @import("uefi/protocol.zig");
......@@ -59,31 +60,19 @@ pub const Guid = extern struct {
5960 node: [6]u8,
6061
6162 /// Format GUID into hexadecimal lowercase xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
62 pub fn format(
63 self: @This(),
64 comptime f: []const u8,
65 options: std.fmt.FormatOptions,
66 writer: anytype,
67 ) !void {
68 _ = options;
69 if (f.len == 0) {
70 const fmt = std.fmt.fmtSliceHexLower;
71
72 const time_low = @byteSwap(self.time_low);
73 const time_mid = @byteSwap(self.time_mid);
74 const time_high_and_version = @byteSwap(self.time_high_and_version);
75
76 return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{
77 fmt(std.mem.asBytes(&time_low)),
78 fmt(std.mem.asBytes(&time_mid)),
79 fmt(std.mem.asBytes(&time_high_and_version)),
80 fmt(std.mem.asBytes(&self.clock_seq_high_and_reserved)),
81 fmt(std.mem.asBytes(&self.clock_seq_low)),
82 fmt(std.mem.asBytes(&self.node)),
83 });
84 } else {
85 std.fmt.invalidFmtError(f, self);
86 }
63 pub fn format(self: @This(), writer: *std.io.Writer) std.io.Writer.Error!void {
64 const time_low = @byteSwap(self.time_low);
65 const time_mid = @byteSwap(self.time_mid);
66 const time_high_and_version = @byteSwap(self.time_high_and_version);
67
68 return writer.print("{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
69 std.mem.asBytes(&time_low),
70 std.mem.asBytes(&time_mid),
71 std.mem.asBytes(&time_high_and_version),
72 std.mem.asBytes(&self.clock_seq_high_and_reserved),
73 std.mem.asBytes(&self.clock_seq_low),
74 std.mem.asBytes(&self.node),
75 });
8776 }
8877
8978 pub fn eql(a: std.os.uefi.Guid, b: std.os.uefi.Guid) bool {
lib/std/os/uefi/protocol/file.zig-24
......@@ -79,30 +79,6 @@ pub const File = extern struct {
7979 VolumeFull,
8080 };
8181
82 pub const SeekableStream = io.SeekableStream(
83 *File,
84 SeekError,
85 SeekError,
86 setPosition,
87 seekBy,
88 getPosition,
89 getEndPos,
90 );
91 pub const Reader = io.Reader(*File, ReadError, read);
92 pub const Writer = io.Writer(*File, WriteError, write);
93
94 pub fn seekableStream(self: *File) SeekableStream {
95 return .{ .context = self };
96 }
97
98 pub fn reader(self: *File) Reader {
99 return .{ .context = self };
100 }
101
102 pub fn writer(self: *File) Writer {
103 return .{ .context = self };
104 }
105
10682 pub fn open(
10783 self: *const File,
10884 file_name: [*:0]const u16,
lib/std/os/windows.zig+2-37
......@@ -1690,40 +1690,6 @@ pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so
16901690 return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen)));
16911691}
16921692
1693pub fn sendmsg(
1694 s: ws2_32.SOCKET,
1695 msg: *ws2_32.WSAMSG_const,
1696 flags: u32,
1697) i32 {
1698 var bytes_send: DWORD = undefined;
1699 if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) {
1700 return ws2_32.SOCKET_ERROR;
1701 } else {
1702 return @as(i32, @as(u31, @intCast(bytes_send)));
1703 }
1704}
1705
1706pub 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 {
1707 var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = @constCast(buf) };
1708 var bytes_send: DWORD = undefined;
1709 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) {
1710 return ws2_32.SOCKET_ERROR;
1711 } else {
1712 return @as(i32, @as(u31, @intCast(bytes_send)));
1713 }
1714}
1715
1716pub fn recvfrom(s: ws2_32.SOCKET, buf: [*]u8, len: usize, flags: u32, from: ?*ws2_32.sockaddr, from_len: ?*ws2_32.socklen_t) i32 {
1717 var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = buf };
1718 var bytes_received: DWORD = undefined;
1719 var flags_inout = flags;
1720 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) {
1721 return ws2_32.SOCKET_ERROR;
1722 } else {
1723 return @as(i32, @as(u31, @intCast(bytes_received)));
1724 }
1725}
1726
17271693pub fn poll(fds: [*]ws2_32.pollfd, n: c_ulong, timeout: i32) i32 {
17281694 return ws2_32.WSAPoll(fds, n, timeout);
17291695}
......@@ -2846,9 +2812,8 @@ pub fn unexpectedError(err: Win32Error) UnexpectedError {
28462812 buf_wstr.len,
28472813 null,
28482814 );
2849 std.debug.print("error.Unexpected: GetLastError({}): {}\n", .{
2850 @intFromEnum(err),
2851 std.unicode.fmtUtf16Le(buf_wstr[0..len]),
2815 std.debug.print("error.Unexpected: GetLastError({d}): {f}\n", .{
2816 err, std.unicode.fmtUtf16Le(buf_wstr[0..len]),
28522817 });
28532818 std.debug.dumpCurrentStackTrace(@returnAddress());
28542819 }
lib/std/os/windows/test.zig+2-2
......@@ -30,7 +30,7 @@ fn testToPrefixedFileNoOracle(comptime path: []const u8, comptime expected_path:
3030 const expected_path_utf16 = std.unicode.utf8ToUtf16LeStringLiteral(expected_path);
3131 const actual_path = try windows.wToPrefixedFileW(null, path_utf16);
3232 std.testing.expectEqualSlices(u16, expected_path_utf16, actual_path.span()) catch |e| {
33 std.debug.print("got '{s}', expected '{s}'\n", .{ std.unicode.fmtUtf16Le(actual_path.span()), std.unicode.fmtUtf16Le(expected_path_utf16) });
33 std.debug.print("got '{f}', expected '{f}'\n", .{ std.unicode.fmtUtf16Le(actual_path.span()), std.unicode.fmtUtf16Le(expected_path_utf16) });
3434 return e;
3535 };
3636}
......@@ -48,7 +48,7 @@ fn testToPrefixedFileOnlyOracle(comptime path: []const u8) !void {
4848 const zig_result = try windows.wToPrefixedFileW(null, path_utf16);
4949 const win32_api_result = try RtlDosPathNameToNtPathName_U(path_utf16);
5050 std.testing.expectEqualSlices(u16, win32_api_result.span(), zig_result.span()) catch |e| {
51 std.debug.print("got '{s}', expected '{s}'\n", .{ std.unicode.fmtUtf16Le(zig_result.span()), std.unicode.fmtUtf16Le(win32_api_result.span()) });
51 std.debug.print("got '{f}', expected '{f}'\n", .{ std.unicode.fmtUtf16Le(zig_result.span()), std.unicode.fmtUtf16Le(win32_api_result.span()) });
5252 return e;
5353 };
5454}
lib/std/os/windows/ws2_32.zig+1-9
......@@ -1829,7 +1829,7 @@ pub extern "ws2_32" fn sendto(
18291829 buf: [*]const u8,
18301830 len: i32,
18311831 flags: i32,
1832 to: *const sockaddr,
1832 to: ?*const sockaddr,
18331833 tolen: i32,
18341834) callconv(.winapi) i32;
18351835
......@@ -2116,14 +2116,6 @@ pub extern "ws2_32" fn WSASendMsg(
21162116 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
21172117) callconv(.winapi) i32;
21182118
2119pub extern "ws2_32" fn WSARecvMsg(
2120 s: SOCKET,
2121 lpMsg: *WSAMSG,
2122 lpdwNumberOfBytesRecv: ?*u32,
2123 lpOverlapped: ?*OVERLAPPED,
2124 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2125) callconv(.winapi) i32;
2126
21272119pub extern "ws2_32" fn WSASendDisconnect(
21282120 s: SOCKET,
21292121 lpOutboundDisconnectData: ?*WSABUF,
lib/std/posix.zig+1-1
......@@ -651,7 +651,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
651651 }
652652
653653 const file: fs.File = .{ .handle = fd };
654 const stream = file.reader();
654 const stream = file.deprecatedReader();
655655 stream.readNoEof(buf) catch return error.Unexpected;
656656}
657657
lib/std/posix/test.zig+1-1
......@@ -667,7 +667,7 @@ test "mmap" {
667667 const file = try tmp.dir.createFile(test_out_file, .{});
668668 defer file.close();
669669
670 const stream = file.writer();
670 const stream = file.deprecatedWriter();
671671
672672 var i: u32 = 0;
673673 while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
lib/std/process.zig+7-7
......@@ -1553,7 +1553,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
15531553 const file = try std.fs.openFileAbsolute("/etc/passwd", .{});
15541554 defer file.close();
15551555
1556 const reader = file.reader();
1556 const reader = file.deprecatedReader();
15571557
15581558 const State = enum {
15591559 Start,
......@@ -1895,7 +1895,7 @@ pub fn createEnvironFromMap(
18951895 var i: usize = 0;
18961896
18971897 if (zig_progress_action == .add) {
1898 envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?});
1898 envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}, 0);
18991899 i += 1;
19001900 }
19011901
......@@ -1906,16 +1906,16 @@ pub fn createEnvironFromMap(
19061906 .add => unreachable,
19071907 .delete => continue,
19081908 .edit => {
1909 envp_buf[i] = try std.fmt.allocPrintZ(arena, "{s}={d}", .{
1909 envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "{s}={d}", .{
19101910 pair.key_ptr.*, options.zig_progress_fd.?,
1911 });
1911 }, 0);
19121912 i += 1;
19131913 continue;
19141914 },
19151915 .nothing => {},
19161916 };
19171917
1918 envp_buf[i] = try std.fmt.allocPrintZ(arena, "{s}={s}", .{ pair.key_ptr.*, pair.value_ptr.* });
1918 envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "{s}={s}", .{ pair.key_ptr.*, pair.value_ptr.* }, 0);
19191919 i += 1;
19201920 }
19211921 }
......@@ -1965,7 +1965,7 @@ pub fn createEnvironFromExisting(
19651965 var existing_index: usize = 0;
19661966
19671967 if (zig_progress_action == .add) {
1968 envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?});
1968 envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}, 0);
19691969 i += 1;
19701970 }
19711971
......@@ -1974,7 +1974,7 @@ pub fn createEnvironFromExisting(
19741974 .add => unreachable,
19751975 .delete => continue,
19761976 .edit => {
1977 envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?});
1977 envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}, 0);
19781978 i += 1;
19791979 continue;
19801980 },
lib/std/process/Child.zig+2-2
......@@ -1004,12 +1004,12 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
10041004
10051005fn writeIntFd(fd: i32, value: ErrInt) !void {
10061006 const file: File = .{ .handle = fd };
1007 file.writer().writeInt(u64, @intCast(value), .little) catch return error.SystemResources;
1007 file.deprecatedWriter().writeInt(u64, @intCast(value), .little) catch return error.SystemResources;
10081008}
10091009
10101010fn readIntFd(fd: i32) !ErrInt {
10111011 const file: File = .{ .handle = fd };
1012 return @intCast(file.reader().readInt(u64, .little) catch return error.SystemResources);
1012 return @intCast(file.deprecatedReader().readInt(u64, .little) catch return error.SystemResources);
10131013}
10141014
10151015const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
lib/std/tar.zig+1-1
......@@ -348,7 +348,7 @@ pub fn Iterator(comptime ReaderType: type) type {
348348 unread_bytes: *u64,
349349 parent_reader: ReaderType,
350350
351 pub const Reader = std.io.Reader(File, ReaderType.Error, File.read);
351 pub const Reader = std.io.GenericReader(File, ReaderType.Error, File.read);
352352
353353 pub fn reader(self: File) Reader {
354354 return .{ .context = self };
lib/std/testing.zig+85-31
......@@ -105,7 +105,7 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void {
105105 .error_set,
106106 => {
107107 if (actual != expected) {
108 print("expected {}, found {}\n", .{ expected, actual });
108 print("expected {any}, found {any}\n", .{ expected, actual });
109109 return error.TestExpectedEqual;
110110 }
111111 },
......@@ -267,9 +267,13 @@ test "expectEqual null" {
267267
268268/// This function is intended to be used only in tests. When the formatted result of the template
269269/// and its arguments does not equal the expected text, it prints diagnostics to stderr to show how
270/// they are not equal, then returns an error. It depends on `expectEqualStrings()` for printing
270/// they are not equal, then returns an error. It depends on `expectEqualStrings` for printing
271271/// diagnostics.
272272pub fn expectFmt(expected: []const u8, comptime template: []const u8, args: anytype) !void {
273 if (@inComptime()) {
274 var buffer: [std.fmt.count(template, args)]u8 = undefined;
275 return expectEqualStrings(expected, try std.fmt.bufPrint(&buffer, template, args));
276 }
273277 const actual = try std.fmt.allocPrint(allocator, template, args);
274278 defer allocator.free(actual);
275279 return expectEqualStrings(expected, actual);
......@@ -356,9 +360,6 @@ test expectApproxEqRel {
356360/// The colorized output is optional and controlled by the return of `std.io.tty.detectConfig()`.
357361/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
358362pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {
359 if (expected.ptr == actual.ptr and expected.len == actual.len) {
360 return;
361 }
362363 const diff_index: usize = diff_index: {
363364 const shortest = @min(expected.len, actual.len);
364365 var index: usize = 0;
......@@ -367,12 +368,21 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
367368 }
368369 break :diff_index if (expected.len == actual.len) return else shortest;
369370 };
371 if (!backend_can_print) return error.TestExpectedEqual;
372 const stderr_w = std.debug.lockStderrWriter(&.{});
373 defer std.debug.unlockStderrWriter();
374 failEqualSlices(T, expected, actual, diff_index, stderr_w) catch {};
375 return error.TestExpectedEqual;
376}
370377
371 if (!backend_can_print) {
372 return error.TestExpectedEqual;
373 }
374
375 print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
378fn failEqualSlices(
379 comptime T: type,
380 expected: []const T,
381 actual: []const T,
382 diff_index: usize,
383 w: *std.io.Writer,
384) !void {
385 try w.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
376386
377387 // TODO: Should this be configurable by the caller?
378388 const max_lines: usize = 16;
......@@ -390,8 +400,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
390400 const actual_window = actual[window_start..@min(actual.len, window_start + max_window_size)];
391401 const actual_truncated = window_start + actual_window.len < actual.len;
392402
393 const stderr = std.io.getStdErr();
394 const ttyconf = std.io.tty.detectConfig(stderr);
403 const ttyconf = std.io.tty.detectConfig(.stderr());
395404 var differ = if (T == u8) BytesDiffer{
396405 .expected = expected_window,
397406 .actual = actual_window,
......@@ -407,47 +416,47 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
407416 // that is usually useful.
408417 const index_fmt = if (T == u8) "0x{X}" else "{}";
409418
410 print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len });
419 try w.print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len });
411420 if (window_start > 0) {
412421 if (T == u8) {
413 print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
422 try w.print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
414423 } else {
415 print("... truncated ...\n", .{});
424 try w.print("... truncated ...\n", .{});
416425 }
417426 }
418 differ.write(stderr.writer()) catch {};
427 differ.write(w) catch {};
419428 if (expected_truncated) {
420429 const end_offset = window_start + expected_window.len;
421430 const num_missing_items = expected.len - (window_start + expected_window.len);
422431 if (T == u8) {
423 print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
432 try w.print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
424433 } else {
425 print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
434 try w.print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
426435 }
427436 }
428437
429438 // now reverse expected/actual and print again
430439 differ.expected = actual_window;
431440 differ.actual = expected_window;
432 print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len });
441 try w.print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len });
433442 if (window_start > 0) {
434443 if (T == u8) {
435 print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
444 try w.print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
436445 } else {
437 print("... truncated ...\n", .{});
446 try w.print("... truncated ...\n", .{});
438447 }
439448 }
440 differ.write(stderr.writer()) catch {};
449 differ.write(w) catch {};
441450 if (actual_truncated) {
442451 const end_offset = window_start + actual_window.len;
443452 const num_missing_items = actual.len - (window_start + actual_window.len);
444453 if (T == u8) {
445 print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
454 try w.print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
446455 } else {
447 print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
456 try w.print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
448457 }
449458 }
450 print("\n================================================\n\n", .{});
459 try w.print("\n================================================\n\n", .{});
451460
452461 return error.TestExpectedEqual;
453462}
......@@ -461,7 +470,7 @@ fn SliceDiffer(comptime T: type) type {
461470
462471 const Self = @This();
463472
464 pub fn write(self: Self, writer: anytype) !void {
473 pub fn write(self: Self, writer: *std.io.Writer) !void {
465474 for (self.expected, 0..) |value, i| {
466475 const full_index = self.start_index + i;
467476 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
......@@ -482,7 +491,7 @@ const BytesDiffer = struct {
482491 actual: []const u8,
483492 ttyconf: std.io.tty.Config,
484493
485 pub fn write(self: BytesDiffer, writer: anytype) !void {
494 pub fn write(self: BytesDiffer, writer: *std.io.Writer) !void {
486495 var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
487496 var row: usize = 0;
488497 while (expected_iterator.next()) |chunk| {
......@@ -499,7 +508,7 @@ const BytesDiffer = struct {
499508 if (chunk.len < 16) {
500509 var missing_columns = (16 - chunk.len) * 3;
501510 if (chunk.len < 8) missing_columns += 1;
502 try writer.writeByteNTimes(' ', missing_columns);
511 try writer.splatByteAll(' ', missing_columns);
503512 }
504513 for (chunk, 0..) |byte, col| {
505514 const diff = diffs.isSet(col);
......@@ -528,7 +537,7 @@ const BytesDiffer = struct {
528537 }
529538 }
530539
531 fn writeDiff(self: BytesDiffer, writer: anytype, comptime fmt: []const u8, args: anytype, diff: bool) !void {
540 fn writeDiff(self: BytesDiffer, writer: *std.io.Writer, comptime fmt: []const u8, args: anytype, diff: bool) !void {
532541 if (diff) try self.ttyconf.setColor(writer, .red);
533542 try writer.print(fmt, args);
534543 if (diff) try self.ttyconf.setColor(writer, .reset);
......@@ -637,6 +646,11 @@ pub fn tmpDir(opts: std.fs.Dir.OpenOptions) TmpDir {
637646
638647pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void {
639648 if (std.mem.indexOfDiff(u8, actual, expected)) |diff_index| {
649 if (@inComptime()) {
650 @compileError(std.fmt.comptimePrint("\nexpected:\n{s}\nfound:\n{s}\ndifference starts at index {d}", .{
651 expected, actual, diff_index,
652 }));
653 }
640654 print("\n====== expected this output: =========\n", .{});
641655 printWithVisibleNewlines(expected);
642656 print("\n======== instead found this: =========\n", .{});
......@@ -1108,7 +1122,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
11081122 const arg_i_str = comptime str: {
11091123 var str_buf: [100]u8 = undefined;
11101124 const args_i = i + 1;
1111 const str_len = std.fmt.formatIntBuf(&str_buf, args_i, 10, .lower, .{});
1125 const str_len = std.fmt.printInt(&str_buf, args_i, 10, .lower, .{});
11121126 break :str str_buf[0..str_len];
11131127 };
11141128 @field(args, arg_i_str) = @field(extra_args, field.name);
......@@ -1138,7 +1152,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
11381152 error.OutOfMemory => {
11391153 if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) {
11401154 print(
1141 "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {}",
1155 "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}",
11421156 .{
11431157 fail_index,
11441158 needed_alloc_count,
......@@ -1192,3 +1206,43 @@ pub inline fn fuzz(
11921206) anyerror!void {
11931207 return @import("root").fuzz(context, testOne, options);
11941208}
1209
1210/// A `std.io.Reader` that writes a predetermined list of buffers during `stream`.
1211pub const Reader = struct {
1212 calls: []const Call,
1213 interface: std.io.Reader,
1214 next_call_index: usize,
1215 next_offset: usize,
1216
1217 pub const Call = struct {
1218 buffer: []const u8,
1219 };
1220
1221 pub fn init(buffer: []u8, calls: []const Call) Reader {
1222 return .{
1223 .next_call_index = 0,
1224 .next_offset = 0,
1225 .interface = .{
1226 .vtable = &.{ .stream = stream },
1227 .buffer = buffer,
1228 .seek = 0,
1229 .end = 0,
1230 },
1231 .calls = calls,
1232 };
1233 }
1234
1235 fn stream(io_r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {
1236 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_r));
1237 if (r.calls.len - r.next_call_index == 0) return error.EndOfStream;
1238 const call = r.calls[r.next_call_index];
1239 const buffer = limit.sliceConst(call.buffer[r.next_offset..]);
1240 const n = try w.write(buffer);
1241 r.next_offset += n;
1242 if (call.buffer.len - r.next_offset == 0) {
1243 r.next_call_index += 1;
1244 r.next_offset = 0;
1245 }
1246 return n;
1247 }
1248};
lib/std/unicode.zig+23-36
......@@ -9,6 +9,7 @@ const native_endian = builtin.cpu.arch.endian();
99///
1010/// See also: https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character
1111pub const replacement_character: u21 = 0xFFFD;
12pub const replacement_character_utf8: [3]u8 = utf8EncodeComptime(replacement_character);
1213
1314/// Returns how many bytes the UTF-8 representation would require
1415/// for the given codepoint.
......@@ -802,14 +803,7 @@ fn testDecode(bytes: []const u8) !u21 {
802803/// Ill-formed UTF-8 byte sequences are replaced by the replacement character (U+FFFD)
803804/// according to "U+FFFD Substitution of Maximal Subparts" from Chapter 3 of
804805/// the Unicode standard, and as specified by https://encoding.spec.whatwg.org/#utf-8-decoder
805fn formatUtf8(
806 utf8: []const u8,
807 comptime fmt: []const u8,
808 options: std.fmt.FormatOptions,
809 writer: anytype,
810) !void {
811 _ = fmt;
812 _ = options;
806fn formatUtf8(utf8: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void {
813807 var buf: [300]u8 = undefined; // just an arbitrary size
814808 var u8len: usize = 0;
815809
......@@ -898,27 +892,27 @@ fn formatUtf8(
898892/// Ill-formed UTF-8 byte sequences are replaced by the replacement character (U+FFFD)
899893/// according to "U+FFFD Substitution of Maximal Subparts" from Chapter 3 of
900894/// the Unicode standard, and as specified by https://encoding.spec.whatwg.org/#utf-8-decoder
901pub fn fmtUtf8(utf8: []const u8) std.fmt.Formatter(formatUtf8) {
895pub fn fmtUtf8(utf8: []const u8) std.fmt.Formatter([]const u8, formatUtf8) {
902896 return .{ .data = utf8 };
903897}
904898
905899test fmtUtf8 {
906900 const expectFmt = testing.expectFmt;
907 try expectFmt("", "{}", .{fmtUtf8("")});
908 try expectFmt("foo", "{}", .{fmtUtf8("foo")});
909 try expectFmt("𐐷", "{}", .{fmtUtf8("𐐷")});
901 try expectFmt("", "{f}", .{fmtUtf8("")});
902 try expectFmt("foo", "{f}", .{fmtUtf8("foo")});
903 try expectFmt("𐐷", "{f}", .{fmtUtf8("𐐷")});
910904
911905 // Table 3-8. U+FFFD for Non-Shortest Form Sequences
912 try expectFmt("��������A", "{}", .{fmtUtf8("\xC0\xAF\xE0\x80\xBF\xF0\x81\x82A")});
906 try expectFmt("��������A", "{f}", .{fmtUtf8("\xC0\xAF\xE0\x80\xBF\xF0\x81\x82A")});
913907
914908 // Table 3-9. U+FFFD for Ill-Formed Sequences for Surrogates
915 try expectFmt("��������A", "{}", .{fmtUtf8("\xED\xA0\x80\xED\xBF\xBF\xED\xAFA")});
909 try expectFmt("��������A", "{f}", .{fmtUtf8("\xED\xA0\x80\xED\xBF\xBF\xED\xAFA")});
916910
917911 // Table 3-10. U+FFFD for Other Ill-Formed Sequences
918 try expectFmt("�����A��B", "{}", .{fmtUtf8("\xF4\x91\x92\x93\xFFA\x80\xBFB")});
912 try expectFmt("�����A��B", "{f}", .{fmtUtf8("\xF4\x91\x92\x93\xFFA\x80\xBFB")});
919913
920914 // Table 3-11. U+FFFD for Truncated Sequences
921 try expectFmt("����A", "{}", .{fmtUtf8("\xE1\x80\xE2\xF0\x91\x92\xF1\xBFA")});
915 try expectFmt("����A", "{f}", .{fmtUtf8("\xE1\x80\xE2\xF0\x91\x92\xF1\xBFA")});
922916}
923917
924918fn utf16LeToUtf8ArrayListImpl(
......@@ -1477,14 +1471,7 @@ test calcWtf16LeLen {
14771471
14781472/// Print the given `utf16le` string, encoded as UTF-8 bytes.
14791473/// Unpaired surrogates are replaced by the replacement character (U+FFFD).
1480fn formatUtf16Le(
1481 utf16le: []const u16,
1482 comptime fmt: []const u8,
1483 options: std.fmt.FormatOptions,
1484 writer: anytype,
1485) !void {
1486 _ = fmt;
1487 _ = options;
1474fn formatUtf16Le(utf16le: []const u16, writer: *std.io.Writer) std.io.Writer.Error!void {
14881475 var buf: [300]u8 = undefined; // just an arbitrary size
14891476 var it = Utf16LeIterator.init(utf16le);
14901477 var u8len: usize = 0;
......@@ -1505,23 +1492,23 @@ pub const fmtUtf16le = @compileError("deprecated; renamed to fmtUtf16Le");
15051492/// Return a Formatter for a (potentially ill-formed) UTF-16 LE string,
15061493/// which will be converted to UTF-8 during formatting.
15071494/// Unpaired surrogates are replaced by the replacement character (U+FFFD).
1508pub fn fmtUtf16Le(utf16le: []const u16) std.fmt.Formatter(formatUtf16Le) {
1495pub fn fmtUtf16Le(utf16le: []const u16) std.fmt.Formatter([]const u16, formatUtf16Le) {
15091496 return .{ .data = utf16le };
15101497}
15111498
15121499test fmtUtf16Le {
15131500 const expectFmt = testing.expectFmt;
1514 try expectFmt("", "{}", .{fmtUtf16Le(utf8ToUtf16LeStringLiteral(""))});
1515 try expectFmt("", "{}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral(""))});
1516 try expectFmt("foo", "{}", .{fmtUtf16Le(utf8ToUtf16LeStringLiteral("foo"))});
1517 try expectFmt("foo", "{}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral("foo"))});
1518 try expectFmt("𐐷", "{}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral("𐐷"))});
1519 try expectFmt("퟿", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xd7", native_endian)})});
1520 try expectFmt("�", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xd8", native_endian)})});
1521 try expectFmt("�", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xdb", native_endian)})});
1522 try expectFmt("�", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xdc", native_endian)})});
1523 try expectFmt("�", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xdf", native_endian)})});
1524 try expectFmt("", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xe0", native_endian)})});
1501 try expectFmt("", "{f}", .{fmtUtf16Le(utf8ToUtf16LeStringLiteral(""))});
1502 try expectFmt("", "{f}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral(""))});
1503 try expectFmt("foo", "{f}", .{fmtUtf16Le(utf8ToUtf16LeStringLiteral("foo"))});
1504 try expectFmt("foo", "{f}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral("foo"))});
1505 try expectFmt("𐐷", "{f}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral("𐐷"))});
1506 try expectFmt("퟿", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xd7", native_endian)})});
1507 try expectFmt("�", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xd8", native_endian)})});
1508 try expectFmt("�", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xdb", native_endian)})});
1509 try expectFmt("�", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xdc", native_endian)})});
1510 try expectFmt("�", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xdf", native_endian)})});
1511 try expectFmt("", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xe0", native_endian)})});
15251512}
15261513
15271514fn testUtf8ToUtf16LeStringLiteral(utf8ToUtf16LeStringLiteral_: anytype) !void {
lib/std/unicode/throughput_test.zig+1-1
......@@ -39,7 +39,7 @@ fn benchmarkCodepointCount(buf: []const u8) !ResultCount {
3939}
4040
4141pub fn main() !void {
42 const stdout = std.io.getStdOut().writer();
42 const stdout = std.fs.File.stdout().deprecatedWriter();
4343
4444 try stdout.print("short ASCII strings\n", .{});
4545 {
lib/std/zig.zig+107-120
......@@ -48,7 +48,7 @@ pub const Color = enum {
4848
4949 pub fn get_tty_conf(color: Color) std.io.tty.Config {
5050 return switch (color) {
51 .auto => std.io.tty.detectConfig(std.io.getStdErr()),
51 .auto => std.io.tty.detectConfig(std.fs.File.stderr()),
5252 .on => .escape_codes,
5353 .off => .no_color,
5454 };
......@@ -363,149 +363,136 @@ const Allocator = std.mem.Allocator;
363363
364364/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
365365///
366/// - An empty `{}` format specifier escapes invalid identifiers, identifiers that shadow primitives
367/// and the reserved `_` identifier.
368/// - Add `p` to the specifier to render identifiers that shadow primitives unescaped.
369/// - Add `_` to the specifier to render the reserved `_` identifier unescaped.
370/// - `p` and `_` can be combined, e.g. `{p_}`.
366/// See also `fmtIdFlags`.
367pub fn fmtId(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
368 return .{ .data = .{ .bytes = bytes, .flags = .{} } };
369}
370
371/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
371372///
372pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) {
373 return .{ .data = bytes };
373/// See also `fmtId`.
374pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) std.fmt.Formatter(FormatId, FormatId.render) {
375 return .{ .data = .{ .bytes = bytes, .flags = flags } };
376}
377
378pub fn fmtIdPU(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
379 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } } };
380}
381
382pub fn fmtIdP(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
383 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true } } };
374384}
375385
376386test fmtId {
377387 const expectFmt = std.testing.expectFmt;
378 try expectFmt("@\"while\"", "{}", .{fmtId("while")});
379 try expectFmt("@\"while\"", "{p}", .{fmtId("while")});
380 try expectFmt("@\"while\"", "{_}", .{fmtId("while")});
381 try expectFmt("@\"while\"", "{p_}", .{fmtId("while")});
382 try expectFmt("@\"while\"", "{_p}", .{fmtId("while")});
383
384 try expectFmt("hello", "{}", .{fmtId("hello")});
385 try expectFmt("hello", "{p}", .{fmtId("hello")});
386 try expectFmt("hello", "{_}", .{fmtId("hello")});
387 try expectFmt("hello", "{p_}", .{fmtId("hello")});
388 try expectFmt("hello", "{_p}", .{fmtId("hello")});
389
390 try expectFmt("@\"type\"", "{}", .{fmtId("type")});
391 try expectFmt("type", "{p}", .{fmtId("type")});
392 try expectFmt("@\"type\"", "{_}", .{fmtId("type")});
393 try expectFmt("type", "{p_}", .{fmtId("type")});
394 try expectFmt("type", "{_p}", .{fmtId("type")});
395
396 try expectFmt("@\"_\"", "{}", .{fmtId("_")});
397 try expectFmt("@\"_\"", "{p}", .{fmtId("_")});
398 try expectFmt("_", "{_}", .{fmtId("_")});
399 try expectFmt("_", "{p_}", .{fmtId("_")});
400 try expectFmt("_", "{_p}", .{fmtId("_")});
401
402 try expectFmt("@\"i123\"", "{}", .{fmtId("i123")});
403 try expectFmt("i123", "{p}", .{fmtId("i123")});
404 try expectFmt("@\"4four\"", "{}", .{fmtId("4four")});
405 try expectFmt("_underscore", "{}", .{fmtId("_underscore")});
406 try expectFmt("@\"11\\\"23\"", "{}", .{fmtId("11\"23")});
407 try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")});
388 try expectFmt("@\"while\"", "{f}", .{fmtId("while")});
389 try expectFmt("@\"while\"", "{f}", .{fmtIdFlags("while", .{ .allow_primitive = true })});
390 try expectFmt("@\"while\"", "{f}", .{fmtIdFlags("while", .{ .allow_underscore = true })});
391 try expectFmt("@\"while\"", "{f}", .{fmtIdFlags("while", .{ .allow_primitive = true, .allow_underscore = true })});
392
393 try expectFmt("hello", "{f}", .{fmtId("hello")});
394 try expectFmt("hello", "{f}", .{fmtIdFlags("hello", .{ .allow_primitive = true })});
395 try expectFmt("hello", "{f}", .{fmtIdFlags("hello", .{ .allow_underscore = true })});
396 try expectFmt("hello", "{f}", .{fmtIdFlags("hello", .{ .allow_primitive = true, .allow_underscore = true })});
397
398 try expectFmt("@\"type\"", "{f}", .{fmtId("type")});
399 try expectFmt("type", "{f}", .{fmtIdFlags("type", .{ .allow_primitive = true })});
400 try expectFmt("@\"type\"", "{f}", .{fmtIdFlags("type", .{ .allow_underscore = true })});
401 try expectFmt("type", "{f}", .{fmtIdFlags("type", .{ .allow_primitive = true, .allow_underscore = true })});
402
403 try expectFmt("@\"_\"", "{f}", .{fmtId("_")});
404 try expectFmt("@\"_\"", "{f}", .{fmtIdFlags("_", .{ .allow_primitive = true })});
405 try expectFmt("_", "{f}", .{fmtIdFlags("_", .{ .allow_underscore = true })});
406 try expectFmt("_", "{f}", .{fmtIdFlags("_", .{ .allow_primitive = true, .allow_underscore = true })});
407
408 try expectFmt("@\"i123\"", "{f}", .{fmtId("i123")});
409 try expectFmt("i123", "{f}", .{fmtIdFlags("i123", .{ .allow_primitive = true })});
410 try expectFmt("@\"4four\"", "{f}", .{fmtId("4four")});
411 try expectFmt("_underscore", "{f}", .{fmtId("_underscore")});
412 try expectFmt("@\"11\\\"23\"", "{f}", .{fmtId("11\"23")});
413 try expectFmt("@\"11\\x0f23\"", "{f}", .{fmtId("11\x0F23")});
408414
409415 // These are technically not currently legal in Zig.
410 try expectFmt("@\"\"", "{}", .{fmtId("")});
411 try expectFmt("@\"\\x00\"", "{}", .{fmtId("\x00")});
416 try expectFmt("@\"\"", "{f}", .{fmtId("")});
417 try expectFmt("@\"\\x00\"", "{f}", .{fmtId("\x00")});
412418}
413419
414/// Print the string as a Zig identifier, escaping it with `@""` syntax if needed.
415fn formatId(
420pub const FormatId = struct {
416421 bytes: []const u8,
417 comptime fmt: []const u8,
418 options: std.fmt.FormatOptions,
419 writer: anytype,
420) !void {
421 const allow_primitive, const allow_underscore = comptime parse_fmt: {
422 var allow_primitive = false;
423 var allow_underscore = false;
424 for (fmt) |char| {
425 switch (char) {
426 'p' => if (!allow_primitive) {
427 allow_primitive = true;
428 continue;
429 },
430 '_' => if (!allow_underscore) {
431 allow_underscore = true;
432 continue;
433 },
434 else => {},
435 }
436 @compileError("expected {}, {p}, {_}, {p_} or {_p}, found {" ++ fmt ++ "}");
437 }
438 break :parse_fmt .{ allow_primitive, allow_underscore };
422 flags: Flags,
423 pub const Flags = struct {
424 allow_primitive: bool = false,
425 allow_underscore: bool = false,
439426 };
440427
441 if (isValidId(bytes) and
442 (allow_primitive or !std.zig.isPrimitive(bytes)) and
443 (allow_underscore or !isUnderscore(bytes)))
444 {
445 return writer.writeAll(bytes);
428 /// Print the string as a Zig identifier, escaping it with `@""` syntax if needed.
429 fn render(ctx: FormatId, writer: *std.io.Writer) std.io.Writer.Error!void {
430 const bytes = ctx.bytes;
431 if (isValidId(bytes) and
432 (ctx.flags.allow_primitive or !std.zig.isPrimitive(bytes)) and
433 (ctx.flags.allow_underscore or !isUnderscore(bytes)))
434 {
435 return writer.writeAll(bytes);
436 }
437 try writer.writeAll("@\"");
438 try stringEscape(bytes, writer);
439 try writer.writeByte('"');
446440 }
447 try writer.writeAll("@\"");
448 try stringEscape(bytes, "", options, writer);
449 try writer.writeByte('"');
441};
442
443/// Return a formatter for escaping a double quoted Zig string.
444pub fn fmtString(bytes: []const u8) std.fmt.Formatter([]const u8, stringEscape) {
445 return .{ .data = bytes };
450446}
451447
452/// Return a Formatter for Zig Escapes of a double quoted string.
453/// The format specifier must be one of:
454/// * `{}` treats contents as a double-quoted string.
455/// * `{'}` treats contents as a single-quoted string.
456pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) {
448/// Return a formatter for escaping a single quoted Zig string.
449pub fn fmtChar(bytes: []const u8) std.fmt.Formatter([]const u8, charEscape) {
457450 return .{ .data = bytes };
458451}
459452
460test fmtEscapes {
461 const expectFmt = std.testing.expectFmt;
462 try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")});
463 try expectFmt(
464 \\" \\ hi \x07 \x11 " derp \'"
465 , "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
466 try expectFmt(
453test fmtString {
454 try std.testing.expectFmt("\\x0f", "{f}", .{fmtString("\x0f")});
455 try std.testing.expectFmt(
467456 \\" \\ hi \x07 \x11 \" derp '"
468 , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")});
457 , "\"{f}\"", .{fmtString(" \\ hi \x07 \x11 \" derp '")});
469458}
470459
471/// Print the string as escaped contents of a double quoted or single-quoted string.
472/// Format `{}` treats contents as a double-quoted string.
473/// Format `{'}` treats contents as a single-quoted string.
474pub fn stringEscape(
475 bytes: []const u8,
476 comptime f: []const u8,
477 options: std.fmt.FormatOptions,
478 writer: anytype,
479) !void {
480 _ = options;
460test fmtChar {
461 try std.testing.expectFmt(
462 \\" \\ hi \x07 \x11 " derp \'"
463 , "\"{f}\"", .{fmtChar(" \\ hi \x07 \x11 \" derp '")});
464}
465
466/// Print the string as escaped contents of a double quoted string.
467pub fn stringEscape(bytes: []const u8, w: *std.io.Writer) std.io.Writer.Error!void {
481468 for (bytes) |byte| switch (byte) {
482 '\n' => try writer.writeAll("\\n"),
483 '\r' => try writer.writeAll("\\r"),
484 '\t' => try writer.writeAll("\\t"),
485 '\\' => try writer.writeAll("\\\\"),
486 '"' => {
487 if (f.len == 1 and f[0] == '\'') {
488 try writer.writeByte('"');
489 } else if (f.len == 0) {
490 try writer.writeAll("\\\"");
491 } else {
492 @compileError("expected {} or {'}, found {" ++ f ++ "}");
493 }
494 },
495 '\'' => {
496 if (f.len == 1 and f[0] == '\'') {
497 try writer.writeAll("\\'");
498 } else if (f.len == 0) {
499 try writer.writeByte('\'');
500 } else {
501 @compileError("expected {} or {'}, found {" ++ f ++ "}");
502 }
469 '\n' => try w.writeAll("\\n"),
470 '\r' => try w.writeAll("\\r"),
471 '\t' => try w.writeAll("\\t"),
472 '\\' => try w.writeAll("\\\\"),
473 '"' => try w.writeAll("\\\""),
474 '\'' => try w.writeByte('\''),
475 ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte),
476 else => {
477 try w.writeAll("\\x");
478 try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' });
503479 },
504 ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte),
505 // Use hex escapes for rest any unprintable characters.
480 };
481}
482
483/// Print the string as escaped contents of a single-quoted string.
484pub fn charEscape(bytes: []const u8, w: *std.io.Writer) std.io.Writer.Error!void {
485 for (bytes) |byte| switch (byte) {
486 '\n' => try w.writeAll("\\n"),
487 '\r' => try w.writeAll("\\r"),
488 '\t' => try w.writeAll("\\t"),
489 '\\' => try w.writeAll("\\\\"),
490 '"' => try w.writeByte('"'),
491 '\'' => try w.writeAll("\\'"),
492 ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte),
506493 else => {
507 try writer.writeAll("\\x");
508 try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer);
494 try w.writeAll("\\x");
495 try w.printInt(byte, 16, .lower, .{ .width = 2, .fill = '0' });
509496 },
510497 };
511498}
lib/std/zig/Ast.zig+2-2
......@@ -565,14 +565,14 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
565565
566566 .invalid_byte => {
567567 const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..];
568 return stream.print("{s} contains invalid byte: '{'}'", .{
568 return stream.print("{s} contains invalid byte: '{f}'", .{
569569 switch (tok_slice[0]) {
570570 '\'' => "character literal",
571571 '"', '\\' => "string literal",
572572 '/' => "comment",
573573 else => unreachable,
574574 },
575 std.zig.fmtEscapes(tok_slice[parse_error.extra.offset..][0..1]),
575 std.zig.fmtChar(tok_slice[parse_error.extra.offset..][0..1]),
576576 });
577577 },
578578
lib/std/zig/AstGen.zig+1-7
......@@ -11305,13 +11305,7 @@ fn failWithStrLitError(
1130511305 offset: u32,
1130611306) InnerError {
1130711307 const raw_string = bytes[offset..];
11308 return failOff(
11309 astgen,
11310 token,
11311 @intCast(offset + err.offset()),
11312 "{}",
11313 .{err.fmt(raw_string)},
11314 );
11308 return failOff(astgen, token, @intCast(offset + err.offset()), "{f}", .{err.fmt(raw_string)});
1131511309}
1131611310
1131711311fn failNode(
lib/std/zig/ErrorBundle.zig+81-71
......@@ -7,6 +7,12 @@
77//! empty, it means there are no errors. This special encoding exists so that
88//! heap allocation is not needed in the common case of no errors.
99
10const std = @import("std");
11const ErrorBundle = @This();
12const Allocator = std.mem.Allocator;
13const assert = std.debug.assert;
14const Writer = std.io.Writer;
15
1016string_bytes: []const u8,
1117/// The first thing in this array is an `ErrorMessageList`.
1218extra: []const u32,
......@@ -157,23 +163,23 @@ pub const RenderOptions = struct {
157163};
158164
159165pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {
160 std.debug.lockStdErr();
161 defer std.debug.unlockStdErr();
162 const stderr = std.io.getStdErr();
163 return renderToWriter(eb, options, stderr.writer()) catch return;
166 var buffer: [256]u8 = undefined;
167 const w = std.debug.lockStderrWriter(&buffer);
168 defer std.debug.unlockStderrWriter();
169 renderToWriter(eb, options, w) catch return;
164170}
165171
166pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void {
172pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer) (Writer.Error || std.posix.UnexpectedError)!void {
167173 if (eb.extra.len == 0) return;
168174 for (eb.getMessages()) |err_msg| {
169 try renderErrorMessageToWriter(eb, options, err_msg, writer, "error", .red, 0);
175 try renderErrorMessageToWriter(eb, options, err_msg, w, "error", .red, 0);
170176 }
171177
172178 if (options.include_log_text) {
173179 const log_text = eb.getCompileLogOutput();
174180 if (log_text.len != 0) {
175 try writer.writeAll("\nCompile Log Output:\n");
176 try writer.writeAll(log_text);
181 try w.writeAll("\nCompile Log Output:\n");
182 try w.writeAll(log_text);
177183 }
178184 }
179185}
......@@ -182,74 +188,81 @@ fn renderErrorMessageToWriter(
182188 eb: ErrorBundle,
183189 options: RenderOptions,
184190 err_msg_index: MessageIndex,
185 stderr: anytype,
191 w: *Writer,
186192 kind: []const u8,
187193 color: std.io.tty.Color,
188194 indent: usize,
189) anyerror!void {
195) (Writer.Error || std.posix.UnexpectedError)!void {
190196 const ttyconf = options.ttyconf;
191 var counting_writer = std.io.countingWriter(stderr);
192 const counting_stderr = counting_writer.writer();
193197 const err_msg = eb.getErrorMessage(err_msg_index);
194198 if (err_msg.src_loc != .none) {
195199 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
196 try counting_stderr.writeByteNTimes(' ', indent);
197 try ttyconf.setColor(stderr, .bold);
198 try counting_stderr.print("{s}:{d}:{d}: ", .{
200 var prefix: std.io.Writer.Discarding = .init(&.{});
201 try w.splatByteAll(' ', indent);
202 prefix.count += indent;
203 try ttyconf.setColor(w, .bold);
204 try w.print("{s}:{d}:{d}: ", .{
205 eb.nullTerminatedString(src.data.src_path),
206 src.data.line + 1,
207 src.data.column + 1,
208 });
209 try prefix.writer.print("{s}:{d}:{d}: ", .{
199210 eb.nullTerminatedString(src.data.src_path),
200211 src.data.line + 1,
201212 src.data.column + 1,
202213 });
203 try ttyconf.setColor(stderr, color);
204 try counting_stderr.writeAll(kind);
205 try counting_stderr.writeAll(": ");
214 try ttyconf.setColor(w, color);
215 try w.writeAll(kind);
216 prefix.count += kind.len;
217 try w.writeAll(": ");
218 prefix.count += 2;
206219 // This is the length of the part before the error message:
207220 // e.g. "file.zig:4:5: error: "
208 const prefix_len: usize = @intCast(counting_stderr.context.bytes_written);
209 try ttyconf.setColor(stderr, .reset);
210 try ttyconf.setColor(stderr, .bold);
221 const prefix_len: usize = @intCast(prefix.count);
222 try ttyconf.setColor(w, .reset);
223 try ttyconf.setColor(w, .bold);
211224 if (err_msg.count == 1) {
212 try writeMsg(eb, err_msg, stderr, prefix_len);
213 try stderr.writeByte('\n');
225 try writeMsg(eb, err_msg, w, prefix_len);
226 try w.writeByte('\n');
214227 } else {
215 try writeMsg(eb, err_msg, stderr, prefix_len);
216 try ttyconf.setColor(stderr, .dim);
217 try stderr.print(" ({d} times)\n", .{err_msg.count});
228 try writeMsg(eb, err_msg, w, prefix_len);
229 try ttyconf.setColor(w, .dim);
230 try w.print(" ({d} times)\n", .{err_msg.count});
218231 }
219 try ttyconf.setColor(stderr, .reset);
232 try ttyconf.setColor(w, .reset);
220233 if (src.data.source_line != 0 and options.include_source_line) {
221234 const line = eb.nullTerminatedString(src.data.source_line);
222235 for (line) |b| switch (b) {
223 '\t' => try stderr.writeByte(' '),
224 else => try stderr.writeByte(b),
236 '\t' => try w.writeByte(' '),
237 else => try w.writeByte(b),
225238 };
226 try stderr.writeByte('\n');
239 try w.writeByte('\n');
227240 // TODO basic unicode code point monospace width
228241 const before_caret = src.data.span_main - src.data.span_start;
229242 // -1 since span.main includes the caret
230243 const after_caret = src.data.span_end -| src.data.span_main -| 1;
231 try stderr.writeByteNTimes(' ', src.data.column - before_caret);
232 try ttyconf.setColor(stderr, .green);
233 try stderr.writeByteNTimes('~', before_caret);
234 try stderr.writeByte('^');
235 try stderr.writeByteNTimes('~', after_caret);
236 try stderr.writeByte('\n');
237 try ttyconf.setColor(stderr, .reset);
244 try w.splatByteAll(' ', src.data.column - before_caret);
245 try ttyconf.setColor(w, .green);
246 try w.splatByteAll('~', before_caret);
247 try w.writeByte('^');
248 try w.splatByteAll('~', after_caret);
249 try w.writeByte('\n');
250 try ttyconf.setColor(w, .reset);
238251 }
239252 for (eb.getNotes(err_msg_index)) |note| {
240 try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent);
253 try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent);
241254 }
242255 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
243 try ttyconf.setColor(stderr, .reset);
244 try ttyconf.setColor(stderr, .dim);
245 try stderr.print("referenced by:\n", .{});
256 try ttyconf.setColor(w, .reset);
257 try ttyconf.setColor(w, .dim);
258 try w.print("referenced by:\n", .{});
246259 var ref_index = src.end;
247260 for (0..src.data.reference_trace_len) |_| {
248261 const ref_trace = eb.extraData(ReferenceTrace, ref_index);
249262 ref_index = ref_trace.end;
250263 if (ref_trace.data.src_loc != .none) {
251264 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
252 try stderr.print(" {s}: {s}:{d}:{d}\n", .{
265 try w.print(" {s}: {s}:{d}:{d}\n", .{
253266 eb.nullTerminatedString(ref_trace.data.decl_name),
254267 eb.nullTerminatedString(ref_src.src_path),
255268 ref_src.line + 1,
......@@ -257,36 +270,36 @@ fn renderErrorMessageToWriter(
257270 });
258271 } else if (ref_trace.data.decl_name != 0) {
259272 const count = ref_trace.data.decl_name;
260 try stderr.print(
273 try w.print(
261274 " {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
262275 .{ count, count + src.data.reference_trace_len - 1 },
263276 );
264277 } else {
265 try stderr.print(
278 try w.print(
266279 " remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
267280 .{},
268281 );
269282 }
270283 }
271 try ttyconf.setColor(stderr, .reset);
284 try ttyconf.setColor(w, .reset);
272285 }
273286 } else {
274 try ttyconf.setColor(stderr, color);
275 try stderr.writeByteNTimes(' ', indent);
276 try stderr.writeAll(kind);
277 try stderr.writeAll(": ");
278 try ttyconf.setColor(stderr, .reset);
287 try ttyconf.setColor(w, color);
288 try w.splatByteAll(' ', indent);
289 try w.writeAll(kind);
290 try w.writeAll(": ");
291 try ttyconf.setColor(w, .reset);
279292 const msg = eb.nullTerminatedString(err_msg.msg);
280293 if (err_msg.count == 1) {
281 try stderr.print("{s}\n", .{msg});
294 try w.print("{s}\n", .{msg});
282295 } else {
283 try stderr.print("{s}", .{msg});
284 try ttyconf.setColor(stderr, .dim);
285 try stderr.print(" ({d} times)\n", .{err_msg.count});
296 try w.print("{s}", .{msg});
297 try ttyconf.setColor(w, .dim);
298 try w.print(" ({d} times)\n", .{err_msg.count});
286299 }
287 try ttyconf.setColor(stderr, .reset);
300 try ttyconf.setColor(w, .reset);
288301 for (eb.getNotes(err_msg_index)) |note| {
289 try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent + 4);
302 try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent + 4);
290303 }
291304 }
292305}
......@@ -295,21 +308,16 @@ fn renderErrorMessageToWriter(
295308/// to allow for long, good-looking error messages.
296309///
297310/// This is used to split the message in `@compileError("hello\nworld")` for example.
298fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void {
311fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, w: *Writer, indent: usize) !void {
299312 var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n');
300313 while (lines.next()) |line| {
301 try stderr.writeAll(line);
314 try w.writeAll(line);
302315 if (lines.index == null) break;
303 try stderr.writeByte('\n');
304 try stderr.writeByteNTimes(' ', indent);
316 try w.writeByte('\n');
317 try w.splatByteAll(' ', indent);
305318 }
306319}
307320
308const std = @import("std");
309const ErrorBundle = @This();
310const Allocator = std.mem.Allocator;
311const assert = std.debug.assert;
312
313321pub const Wip = struct {
314322 gpa: Allocator,
315323 string_bytes: std.ArrayListUnmanaged(u8),
......@@ -398,7 +406,7 @@ pub const Wip = struct {
398406 pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) Allocator.Error!String {
399407 const gpa = wip.gpa;
400408 const index: String = @intCast(wip.string_bytes.items.len);
401 try wip.string_bytes.writer(gpa).print(fmt, args);
409 try wip.string_bytes.print(gpa, fmt, args);
402410 try wip.string_bytes.append(gpa, 0);
403411 return index;
404412 }
......@@ -788,9 +796,10 @@ pub const Wip = struct {
788796
789797 const ttyconf: std.io.tty.Config = .no_color;
790798
791 var bundle_buf = std.ArrayList(u8).init(std.testing.allocator);
799 var bundle_buf: std.io.Writer.Allocating = .init(std.testing.allocator);
800 const bundle_bw = &bundle_buf.interface;
792801 defer bundle_buf.deinit();
793 try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_buf.writer());
802 try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw);
794803
795804 var copy = copy: {
796805 var wip: ErrorBundle.Wip = undefined;
......@@ -803,10 +812,11 @@ pub const Wip = struct {
803812 };
804813 defer copy.deinit(std.testing.allocator);
805814
806 var copy_buf = std.ArrayList(u8).init(std.testing.allocator);
815 var copy_buf: std.io.Writer.Allocating = .init(std.testing.allocator);
816 const copy_bw = &copy_buf.interface;
807817 defer copy_buf.deinit();
808 try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_buf.writer());
818 try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw);
809819
810 try std.testing.expectEqualStrings(bundle_buf.items, copy_buf.items);
820 try std.testing.expectEqualStrings(bundle_bw.getWritten(), copy_bw.getWritten());
811821 }
812822};
lib/std/zig/ZonGen.zig+1-7
......@@ -756,13 +756,7 @@ fn lowerStrLitError(
756756 raw_string: []const u8,
757757 offset: u32,
758758) Allocator.Error!void {
759 return ZonGen.addErrorTokOff(
760 zg,
761 token,
762 @intCast(offset + err.offset()),
763 "{}",
764 .{err.fmt(raw_string)},
765 );
759 return ZonGen.addErrorTokOff(zg, token, @intCast(offset + err.offset()), "{f}", .{err.fmt(raw_string)});
766760}
767761
768762fn lowerNumberError(zg: *ZonGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) Allocator.Error!void {
lib/std/zig/llvm/Builder.zig+718-741
......@@ -1,3 +1,14 @@
1const std = @import("../../std.zig");
2const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
4const bitcode_writer = @import("bitcode_writer.zig");
5const Builder = @This();
6const builtin = @import("builtin");
7const DW = std.dwarf;
8const ir = @import("ir.zig");
9const log = std.log.scoped(.llvm);
10const Writer = std.io.Writer;
11
112gpa: Allocator,
213strip: bool,
314
......@@ -90,31 +101,38 @@ pub const String = enum(u32) {
90101 const FormatData = struct {
91102 string: String,
92103 builder: *const Builder,
104 quote_behavior: ?QuoteBehavior,
93105 };
94 fn format(
95 data: FormatData,
96 comptime fmt_str: []const u8,
97 _: std.fmt.FormatOptions,
98 writer: anytype,
99 ) @TypeOf(writer).Error!void {
100 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_|
101 @compileError("invalid format string: '" ++ fmt_str ++ "'");
106 fn format(data: FormatData, w: *Writer) Writer.Error!void {
102107 assert(data.string != .none);
103108 const string_slice = data.string.slice(data.builder) orelse
104 return writer.print("{d}", .{@intFromEnum(data.string)});
105 if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_|
106 return writer.writeAll(string_slice);
107 try printEscapedString(
108 string_slice,
109 if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_|
110 .always_quote
111 else
112 .quote_unless_valid_identifier,
113 writer,
114 );
109 return w.print("{d}", .{@intFromEnum(data.string)});
110 const quote_behavior = data.quote_behavior orelse return w.writeAll(string_slice);
111 return printEscapedString(string_slice, quote_behavior, w);
112 }
113
114 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(FormatData, format) {
115 return .{ .data = .{
116 .string = self,
117 .builder = builder,
118 .quote_behavior = .quote_unless_valid_identifier,
119 } };
120 }
121
122 pub fn fmtQ(self: String, builder: *const Builder) std.fmt.Formatter(FormatData, format) {
123 return .{ .data = .{
124 .string = self,
125 .builder = builder,
126 .quote_behavior = .always_quote,
127 } };
115128 }
116 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {
117 return .{ .data = .{ .string = self, .builder = builder } };
129
130 pub fn fmtRaw(self: String, builder: *const Builder) std.fmt.Formatter(FormatData, format) {
131 return .{ .data = .{
132 .string = self,
133 .builder = builder,
134 .quote_behavior = null,
135 } };
118136 }
119137
120138 fn fromIndex(index: ?usize) String {
......@@ -228,7 +246,7 @@ pub const Type = enum(u32) {
228246 _,
229247
230248 pub const ptr_amdgpu_constant =
231 @field(Type, std.fmt.comptimePrint("ptr{ }", .{AddrSpace.amdgpu.constant}));
249 @field(Type, std.fmt.comptimePrint("ptr{f}", .{AddrSpace.amdgpu.constant.fmt(" ")}));
232250
233251 pub const Tag = enum(u4) {
234252 simple,
......@@ -653,18 +671,16 @@ pub const Type = enum(u32) {
653671 const FormatData = struct {
654672 type: Type,
655673 builder: *const Builder,
674 mode: Mode,
675
676 const Mode = enum { default, m, lt, gt, percent };
656677 };
657 fn format(
658 data: FormatData,
659 comptime fmt_str: []const u8,
660 fmt_opts: std.fmt.FormatOptions,
661 writer: anytype,
662 ) @TypeOf(writer).Error!void {
678 fn format(data: FormatData, w: *Writer) Writer.Error!void {
663679 assert(data.type != .none);
664 if (comptime std.mem.eql(u8, fmt_str, "m")) {
680 if (data.mode == .m) {
665681 const item = data.builder.type_items.items[@intFromEnum(data.type)];
666682 switch (item.tag) {
667 .simple => try writer.writeAll(switch (@as(Simple, @enumFromInt(item.data))) {
683 .simple => try w.writeAll(switch (@as(Simple, @enumFromInt(item.data))) {
668684 .void => "isVoid",
669685 .half => "f16",
670686 .bfloat => "bf16",
......@@ -681,36 +697,36 @@ pub const Type = enum(u32) {
681697 .function, .vararg_function => |kind| {
682698 var extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
683699 const params = extra.trail.next(extra.data.params_len, Type, data.builder);
684 try writer.print("f_{m}", .{extra.data.ret.fmt(data.builder)});
685 for (params) |param| try writer.print("{m}", .{param.fmt(data.builder)});
700 try w.print("f_{f}", .{extra.data.ret.fmt(data.builder, .m)});
701 for (params) |param| try w.print("{f}", .{param.fmt(data.builder, .m)});
686702 switch (kind) {
687703 .function => {},
688 .vararg_function => try writer.writeAll("vararg"),
704 .vararg_function => try w.writeAll("vararg"),
689705 else => unreachable,
690706 }
691 try writer.writeByte('f');
707 try w.writeByte('f');
692708 },
693 .integer => try writer.print("i{d}", .{item.data}),
694 .pointer => try writer.print("p{d}", .{item.data}),
709 .integer => try w.print("i{d}", .{item.data}),
710 .pointer => try w.print("p{d}", .{item.data}),
695711 .target => {
696712 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
697713 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
698714 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
699 try writer.print("t{s}", .{extra.data.name.slice(data.builder).?});
700 for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)});
701 for (ints) |int| try writer.print("_{d}", .{int});
702 try writer.writeByte('t');
715 try w.print("t{s}", .{extra.data.name.slice(data.builder).?});
716 for (types) |ty| try w.print("_{f}", .{ty.fmt(data.builder, .m)});
717 for (ints) |int| try w.print("_{d}", .{int});
718 try w.writeByte('t');
703719 },
704720 .vector, .scalable_vector => |kind| {
705721 const extra = data.builder.typeExtraData(Type.Vector, item.data);
706 try writer.print("{s}v{d}{m}", .{
722 try w.print("{s}v{d}{f}", .{
707723 switch (kind) {
708724 .vector => "",
709725 .scalable_vector => "nx",
710726 else => unreachable,
711727 },
712728 extra.len,
713 extra.child.fmt(data.builder),
729 extra.child.fmt(data.builder, .m),
714730 });
715731 },
716732 inline .small_array, .array => |kind| {
......@@ -719,72 +735,72 @@ pub const Type = enum(u32) {
719735 .array => Type.Array,
720736 else => unreachable,
721737 }, item.data);
722 try writer.print("a{d}{m}", .{ extra.length(), extra.child.fmt(data.builder) });
738 try w.print("a{d}{f}", .{ extra.length(), extra.child.fmt(data.builder, .m) });
723739 },
724740 .structure, .packed_structure => {
725741 var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
726742 const fields = extra.trail.next(extra.data.fields_len, Type, data.builder);
727 try writer.writeAll("sl_");
728 for (fields) |field| try writer.print("{m}", .{field.fmt(data.builder)});
729 try writer.writeByte('s');
743 try w.writeAll("sl_");
744 for (fields) |field| try w.print("{f}", .{field.fmt(data.builder, .m)});
745 try w.writeByte('s');
730746 },
731747 .named_structure => {
732748 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
733 try writer.writeAll("s_");
734 if (extra.id.slice(data.builder)) |id| try writer.writeAll(id);
749 try w.writeAll("s_");
750 if (extra.id.slice(data.builder)) |id| try w.writeAll(id);
735751 },
736752 }
737753 return;
738754 }
739 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
755 if (std.enums.tagName(Type, data.type)) |name| return w.writeAll(name);
740756 const item = data.builder.type_items.items[@intFromEnum(data.type)];
741757 switch (item.tag) {
742758 .simple => unreachable,
743759 .function, .vararg_function => |kind| {
744760 var extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
745761 const params = extra.trail.next(extra.data.params_len, Type, data.builder);
746 if (!comptime std.mem.eql(u8, fmt_str, ">"))
747 try writer.print("{%} ", .{extra.data.ret.fmt(data.builder)});
748 if (!comptime std.mem.eql(u8, fmt_str, "<")) {
749 try writer.writeByte('(');
762 if (data.mode != .gt)
763 try w.print("{f} ", .{extra.data.ret.fmt(data.builder, .percent)});
764 if (data.mode != .lt) {
765 try w.writeByte('(');
750766 for (params, 0..) |param, index| {
751 if (index > 0) try writer.writeAll(", ");
752 try writer.print("{%}", .{param.fmt(data.builder)});
767 if (index > 0) try w.writeAll(", ");
768 try w.print("{f}", .{param.fmt(data.builder, .percent)});
753769 }
754770 switch (kind) {
755771 .function => {},
756772 .vararg_function => {
757 if (params.len > 0) try writer.writeAll(", ");
758 try writer.writeAll("...");
773 if (params.len > 0) try w.writeAll(", ");
774 try w.writeAll("...");
759775 },
760776 else => unreachable,
761777 }
762 try writer.writeByte(')');
778 try w.writeByte(')');
763779 }
764780 },
765 .integer => try writer.print("i{d}", .{item.data}),
766 .pointer => try writer.print("ptr{ }", .{@as(AddrSpace, @enumFromInt(item.data))}),
781 .integer => try w.print("i{d}", .{item.data}),
782 .pointer => try w.print("ptr{f}", .{@as(AddrSpace, @enumFromInt(item.data)).fmt(" ")}),
767783 .target => {
768784 var extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
769785 const types = extra.trail.next(extra.data.types_len, Type, data.builder);
770786 const ints = extra.trail.next(extra.data.ints_len, u32, data.builder);
771 try writer.print(
772 \\target({"}
773 , .{extra.data.name.fmt(data.builder)});
774 for (types) |ty| try writer.print(", {%}", .{ty.fmt(data.builder)});
775 for (ints) |int| try writer.print(", {d}", .{int});
776 try writer.writeByte(')');
787 try w.print(
788 \\target({f}
789 , .{extra.data.name.fmtQ(data.builder)});
790 for (types) |ty| try w.print(", {f}", .{ty.fmt(data.builder, .percent)});
791 for (ints) |int| try w.print(", {d}", .{int});
792 try w.writeByte(')');
777793 },
778794 .vector, .scalable_vector => |kind| {
779795 const extra = data.builder.typeExtraData(Type.Vector, item.data);
780 try writer.print("<{s}{d} x {%}>", .{
796 try w.print("<{s}{d} x {f}>", .{
781797 switch (kind) {
782798 .vector => "",
783799 .scalable_vector => "vscale x ",
784800 else => unreachable,
785801 },
786802 extra.len,
787 extra.child.fmt(data.builder),
803 extra.child.fmt(data.builder, .percent),
788804 });
789805 },
790806 inline .small_array, .array => |kind| {
......@@ -793,44 +809,45 @@ pub const Type = enum(u32) {
793809 .array => Type.Array,
794810 else => unreachable,
795811 }, item.data);
796 try writer.print("[{d} x {%}]", .{ extra.length(), extra.child.fmt(data.builder) });
812 try w.print("[{d} x {f}]", .{ extra.length(), extra.child.fmt(data.builder, .percent) });
797813 },
798814 .structure, .packed_structure => |kind| {
799815 var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
800816 const fields = extra.trail.next(extra.data.fields_len, Type, data.builder);
801817 switch (kind) {
802818 .structure => {},
803 .packed_structure => try writer.writeByte('<'),
819 .packed_structure => try w.writeByte('<'),
804820 else => unreachable,
805821 }
806 try writer.writeAll("{ ");
822 try w.writeAll("{ ");
807823 for (fields, 0..) |field, index| {
808 if (index > 0) try writer.writeAll(", ");
809 try writer.print("{%}", .{field.fmt(data.builder)});
824 if (index > 0) try w.writeAll(", ");
825 try w.print("{f}", .{field.fmt(data.builder, .percent)});
810826 }
811 try writer.writeAll(" }");
827 try w.writeAll(" }");
812828 switch (kind) {
813829 .structure => {},
814 .packed_structure => try writer.writeByte('>'),
830 .packed_structure => try w.writeByte('>'),
815831 else => unreachable,
816832 }
817833 },
818834 .named_structure => {
819835 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
820 if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
836 if (data.mode == .percent) try w.print("%{f}", .{
821837 extra.id.fmt(data.builder),
822838 }) else switch (extra.body) {
823 .none => try writer.writeAll("opaque"),
839 .none => try w.writeAll("opaque"),
824840 else => try format(.{
825841 .type = extra.body,
826842 .builder = data.builder,
827 }, fmt_str, fmt_opts, writer),
843 .mode = data.mode,
844 }, w),
828845 }
829846 },
830847 }
831848 }
832 pub fn fmt(self: Type, builder: *const Builder) std.fmt.Formatter(format) {
833 return .{ .data = .{ .type = self, .builder = builder } };
849 pub fn fmt(self: Type, builder: *const Builder, mode: FormatData.Mode) std.fmt.Formatter(FormatData, format) {
850 return .{ .data = .{ .type = self, .builder = builder, .mode = mode } };
834851 }
835852
836853 const IsSizedVisited = std.AutoHashMapUnmanaged(Type, void);
......@@ -1138,15 +1155,13 @@ pub const Attribute = union(Kind) {
11381155 const FormatData = struct {
11391156 attribute_index: Index,
11401157 builder: *const Builder,
1158 flags: Flags = .{},
1159 const Flags = struct {
1160 pound: bool = false,
1161 quote: bool = false,
1162 };
11411163 };
1142 fn format(
1143 data: FormatData,
1144 comptime fmt_str: []const u8,
1145 _: std.fmt.FormatOptions,
1146 writer: anytype,
1147 ) @TypeOf(writer).Error!void {
1148 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_|
1149 @compileError("invalid format string: '" ++ fmt_str ++ "'");
1164 fn format(data: FormatData, w: *Writer) Writer.Error!void {
11501165 const attribute = data.attribute_index.toAttribute(data.builder);
11511166 switch (attribute) {
11521167 .zeroext,
......@@ -1219,97 +1234,99 @@ pub const Attribute = union(Kind) {
12191234 .no_sanitize_address,
12201235 .no_sanitize_hwaddress,
12211236 .sanitize_address_dyninit,
1222 => try writer.print(" {s}", .{@tagName(attribute)}),
1237 => try w.print(" {s}", .{@tagName(attribute)}),
12231238 .byval,
12241239 .byref,
12251240 .preallocated,
12261241 .inalloca,
12271242 .sret,
12281243 .elementtype,
1229 => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }),
1230 .@"align" => |alignment| try writer.print("{ }", .{alignment}),
1244 => |ty| try w.print(" {s}({f})", .{ @tagName(attribute), ty.fmt(data.builder, .percent) }),
1245 .@"align" => |alignment| try w.print("{f}", .{alignment.fmt(" ")}),
12311246 .dereferenceable,
12321247 .dereferenceable_or_null,
1233 => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }),
1248 => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }),
12341249 .nofpclass => |fpclass| {
12351250 const Int = @typeInfo(FpClass).@"struct".backing_integer.?;
1236 try writer.print(" {s}(", .{@tagName(attribute)});
1251 try w.print(" {s}(", .{@tagName(attribute)});
12371252 var any = false;
12381253 var remaining: Int = @bitCast(fpclass);
12391254 inline for (@typeInfo(FpClass).@"struct".decls) |decl| {
12401255 const pattern: Int = @bitCast(@field(FpClass, decl.name));
12411256 if (remaining & pattern == pattern) {
12421257 if (!any) {
1243 try writer.writeByte(' ');
1258 try w.writeByte(' ');
12441259 any = true;
12451260 }
1246 try writer.writeAll(decl.name);
1261 try w.writeAll(decl.name);
12471262 remaining &= ~pattern;
12481263 }
12491264 }
1250 try writer.writeByte(')');
1265 try w.writeByte(')');
1266 },
1267 .alignstack => |alignment| {
1268 try w.print(" {t}", .{attribute});
1269 const alignment_bytes = alignment.toByteUnits() orelse return;
1270 if (data.flags.pound) {
1271 try w.print("={d}", .{alignment_bytes});
1272 } else {
1273 try w.print("({d})", .{alignment_bytes});
1274 }
12511275 },
1252 .alignstack => |alignment| try writer.print(
1253 if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null)
1254 " {s}={d}"
1255 else
1256 " {s}({d})",
1257 .{ @tagName(attribute), alignment.toByteUnits() orelse return },
1258 ),
12591276 .allockind => |allockind| {
1260 try writer.print(" {s}(\"", .{@tagName(attribute)});
1277 try w.print(" {t}(\"", .{attribute});
12611278 var any = false;
12621279 inline for (@typeInfo(AllocKind).@"struct".fields) |field| {
12631280 if (comptime std.mem.eql(u8, field.name, "_")) continue;
12641281 if (@field(allockind, field.name)) {
12651282 if (!any) {
1266 try writer.writeByte(',');
1283 try w.writeByte(',');
12671284 any = true;
12681285 }
1269 try writer.writeAll(field.name);
1286 try w.writeAll(field.name);
12701287 }
12711288 }
1272 try writer.writeAll("\")");
1289 try w.writeAll("\")");
12731290 },
12741291 .allocsize => |allocsize| {
1275 try writer.print(" {s}({d}", .{ @tagName(attribute), allocsize.elem_size });
1292 try w.print(" {t}({d}", .{ attribute, allocsize.elem_size });
12761293 if (allocsize.num_elems != AllocSize.none)
1277 try writer.print(",{d}", .{allocsize.num_elems});
1278 try writer.writeByte(')');
1294 try w.print(",{d}", .{allocsize.num_elems});
1295 try w.writeByte(')');
12791296 },
12801297 .memory => |memory| {
1281 try writer.print(" {s}(", .{@tagName(attribute)});
1298 try w.print(" {t}(", .{attribute});
12821299 var any = memory.other != .none or
12831300 (memory.argmem == .none and memory.inaccessiblemem == .none);
1284 if (any) try writer.writeAll(@tagName(memory.other));
1301 if (any) try w.writeAll(@tagName(memory.other));
12851302 inline for (.{ "argmem", "inaccessiblemem" }) |kind| {
12861303 if (@field(memory, kind) != memory.other) {
1287 if (any) try writer.writeAll(", ");
1288 try writer.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) });
1304 if (any) try w.writeAll(", ");
1305 try w.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) });
12891306 any = true;
12901307 }
12911308 }
1292 try writer.writeByte(')');
1309 try w.writeByte(')');
12931310 },
12941311 .uwtable => |uwtable| if (uwtable != .none) {
1295 try writer.print(" {s}", .{@tagName(attribute)});
1296 if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)});
1312 try w.print(" {s}", .{@tagName(attribute)});
1313 if (uwtable != UwTable.default) try w.print("({s})", .{@tagName(uwtable)});
12971314 },
1298 .vscale_range => |vscale_range| try writer.print(" {s}({d},{d})", .{
1315 .vscale_range => |vscale_range| try w.print(" {s}({d},{d})", .{
12991316 @tagName(attribute),
13001317 vscale_range.min.toByteUnits().?,
13011318 vscale_range.max.toByteUnits() orelse 0,
13021319 }),
1303 .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) {
1304 try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)});
1320 .string => |string_attr| if (data.flags.quote) {
1321 try w.print(" {f}", .{string_attr.kind.fmtQ(data.builder)});
13051322 if (string_attr.value != .empty)
1306 try writer.print("={\"}", .{string_attr.value.fmt(data.builder)});
1323 try w.print("={f}", .{string_attr.value.fmtQ(data.builder)});
13071324 },
13081325 .none => unreachable,
13091326 }
13101327 }
1311 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
1312 return .{ .data = .{ .attribute_index = self, .builder = builder } };
1328 pub fn fmt(self: Index, builder: *const Builder, mode: FormatData.mode) std.fmt.Formatter(FormatData, format) {
1329 return .{ .data = .{ .attribute_index = self, .builder = builder, .mode = mode } };
13131330 }
13141331
13151332 fn toStorage(self: Index, builder: *const Builder) Storage {
......@@ -1582,20 +1599,18 @@ pub const Attributes = enum(u32) {
15821599 const FormatData = struct {
15831600 attributes: Attributes,
15841601 builder: *const Builder,
1602 flags: Flags = .{},
1603 const Flags = Attribute.Index.FormatData.Flags;
15851604 };
1586 fn format(
1587 data: FormatData,
1588 comptime fmt_str: []const u8,
1589 fmt_opts: std.fmt.FormatOptions,
1590 writer: anytype,
1591 ) @TypeOf(writer).Error!void {
1605 fn format(data: FormatData, w: *Writer) Writer.Error!void {
15921606 for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{
15931607 .attribute_index = attribute_index,
15941608 .builder = data.builder,
1595 }, fmt_str, fmt_opts, writer);
1609 .flags = data.flags,
1610 }, w);
15961611 }
1597 pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) {
1598 return .{ .data = .{ .attributes = self, .builder = builder } };
1612 pub fn fmt(self: Attributes, builder: *const Builder, flags: FormatData.Flags) std.fmt.Formatter(FormatData, format) {
1613 return .{ .data = .{ .attributes = self, .builder = builder, .flags = flags } };
15991614 }
16001615};
16011616
......@@ -1781,24 +1796,14 @@ pub const Linkage = enum(u4) {
17811796 extern_weak = 7,
17821797 external = 0,
17831798
1784 pub fn format(
1785 self: Linkage,
1786 comptime _: []const u8,
1787 _: std.fmt.FormatOptions,
1788 writer: anytype,
1789 ) @TypeOf(writer).Error!void {
1790 if (self != .external) try writer.print(" {s}", .{@tagName(self)});
1799 pub fn format(self: Linkage, w: *Writer) Writer.Error!void {
1800 if (self != .external) try w.print(" {s}", .{@tagName(self)});
17911801 }
17921802
1793 fn formatOptional(
1794 data: ?Linkage,
1795 comptime _: []const u8,
1796 _: std.fmt.FormatOptions,
1797 writer: anytype,
1798 ) @TypeOf(writer).Error!void {
1799 if (data) |linkage| try writer.print(" {s}", .{@tagName(linkage)});
1803 fn formatOptional(data: ?Linkage, w: *Writer) Writer.Error!void {
1804 if (data) |linkage| try w.print(" {s}", .{@tagName(linkage)});
18001805 }
1801 pub fn fmtOptional(self: ?Linkage) std.fmt.Formatter(formatOptional) {
1806 pub fn fmtOptional(self: ?Linkage) std.fmt.Formatter(?Linkage, formatOptional) {
18021807 return .{ .data = self };
18031808 }
18041809};
......@@ -1808,13 +1813,8 @@ pub const Preemption = enum {
18081813 dso_local,
18091814 implicit_dso_local,
18101815
1811 pub fn format(
1812 self: Preemption,
1813 comptime _: []const u8,
1814 _: std.fmt.FormatOptions,
1815 writer: anytype,
1816 ) @TypeOf(writer).Error!void {
1817 if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)});
1816 pub fn format(self: Preemption, w: *Writer) Writer.Error!void {
1817 if (self == .dso_local) try w.print(" {s}", .{@tagName(self)});
18181818 }
18191819};
18201820
......@@ -1831,12 +1831,7 @@ pub const Visibility = enum(u2) {
18311831 };
18321832 }
18331833
1834 pub fn format(
1835 self: Visibility,
1836 comptime _: []const u8,
1837 _: std.fmt.FormatOptions,
1838 writer: anytype,
1839 ) @TypeOf(writer).Error!void {
1834 pub fn format(self: Visibility, writer: *Writer) Writer.Error!void {
18401835 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
18411836 }
18421837};
......@@ -1846,13 +1841,8 @@ pub const DllStorageClass = enum(u2) {
18461841 dllimport = 1,
18471842 dllexport = 2,
18481843
1849 pub fn format(
1850 self: DllStorageClass,
1851 comptime _: []const u8,
1852 _: std.fmt.FormatOptions,
1853 writer: anytype,
1854 ) @TypeOf(writer).Error!void {
1855 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
1844 pub fn format(self: DllStorageClass, w: *Writer) Writer.Error!void {
1845 if (self != .default) try w.print(" {s}", .{@tagName(self)});
18561846 }
18571847};
18581848
......@@ -1863,15 +1853,31 @@ pub const ThreadLocal = enum(u3) {
18631853 initialexec = 3,
18641854 localexec = 4,
18651855
1866 pub fn format(
1867 self: ThreadLocal,
1868 comptime prefix: []const u8,
1869 _: std.fmt.FormatOptions,
1870 writer: anytype,
1871 ) @TypeOf(writer).Error!void {
1872 if (self == .default) return;
1873 try writer.print("{s}thread_local", .{prefix});
1874 if (self != .generaldynamic) try writer.print("({s})", .{@tagName(self)});
1856 pub fn format(tl: ThreadLocal, w: *Writer) Writer.Error!void {
1857 return Prefixed.format(.{ .thread_local = tl, .prefix = "" }, w);
1858 }
1859
1860 pub const Prefixed = struct {
1861 thread_local: ThreadLocal,
1862 prefix: []const u8,
1863
1864 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
1865 switch (p.thread_local) {
1866 .default => return,
1867 .generaldynamic => {
1868 var vecs: [2][]const u8 = .{ p.prefix, "thread_local" };
1869 return w.writeVecAll(&vecs);
1870 },
1871 else => {
1872 var vecs: [4][]const u8 = .{ p.prefix, "thread_local(", @tagName(p.thread_local), ")" };
1873 return w.writeVecAll(&vecs);
1874 },
1875 }
1876 }
1877 };
1878
1879 pub fn fmt(tl: ThreadLocal, prefix: []const u8) Prefixed {
1880 return .{ .thread_local = tl, .prefix = prefix };
18751881 }
18761882};
18771883
......@@ -1882,13 +1888,8 @@ pub const UnnamedAddr = enum(u2) {
18821888 unnamed_addr = 1,
18831889 local_unnamed_addr = 2,
18841890
1885 pub fn format(
1886 self: UnnamedAddr,
1887 comptime _: []const u8,
1888 _: std.fmt.FormatOptions,
1889 writer: anytype,
1890 ) @TypeOf(writer).Error!void {
1891 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
1891 pub fn format(self: UnnamedAddr, w: *Writer) Writer.Error!void {
1892 if (self != .default) try w.print(" {s}", .{@tagName(self)});
18921893 }
18931894};
18941895
......@@ -1981,13 +1982,24 @@ pub const AddrSpace = enum(u24) {
19811982 pub const funcref: AddrSpace = @enumFromInt(20);
19821983 };
19831984
1984 pub fn format(
1985 self: AddrSpace,
1986 comptime prefix: []const u8,
1987 _: std.fmt.FormatOptions,
1988 writer: anytype,
1989 ) @TypeOf(writer).Error!void {
1990 if (self != .default) try writer.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) });
1985 pub fn format(addr_space: AddrSpace, w: *Writer) Writer.Error!void {
1986 return Prefixed.format(.{ .addr_space = addr_space, .prefix = "" }, w);
1987 }
1988
1989 pub const Prefixed = struct {
1990 addr_space: AddrSpace,
1991 prefix: []const u8,
1992
1993 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
1994 switch (p.addr_space) {
1995 .default => return,
1996 else => return w.print("{s}addrspace({d})", .{ p.prefix, p.addr_space }),
1997 }
1998 }
1999 };
2000
2001 pub fn fmt(addr_space: AddrSpace, prefix: []const u8) Prefixed {
2002 return .{ .addr_space = addr_space, .prefix = prefix };
19912003 }
19922004};
19932005
......@@ -1995,15 +2007,8 @@ pub const ExternallyInitialized = enum {
19952007 default,
19962008 externally_initialized,
19972009
1998 pub fn format(
1999 self: ExternallyInitialized,
2000 comptime _: []const u8,
2001 _: std.fmt.FormatOptions,
2002 writer: anytype,
2003 ) @TypeOf(writer).Error!void {
2004 if (self == .default) return;
2005 try writer.writeByte(' ');
2006 try writer.writeAll(@tagName(self));
2010 pub fn format(self: ExternallyInitialized, w: *Writer) Writer.Error!void {
2011 if (self != .default) try w.print(" {s}", .{@tagName(self)});
20072012 }
20082013};
20092014
......@@ -2026,13 +2031,18 @@ pub const Alignment = enum(u6) {
20262031 return if (self == .default) 0 else (@intFromEnum(self) + 1);
20272032 }
20282033
2029 pub fn format(
2030 self: Alignment,
2031 comptime prefix: []const u8,
2032 _: std.fmt.FormatOptions,
2033 writer: anytype,
2034 ) @TypeOf(writer).Error!void {
2035 try writer.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return });
2034 pub const Prefixed = struct {
2035 alignment: Alignment,
2036 prefix: []const u8,
2037
2038 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
2039 const byte_units = p.alignment.toByteUnits() orelse return;
2040 return w.print("{s}align ({d})", .{ p.prefix, byte_units });
2041 }
2042 };
2043
2044 pub fn fmt(alignment: Alignment, prefix: []const u8) Prefixed {
2045 return .{ .alignment = alignment, .prefix = prefix };
20362046 }
20372047};
20382048
......@@ -2105,12 +2115,7 @@ pub const CallConv = enum(u10) {
21052115
21062116 pub const default = CallConv.ccc;
21072117
2108 pub fn format(
2109 self: CallConv,
2110 comptime _: []const u8,
2111 _: std.fmt.FormatOptions,
2112 writer: anytype,
2113 ) @TypeOf(writer).Error!void {
2118 pub fn format(self: CallConv, w: *Writer) Writer.Error!void {
21142119 switch (self) {
21152120 default => {},
21162121 .fastcc,
......@@ -2164,8 +2169,8 @@ pub const CallConv = enum(u10) {
21642169 .aarch64_sme_preservemost_from_x2,
21652170 .m68k_rtdcc,
21662171 .riscv_vectorcallcc,
2167 => try writer.print(" {s}", .{@tagName(self)}),
2168 _ => try writer.print(" cc{d}", .{@intFromEnum(self)}),
2172 => try w.print(" {s}", .{@tagName(self)}),
2173 _ => try w.print(" cc{d}", .{@intFromEnum(self)}),
21692174 }
21702175 }
21712176};
......@@ -2190,31 +2195,25 @@ pub const StrtabString = enum(u32) {
21902195 const FormatData = struct {
21912196 string: StrtabString,
21922197 builder: *const Builder,
2198 quote_behavior: ?QuoteBehavior,
21932199 };
2194 fn format(
2195 data: FormatData,
2196 comptime fmt_str: []const u8,
2197 _: std.fmt.FormatOptions,
2198 writer: anytype,
2199 ) @TypeOf(writer).Error!void {
2200 if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_|
2201 @compileError("invalid format string: '" ++ fmt_str ++ "'");
2200 fn format(data: FormatData, w: *Writer) Writer.Error!void {
22022201 assert(data.string != .none);
22032202 const string_slice = data.string.slice(data.builder) orelse
2204 return writer.print("{d}", .{@intFromEnum(data.string)});
2205 if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_|
2206 return writer.writeAll(string_slice);
2207 try printEscapedString(
2208 string_slice,
2209 if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_|
2210 .always_quote
2211 else
2212 .quote_unless_valid_identifier,
2213 writer,
2214 );
2203 return w.print("{d}", .{@intFromEnum(data.string)});
2204 const quote_behavior = data.quote_behavior orelse return w.writeAll(string_slice);
2205 return printEscapedString(string_slice, quote_behavior, w);
22152206 }
2216 pub fn fmt(self: StrtabString, builder: *const Builder) std.fmt.Formatter(format) {
2217 return .{ .data = .{ .string = self, .builder = builder } };
2207 pub fn fmt(
2208 self: StrtabString,
2209 builder: *const Builder,
2210 quote_behavior: ?QuoteBehavior,
2211 ) std.fmt.Formatter(FormatData, format) {
2212 return .{ .data = .{
2213 .string = self,
2214 .builder = builder,
2215 .quote_behavior = quote_behavior,
2216 } };
22182217 }
22192218
22202219 fn fromIndex(index: ?usize) StrtabString {
......@@ -2264,7 +2263,7 @@ pub fn strtabStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: a
22642263}
22652264
22662265pub fn strtabStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) StrtabString {
2267 self.strtab_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
2266 self.strtab_string_bytes.printAssumeCapacity(fmt_str, fmt_args);
22682267 return self.trailingStrtabStringAssumeCapacity();
22692268}
22702269
......@@ -2383,17 +2382,12 @@ pub const Global = struct {
23832382 global: Index,
23842383 builder: *const Builder,
23852384 };
2386 fn format(
2387 data: FormatData,
2388 comptime _: []const u8,
2389 _: std.fmt.FormatOptions,
2390 writer: anytype,
2391 ) @TypeOf(writer).Error!void {
2392 try writer.print("@{}", .{
2393 data.global.unwrap(data.builder).name(data.builder).fmt(data.builder),
2385 fn format(data: FormatData, w: *Writer) Writer.Error!void {
2386 try w.print("@{f}", .{
2387 data.global.unwrap(data.builder).name(data.builder).fmt(data.builder, null),
23942388 });
23952389 }
2396 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
2390 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(FormatData, format) {
23972391 return .{ .data = .{ .global = self, .builder = builder } };
23982392 }
23992393
......@@ -4833,29 +4827,23 @@ pub const Function = struct {
48334827 instruction: Instruction.Index,
48344828 function: Function.Index,
48354829 builder: *Builder,
4830 flags: FormatFlags,
48364831 };
4837 fn format(
4838 data: FormatData,
4839 comptime fmt_str: []const u8,
4840 _: std.fmt.FormatOptions,
4841 writer: anytype,
4842 ) @TypeOf(writer).Error!void {
4843 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
4844 @compileError("invalid format string: '" ++ fmt_str ++ "'");
4845 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
4832 fn format(data: FormatData, w: *Writer) Writer.Error!void {
4833 if (data.flags.comma) {
48464834 if (data.instruction == .none) return;
4847 try writer.writeByte(',');
4835 try w.writeByte(',');
48484836 }
4849 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
4837 if (data.flags.space) {
48504838 if (data.instruction == .none) return;
4851 try writer.writeByte(' ');
4839 try w.writeByte(' ');
48524840 }
4853 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try writer.print(
4854 "{%} ",
4855 .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder)},
4841 if (data.flags.percent) try w.print(
4842 "{f} ",
4843 .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder, .percent)},
48564844 );
48574845 assert(data.instruction != .none);
4858 try writer.print("%{}", .{
4846 try w.print("%{f}", .{
48594847 data.instruction.name(data.function.ptrConst(data.builder)).fmt(data.builder),
48604848 });
48614849 }
......@@ -4863,8 +4851,14 @@ pub const Function = struct {
48634851 self: Instruction.Index,
48644852 function: Function.Index,
48654853 builder: *Builder,
4866 ) std.fmt.Formatter(format) {
4867 return .{ .data = .{ .instruction = self, .function = function, .builder = builder } };
4854 flags: FormatFlags,
4855 ) std.fmt.Formatter(FormatData, format) {
4856 return .{ .data = .{
4857 .instruction = self,
4858 .function = function,
4859 .builder = builder,
4860 .flags = flags,
4861 } };
48684862 }
48694863 };
48704864
......@@ -6361,10 +6355,10 @@ pub const WipFunction = struct {
63616355
63626356 while (true) {
63636357 gop.value_ptr.* = @enumFromInt(@intFromEnum(gop.value_ptr.*) + 1);
6364 const unique_name = try wip_name.builder.fmt("{r}{s}{r}", .{
6365 name.fmt(wip_name.builder),
6358 const unique_name = try wip_name.builder.fmt("{f}{s}{f}", .{
6359 name.fmtRaw(wip_name.builder),
63666360 sep,
6367 gop.value_ptr.fmt(wip_name.builder),
6361 gop.value_ptr.fmtRaw(wip_name.builder),
63686362 });
63696363 const unique_gop = try wip_name.next_unique_name.getOrPut(unique_name);
63706364 if (!unique_gop.found_existing) {
......@@ -7031,13 +7025,27 @@ pub const MemoryAccessKind = enum(u1) {
70317025 normal,
70327026 @"volatile",
70337027
7034 pub fn format(
7035 self: MemoryAccessKind,
7036 comptime prefix: []const u8,
7037 _: std.fmt.FormatOptions,
7038 writer: anytype,
7039 ) @TypeOf(writer).Error!void {
7040 if (self != .normal) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
7028 pub fn format(memory_access_kind: MemoryAccessKind, w: *Writer) Writer.Error!void {
7029 return Prefixed.format(.{ .memory_access_kind = memory_access_kind, .prefix = "" }, w);
7030 }
7031
7032 pub const Prefixed = struct {
7033 memory_access_kind: MemoryAccessKind,
7034 prefix: []const u8,
7035
7036 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
7037 switch (p.memory_access_kind) {
7038 .normal => return,
7039 .@"volatile" => {
7040 var vecs: [2][]const u8 = .{ p.prefix, "volatile" };
7041 return w.writeVecAll(&vecs);
7042 },
7043 }
7044 }
7045 };
7046
7047 pub fn fmt(memory_access_kind: MemoryAccessKind, prefix: []const u8) Prefixed {
7048 return .{ .memory_access_kind = memory_access_kind, .prefix = prefix };
70417049 }
70427050};
70437051
......@@ -7045,15 +7053,27 @@ pub const SyncScope = enum(u1) {
70457053 singlethread,
70467054 system,
70477055
7048 pub fn format(
7049 self: SyncScope,
7050 comptime prefix: []const u8,
7051 _: std.fmt.FormatOptions,
7052 writer: anytype,
7053 ) @TypeOf(writer).Error!void {
7054 if (self != .system) try writer.print(
7055 \\{s}syncscope("{s}")
7056 , .{ prefix, @tagName(self) });
7056 pub fn format(sync_scope: SyncScope, w: *Writer) Writer.Error!void {
7057 return Prefixed.format(.{ .sync_scope = sync_scope, .prefix = "" }, w);
7058 }
7059
7060 pub const Prefixed = struct {
7061 sync_scope: SyncScope,
7062 prefix: []const u8,
7063
7064 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
7065 switch (p.sync_scope) {
7066 .system => return,
7067 .singlethread => {
7068 var vecs: [2][]const u8 = .{ p.prefix, "syncscope(\"singlethread\")" };
7069 return w.writeVecAll(&vecs);
7070 },
7071 }
7072 }
7073 };
7074
7075 pub fn fmt(sync_scope: SyncScope, prefix: []const u8) Prefixed {
7076 return .{ .sync_scope = sync_scope, .prefix = prefix };
70577077 }
70587078};
70597079
......@@ -7066,13 +7086,27 @@ pub const AtomicOrdering = enum(u3) {
70667086 acq_rel = 5,
70677087 seq_cst = 6,
70687088
7069 pub fn format(
7070 self: AtomicOrdering,
7071 comptime prefix: []const u8,
7072 _: std.fmt.FormatOptions,
7073 writer: anytype,
7074 ) @TypeOf(writer).Error!void {
7075 if (self != .none) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
7089 pub fn format(atomic_ordering: AtomicOrdering, w: *Writer) Writer.Error!void {
7090 return Prefixed.format(.{ .atomic_ordering = atomic_ordering, .prefix = "" }, w);
7091 }
7092
7093 pub const Prefixed = struct {
7094 atomic_ordering: AtomicOrdering,
7095 prefix: []const u8,
7096
7097 pub fn format(p: Prefixed, w: *Writer) Writer.Error!void {
7098 switch (p.atomic_ordering) {
7099 .none => return,
7100 else => {
7101 var vecs: [2][]const u8 = .{ p.prefix, @tagName(p.atomic_ordering) };
7102 return w.writeVecAll(&vecs);
7103 },
7104 }
7105 }
7106 };
7107
7108 pub fn fmt(atomic_ordering: AtomicOrdering, prefix: []const u8) Prefixed {
7109 return .{ .atomic_ordering = atomic_ordering, .prefix = prefix };
70767110 }
70777111};
70787112
......@@ -7486,27 +7520,21 @@ pub const Constant = enum(u32) {
74867520 const FormatData = struct {
74877521 constant: Constant,
74887522 builder: *Builder,
7523 flags: FormatFlags,
74897524 };
7490 fn format(
7491 data: FormatData,
7492 comptime fmt_str: []const u8,
7493 _: std.fmt.FormatOptions,
7494 writer: anytype,
7495 ) @TypeOf(writer).Error!void {
7496 if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
7497 @compileError("invalid format string: '" ++ fmt_str ++ "'");
7498 if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
7525 fn format(data: FormatData, w: *Writer) Writer.Error!void {
7526 if (data.flags.comma) {
74997527 if (data.constant == .no_init) return;
7500 try writer.writeByte(',');
7528 try w.writeByte(',');
75017529 }
7502 if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
7530 if (data.flags.space) {
75037531 if (data.constant == .no_init) return;
7504 try writer.writeByte(' ');
7532 try w.writeByte(' ');
75057533 }
7506 if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null)
7507 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
7534 if (data.flags.percent)
7535 try w.print("{f} ", .{data.constant.typeOf(data.builder).fmt(data.builder, .percent)});
75087536 assert(data.constant != .no_init);
7509 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
7537 if (std.enums.tagName(Constant, data.constant)) |name| return w.writeAll(name);
75107538 switch (data.constant.unwrap()) {
75117539 .constant => |constant| {
75127540 const item = data.builder.constant_items.get(constant);
......@@ -7543,13 +7571,13 @@ pub const Constant = enum(u32) {
75437571 var stack align(@alignOf(ExpectedContents)) =
75447572 std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa);
75457573 const allocator = stack.get();
7546 const str = try bigint.toStringAlloc(allocator, 10, undefined);
7574 const str = bigint.toStringAlloc(allocator, 10, undefined) catch return error.WriteFailed;
75477575 defer allocator.free(str);
7548 try writer.writeAll(str);
7576 try w.writeAll(str);
75497577 },
75507578 .half,
75517579 .bfloat,
7552 => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
7580 => |tag| try w.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
75537581 .half => 'H',
75547582 .bfloat => 'R',
75557583 else => unreachable,
......@@ -7580,7 +7608,7 @@ pub const Constant = enum(u32) {
75807608 ) + 1,
75817609 else => 0,
75827610 };
7583 try writer.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){
7611 try w.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){
75847612 .mantissa = std.math.shl(
75857613 Mantissa64,
75867614 repr.mantissa,
......@@ -7602,13 +7630,13 @@ pub const Constant = enum(u32) {
76027630 },
76037631 .double => {
76047632 const extra = data.builder.constantExtraData(Double, item.data);
7605 try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
7633 try w.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
76067634 },
76077635 .fp128,
76087636 .ppc_fp128,
76097637 => |tag| {
76107638 const extra = data.builder.constantExtraData(Fp128, item.data);
7611 try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
7639 try w.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
76127640 @as(u8, switch (tag) {
76137641 .fp128 => 'L',
76147642 .ppc_fp128 => 'M',
......@@ -7622,7 +7650,7 @@ pub const Constant = enum(u32) {
76227650 },
76237651 .x86_fp80 => {
76247652 const extra = data.builder.constantExtraData(Fp80, item.data);
7625 try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
7653 try w.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
76267654 extra.hi, extra.lo_hi, extra.lo_lo,
76277655 });
76287656 },
......@@ -7631,7 +7659,7 @@ pub const Constant = enum(u32) {
76317659 .zeroinitializer,
76327660 .undef,
76337661 .poison,
7634 => |tag| try writer.writeAll(@tagName(tag)),
7662 => |tag| try w.writeAll(@tagName(tag)),
76357663 .structure,
76367664 .packed_structure,
76377665 .array,
......@@ -7640,7 +7668,7 @@ pub const Constant = enum(u32) {
76407668 var extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
76417669 const len: u32 = @intCast(extra.data.type.aggregateLen(data.builder));
76427670 const vals = extra.trail.next(len, Constant, data.builder);
7643 try writer.writeAll(switch (tag) {
7671 try w.writeAll(switch (tag) {
76447672 .structure => "{ ",
76457673 .packed_structure => "<{ ",
76467674 .array => "[",
......@@ -7648,10 +7676,10 @@ pub const Constant = enum(u32) {
76487676 else => unreachable,
76497677 });
76507678 for (vals, 0..) |val, index| {
7651 if (index > 0) try writer.writeAll(", ");
7652 try writer.print("{%}", .{val.fmt(data.builder)});
7679 if (index > 0) try w.writeAll(", ");
7680 try w.print("{f}", .{val.fmt(data.builder, .{ .percent = true })});
76537681 }
7654 try writer.writeAll(switch (tag) {
7682 try w.writeAll(switch (tag) {
76557683 .structure => " }",
76567684 .packed_structure => " }>",
76577685 .array => "]",
......@@ -7662,30 +7690,30 @@ pub const Constant = enum(u32) {
76627690 .splat => {
76637691 const extra = data.builder.constantExtraData(Splat, item.data);
76647692 const len = extra.type.vectorLen(data.builder);
7665 try writer.writeByte('<');
7693 try w.writeByte('<');
76667694 for (0..len) |index| {
7667 if (index > 0) try writer.writeAll(", ");
7668 try writer.print("{%}", .{extra.value.fmt(data.builder)});
7695 if (index > 0) try w.writeAll(", ");
7696 try w.print("{f}", .{extra.value.fmt(data.builder, .{ .percent = true })});
76697697 }
7670 try writer.writeByte('>');
7698 try w.writeByte('>');
76717699 },
7672 .string => try writer.print("c{\"}", .{
7673 @as(String, @enumFromInt(item.data)).fmt(data.builder),
7700 .string => try w.print("c{f}", .{
7701 @as(String, @enumFromInt(item.data)).fmtQ(data.builder),
76747702 }),
76757703 .blockaddress => |tag| {
76767704 const extra = data.builder.constantExtraData(BlockAddress, item.data);
76777705 const function = extra.function.ptrConst(data.builder);
7678 try writer.print("{s}({}, {})", .{
7706 try w.print("{s}({f}, {f})", .{
76797707 @tagName(tag),
76807708 function.global.fmt(data.builder),
7681 extra.block.toInst(function).fmt(extra.function, data.builder),
7709 extra.block.toInst(function).fmt(extra.function, data.builder, .{}),
76827710 });
76837711 },
76847712 .dso_local_equivalent,
76857713 .no_cfi,
76867714 => |tag| {
76877715 const function: Function.Index = @enumFromInt(item.data);
7688 try writer.print("{s} {}", .{
7716 try w.print("{s} {f}", .{
76897717 @tagName(tag),
76907718 function.ptrConst(data.builder).global.fmt(data.builder),
76917719 });
......@@ -7697,10 +7725,10 @@ pub const Constant = enum(u32) {
76977725 .addrspacecast,
76987726 => |tag| {
76997727 const extra = data.builder.constantExtraData(Cast, item.data);
7700 try writer.print("{s} ({%} to {%})", .{
7728 try w.print("{s} ({f} to {f})", .{
77017729 @tagName(tag),
7702 extra.val.fmt(data.builder),
7703 extra.type.fmt(data.builder),
7730 extra.val.fmt(data.builder, .{ .percent = true }),
7731 extra.type.fmt(data.builder, .percent),
77047732 });
77057733 },
77067734 .getelementptr,
......@@ -7709,13 +7737,13 @@ pub const Constant = enum(u32) {
77097737 var extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
77107738 const indices =
77117739 extra.trail.next(extra.data.info.indices_len, Constant, data.builder);
7712 try writer.print("{s} ({%}, {%}", .{
7740 try w.print("{s} ({f}, {f}", .{
77137741 @tagName(tag),
7714 extra.data.type.fmt(data.builder),
7715 extra.data.base.fmt(data.builder),
7742 extra.data.type.fmt(data.builder, .percent),
7743 extra.data.base.fmt(data.builder, .{ .percent = true }),
77167744 });
7717 for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
7718 try writer.writeByte(')');
7745 for (indices) |index| try w.print(", {f}", .{index.fmt(data.builder, .{ .percent = true })});
7746 try w.writeByte(')');
77197747 },
77207748 .add,
77217749 .@"add nsw",
......@@ -7727,10 +7755,10 @@ pub const Constant = enum(u32) {
77277755 .xor,
77287756 => |tag| {
77297757 const extra = data.builder.constantExtraData(Binary, item.data);
7730 try writer.print("{s} ({%}, {%})", .{
7758 try w.print("{s} ({f}, {f})", .{
77317759 @tagName(tag),
7732 extra.lhs.fmt(data.builder),
7733 extra.rhs.fmt(data.builder),
7760 extra.lhs.fmt(data.builder, .{ .percent = true }),
7761 extra.rhs.fmt(data.builder, .{ .percent = true }),
77347762 });
77357763 },
77367764 .@"asm",
......@@ -7751,19 +7779,23 @@ pub const Constant = enum(u32) {
77517779 .@"asm sideeffect alignstack inteldialect unwind",
77527780 => |tag| {
77537781 const extra = data.builder.constantExtraData(Assembly, item.data);
7754 try writer.print("{s} {\"}, {\"}", .{
7782 try w.print("{s} {f}, {f}", .{
77557783 @tagName(tag),
7756 extra.assembly.fmt(data.builder),
7757 extra.constraints.fmt(data.builder),
7784 extra.assembly.fmtQ(data.builder),
7785 extra.constraints.fmtQ(data.builder),
77587786 });
77597787 },
77607788 }
77617789 },
7762 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
7790 .global => |global| try w.print("{f}", .{global.fmt(data.builder)}),
77637791 }
77647792 }
7765 pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
7766 return .{ .data = .{ .constant = self, .builder = builder } };
7793 pub fn fmt(self: Constant, builder: *Builder, flags: FormatFlags) std.fmt.Formatter(FormatData, format) {
7794 return .{ .data = .{
7795 .constant = self,
7796 .builder = builder,
7797 .flags = flags,
7798 } };
77677799 }
77687800};
77697801
......@@ -7818,28 +7850,26 @@ pub const Value = enum(u32) {
78187850 value: Value,
78197851 function: Function.Index,
78207852 builder: *Builder,
7853 flags: FormatFlags,
78217854 };
7822 fn format(
7823 data: FormatData,
7824 comptime fmt_str: []const u8,
7825 fmt_opts: std.fmt.FormatOptions,
7826 writer: anytype,
7827 ) @TypeOf(writer).Error!void {
7855 fn format(data: FormatData, w: *Writer) Writer.Error!void {
78287856 switch (data.value.unwrap()) {
78297857 .instruction => |instruction| try Function.Instruction.Index.format(.{
78307858 .instruction = instruction,
78317859 .function = data.function,
78327860 .builder = data.builder,
7833 }, fmt_str, fmt_opts, writer),
7861 .flags = data.flags,
7862 }, w),
78347863 .constant => |constant| try Constant.format(.{
78357864 .constant = constant,
78367865 .builder = data.builder,
7837 }, fmt_str, fmt_opts, writer),
7866 .flags = data.flags,
7867 }, w),
78387868 .metadata => unreachable,
78397869 }
78407870 }
7841 pub fn fmt(self: Value, function: Function.Index, builder: *Builder) std.fmt.Formatter(format) {
7842 return .{ .data = .{ .value = self, .function = function, .builder = builder } };
7871 pub fn fmt(self: Value, function: Function.Index, builder: *Builder, flags: FormatFlags) std.fmt.Formatter(FormatData, format) {
7872 return .{ .data = .{ .value = self, .function = function, .builder = builder, .flags = flags } };
78437873 }
78447874};
78457875
......@@ -7869,15 +7899,10 @@ pub const MetadataString = enum(u32) {
78697899 metadata_string: MetadataString,
78707900 builder: *const Builder,
78717901 };
7872 fn format(
7873 data: FormatData,
7874 comptime _: []const u8,
7875 _: std.fmt.FormatOptions,
7876 writer: anytype,
7877 ) @TypeOf(writer).Error!void {
7878 try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, writer);
7902 fn format(data: FormatData, w: *Writer) Writer.Error!void {
7903 try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, w);
78797904 }
7880 fn fmt(self: MetadataString, builder: *const Builder) std.fmt.Formatter(format) {
7905 fn fmt(self: MetadataString, builder: *const Builder) std.fmt.Formatter(FormatData, format) {
78817906 return .{ .data = .{ .metadata_string = self, .builder = builder } };
78827907 }
78837908};
......@@ -8039,29 +8064,24 @@ pub const Metadata = enum(u32) {
80398064 AllCallsDescribed: bool = false,
80408065 Unused: u2 = 0,
80418066
8042 pub fn format(
8043 self: DIFlags,
8044 comptime _: []const u8,
8045 _: std.fmt.FormatOptions,
8046 writer: anytype,
8047 ) @TypeOf(writer).Error!void {
8067 pub fn format(self: DIFlags, w: *Writer) Writer.Error!void {
80488068 var need_pipe = false;
80498069 inline for (@typeInfo(DIFlags).@"struct".fields) |field| {
80508070 switch (@typeInfo(field.type)) {
80518071 .bool => if (@field(self, field.name)) {
8052 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8053 try writer.print("DIFlag{s}", .{field.name});
8072 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
8073 try w.print("DIFlag{s}", .{field.name});
80548074 },
80558075 .@"enum" => if (@field(self, field.name) != .Zero) {
8056 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8057 try writer.print("DIFlag{s}", .{@tagName(@field(self, field.name))});
8076 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
8077 try w.print("DIFlag{s}", .{@tagName(@field(self, field.name))});
80588078 },
80598079 .int => assert(@field(self, field.name) == 0),
80608080 else => @compileError("bad field type: " ++ field.name ++ ": " ++
80618081 @typeName(field.type)),
80628082 }
80638083 }
8064 if (!need_pipe) try writer.writeByte('0');
8084 if (!need_pipe) try w.writeByte('0');
80658085 }
80668086 };
80678087
......@@ -8101,29 +8121,24 @@ pub const Metadata = enum(u32) {
81018121 ObjCDirect: bool = false,
81028122 Unused: u20 = 0,
81038123
8104 pub fn format(
8105 self: DISPFlags,
8106 comptime _: []const u8,
8107 _: std.fmt.FormatOptions,
8108 writer: anytype,
8109 ) @TypeOf(writer).Error!void {
8124 pub fn format(self: DISPFlags, w: *Writer) Writer.Error!void {
81108125 var need_pipe = false;
81118126 inline for (@typeInfo(DISPFlags).@"struct".fields) |field| {
81128127 switch (@typeInfo(field.type)) {
81138128 .bool => if (@field(self, field.name)) {
8114 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8115 try writer.print("DISPFlag{s}", .{field.name});
8129 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
8130 try w.print("DISPFlag{s}", .{field.name});
81168131 },
81178132 .@"enum" => if (@field(self, field.name) != .Zero) {
8118 if (need_pipe) try writer.writeAll(" | ") else need_pipe = true;
8119 try writer.print("DISPFlag{s}", .{@tagName(@field(self, field.name))});
8133 if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
8134 try w.print("DISPFlag{s}", .{@tagName(@field(self, field.name))});
81208135 },
81218136 .int => assert(@field(self, field.name) == 0),
81228137 else => @compileError("bad field type: " ++ field.name ++ ": " ++
81238138 @typeName(field.type)),
81248139 }
81258140 }
8126 if (!need_pipe) try writer.writeByte('0');
8141 if (!need_pipe) try w.writeByte('0');
81278142 }
81288143 };
81298144
......@@ -8298,6 +8313,7 @@ pub const Metadata = enum(u32) {
82988313 formatter: *Formatter,
82998314 prefix: []const u8 = "",
83008315 node: Node,
8316 specialized: ?FormatFlags,
83018317
83028318 const Node = union(enum) {
83038319 none,
......@@ -8323,20 +8339,14 @@ pub const Metadata = enum(u32) {
83238339 };
83248340 };
83258341 };
8326 fn format(
8327 data: FormatData,
8328 comptime fmt_str: []const u8,
8329 fmt_opts: std.fmt.FormatOptions,
8330 writer: anytype,
8331 ) @TypeOf(writer).Error!void {
8342 fn format(data: FormatData, w: *Writer) Writer.Error!void {
83328343 if (data.node == .none) return;
83338344
8334 const is_specialized = fmt_str.len > 0 and fmt_str[0] == 'S';
8335 const recurse_fmt_str = if (is_specialized) fmt_str[1..] else fmt_str;
8345 const is_specialized = data.specialized != null;
83368346
8337 if (data.formatter.need_comma) try writer.writeAll(", ");
8347 if (data.formatter.need_comma) try w.writeAll(", ");
83388348 defer data.formatter.need_comma = true;
8339 try writer.writeAll(data.prefix);
8349 try w.writeAll(data.prefix);
83408350
83418351 const builder = data.formatter.builder;
83428352 switch (data.node) {
......@@ -8351,54 +8361,57 @@ pub const Metadata = enum(u32) {
83518361 .expression => {
83528362 var extra = builder.metadataExtraDataTrail(Expression, item.data);
83538363 const elements = extra.trail.next(extra.data.elements_len, u32, builder);
8354 try writer.writeAll("!DIExpression(");
8364 try w.writeAll("!DIExpression(");
83558365 for (elements) |element| try format(.{
83568366 .formatter = data.formatter,
83578367 .node = .{ .u64 = element },
8358 }, "%", fmt_opts, writer);
8359 try writer.writeByte(')');
8368 .specialized = .{ .percent = true },
8369 }, w);
8370 try w.writeByte(')');
83608371 },
83618372 .constant => try Constant.format(.{
83628373 .constant = @enumFromInt(item.data),
83638374 .builder = builder,
8364 }, recurse_fmt_str, fmt_opts, writer),
8375 .flags = data.specialized orelse .{},
8376 }, w),
83658377 else => unreachable,
83668378 }
83678379 },
8368 .index => |node| try writer.print("!{d}", .{node}),
8380 .index => |node| try w.print("!{d}", .{node}),
83698381 inline .local_value, .local_metadata => |node, tag| try Value.format(.{
83708382 .value = node.value,
83718383 .function = node.function,
83728384 .builder = builder,
8373 }, switch (tag) {
8374 .local_value => recurse_fmt_str,
8375 .local_metadata => "%",
8376 else => unreachable,
8377 }, fmt_opts, writer),
8385 .flags = switch (tag) {
8386 .local_value => data.specialized orelse .{},
8387 .local_metadata => .{ .percent = true },
8388 else => unreachable,
8389 },
8390 }, w),
83788391 inline .local_inline, .local_index => |node, tag| {
8379 if (comptime std.mem.eql(u8, recurse_fmt_str, "%"))
8380 try writer.print("{%} ", .{Type.metadata.fmt(builder)});
8392 if (data.specialized) |flags| {
8393 if (flags.onlyPercent()) {
8394 try w.print("{f} ", .{Type.metadata.fmt(builder, .percent)});
8395 }
8396 }
83818397 try format(.{
83828398 .formatter = data.formatter,
83838399 .node = @unionInit(FormatData.Node, @tagName(tag)["local_".len..], node),
8384 }, "%", fmt_opts, writer);
8400 .specialized = .{ .percent = true },
8401 }, w);
83858402 },
8386 .string => |node| try writer.print((if (is_specialized) "" else "!") ++ "{}", .{
8387 node.fmt(builder),
8403 .string => |node| try w.print("{s}{f}", .{
8404 @as([]const u8, if (is_specialized) "" else "!"), node.fmt(builder),
83888405 }),
8389 inline .bool,
8390 .u32,
8391 .u64,
8392 .di_flags,
8393 .sp_flags,
8394 => |node| try writer.print("{}", .{node}),
8395 .raw => |node| try writer.writeAll(node),
8406 inline .bool, .u32, .u64 => |node| try w.print("{}", .{node}),
8407 inline .di_flags, .sp_flags => |node| try w.print("{f}", .{node}),
8408 .raw => |node| try w.writeAll(node),
83968409 }
83978410 }
8398 inline fn fmt(formatter: *Formatter, prefix: []const u8, node: anytype) switch (@TypeOf(node)) {
8411 inline fn fmt(formatter: *Formatter, prefix: []const u8, node: anytype, special: ?FormatFlags) switch (@TypeOf(node)) {
83998412 Metadata => Allocator.Error,
84008413 else => error{},
8401 }!std.fmt.Formatter(format) {
8414 }!std.fmt.Formatter(FormatData, format) {
84028415 const Node = @TypeOf(node);
84038416 const MaybeNode = switch (@typeInfo(Node)) {
84048417 .optional => Node,
......@@ -8435,6 +8448,7 @@ pub const Metadata = enum(u32) {
84358448 .optional, .null => .none,
84368449 else => unreachable,
84378450 },
8451 .specialized = special,
84388452 } };
84398453 }
84408454 inline fn fmtLocal(
......@@ -8442,7 +8456,7 @@ pub const Metadata = enum(u32) {
84428456 prefix: []const u8,
84438457 value: Value,
84448458 function: Function.Index,
8445 ) Allocator.Error!std.fmt.Formatter(format) {
8459 ) Allocator.Error!std.fmt.Formatter(FormatData, format) {
84468460 return .{ .data = .{
84478461 .formatter = formatter,
84488462 .prefix = prefix,
......@@ -8467,6 +8481,7 @@ pub const Metadata = enum(u32) {
84678481 };
84688482 },
84698483 },
8484 .specialized = null,
84708485 } };
84718486 }
84728487 fn refUnwrapped(formatter: *Formatter, node: Metadata) Allocator.Error!FormatData.Node {
......@@ -8506,7 +8521,7 @@ pub const Metadata = enum(u32) {
85068521 DIGlobalVariableExpression,
85078522 },
85088523 nodes: anytype,
8509 writer: anytype,
8524 w: *Writer,
85108525 ) !void {
85118526 comptime var fmt_str: []const u8 = "";
85128527 const names = comptime std.meta.fieldNames(@TypeOf(nodes));
......@@ -8523,10 +8538,10 @@ pub const Metadata = enum(u32) {
85238538 }
85248539 fmt_str = fmt_str ++ "(";
85258540 inline for (fields[2..], names) |*field, name| {
8526 fmt_str = fmt_str ++ "{[" ++ name ++ "]S}";
8541 fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";
85278542 field.* = .{
85288543 .name = name,
8529 .type = std.fmt.Formatter(format),
8544 .type = std.fmt.Formatter(FormatData, format),
85308545 .default_value_ptr = null,
85318546 .is_comptime = false,
85328547 .alignment = 0,
......@@ -8545,8 +8560,9 @@ pub const Metadata = enum(u32) {
85458560 inline for (names) |name| @field(fmt_args, name) = try formatter.fmt(
85468561 name ++ ": ",
85478562 @field(nodes, name),
8563 null,
85488564 );
8549 try writer.print(fmt_str, fmt_args);
8565 try w.print(fmt_str, fmt_args);
85508566 }
85518567 };
85528568};
......@@ -8636,7 +8652,7 @@ pub fn init(options: Options) Allocator.Error!Builder {
86368652 inline for (.{ 0, 4 }) |addr_space_index| {
86378653 const addr_space: AddrSpace = @enumFromInt(addr_space_index);
86388654 assert(self.ptrTypeAssumeCapacity(addr_space) ==
8639 @field(Type, std.fmt.comptimePrint("ptr{ }", .{addr_space})));
8655 @field(Type, std.fmt.comptimePrint("ptr{f}", .{addr_space.fmt(" ")})));
86408656 }
86418657 }
86428658
......@@ -8759,16 +8775,8 @@ pub fn deinit(self: *Builder) void {
87598775 self.* = undefined;
87608776}
87618777
8762pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
8763 self.module_asm.clearRetainingCapacity();
8764 return self.appendModuleAsm();
8765}
8766
8767pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer {
8768 return self.module_asm.writer(self.gpa);
8769}
8770
8771pub fn finishModuleAsm(self: *Builder) Allocator.Error!void {
8778pub fn finishModuleAsm(self: *Builder, aw: *Writer.Allocating) Allocator.Error!void {
8779 self.module_asm = aw.toArrayList();
87728780 if (self.module_asm.getLastOrNull()) |last| if (last != '\n')
87738781 try self.module_asm.append(self.gpa, '\n');
87748782}
......@@ -8804,7 +8812,7 @@ pub fn fmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allo
88048812}
88058813
88068814pub fn fmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) String {
8807 self.string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
8815 self.string_bytes.printAssumeCapacity(fmt_str, fmt_args);
88088816 return self.trailingStringAssumeCapacity();
88098817}
88108818
......@@ -9076,9 +9084,13 @@ pub fn getIntrinsic(
90769084 const allocator = stack.get();
90779085
90789086 const name = name: {
9079 const writer = self.strtab_string_bytes.writer(self.gpa);
9080 try writer.print("llvm.{s}", .{@tagName(id)});
9081 for (overload) |ty| try writer.print(".{m}", .{ty.fmt(self)});
9087 {
9088 var aw: Writer.Allocating = .fromArrayList(self.gpa, &self.strtab_string_bytes);
9089 const w = &aw.writer;
9090 defer self.strtab_string_bytes = aw.toArrayList();
9091 w.print("llvm.{s}", .{@tagName(id)}) catch return error.OutOfMemory;
9092 for (overload) |ty| w.print(".{f}", .{ty.fmt(self, .m)}) catch return error.OutOfMemory;
9093 }
90829094 break :name try self.trailingStrtabString();
90839095 };
90849096 if (self.getGlobal(name)) |global| return global.ptrConst(self).kind.function;
......@@ -9492,139 +9504,105 @@ pub fn asmValue(
94929504 return (try self.asmConst(ty, info, assembly, constraints)).toValue();
94939505}
94949506
9495pub fn dump(self: *Builder) void {
9496 self.print(std.io.getStdErr().writer()) catch {};
9507pub fn dump(b: *Builder) void {
9508 var buffer: [4000]u8 = undefined;
9509 const stderr: std.fs.File = .stderr();
9510 b.printToFile(stderr, &buffer) catch {};
94979511}
94989512
9499pub fn printToFile(self: *Builder, path: []const u8) Allocator.Error!bool {
9500 var file = std.fs.cwd().createFile(path, .{}) catch |err| {
9501 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
9502 return false;
9503 };
9513pub fn printToFilePath(b: *Builder, dir: std.fs.Dir, path: []const u8) !void {
9514 var buffer: [4000]u8 = undefined;
9515 const file = try dir.createFile(path, .{});
95049516 defer file.close();
9505 self.print(file.writer()) catch |err| {
9506 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
9507 return false;
9508 };
9509 return true;
9517 try b.printToFile(file, &buffer);
95109518}
95119519
9512pub fn print(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {
9513 var bw = std.io.bufferedWriter(writer);
9514 try self.printUnbuffered(bw.writer());
9515 try bw.flush();
9520pub fn printToFile(b: *Builder, file: std.fs.File, buffer: []u8) !void {
9521 var fw = file.writer(buffer);
9522 try print(b, &fw.interface);
9523 try fw.interface.flush();
95169524}
95179525
9518fn WriterWithErrors(comptime BackingWriter: type, comptime ExtraErrors: type) type {
9519 return struct {
9520 backing_writer: BackingWriter,
9521
9522 pub const Error = BackingWriter.Error || ExtraErrors;
9523 pub const Writer = std.io.Writer(*const Self, Error, write);
9524
9525 const Self = @This();
9526
9527 pub fn writer(self: *const Self) Writer {
9528 return .{ .context = self };
9529 }
9530
9531 pub fn write(self: *const Self, bytes: []const u8) Error!usize {
9532 return self.backing_writer.write(bytes);
9533 }
9534 };
9535}
9536fn writerWithErrors(
9537 backing_writer: anytype,
9538 comptime ExtraErrors: type,
9539) WriterWithErrors(@TypeOf(backing_writer), ExtraErrors) {
9540 return .{ .backing_writer = backing_writer };
9541}
9542
9543pub fn printUnbuffered(
9544 self: *Builder,
9545 backing_writer: anytype,
9546) (@TypeOf(backing_writer).Error || Allocator.Error)!void {
9547 const writer_with_errors = writerWithErrors(backing_writer, Allocator.Error);
9548 const writer = writer_with_errors.writer();
9549
9526pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void {
95509527 var need_newline = false;
95519528 var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined };
95529529 defer metadata_formatter.map.deinit(self.gpa);
95539530
95549531 if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) {
9555 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9556 if (self.source_filename != .none) try writer.print(
9532 if (need_newline) try w.writeByte('\n') else need_newline = true;
9533 if (self.source_filename != .none) try w.print(
95579534 \\; ModuleID = '{s}'
9558 \\source_filename = {"}
9535 \\source_filename = {f}
95599536 \\
9560 , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) });
9561 if (self.data_layout != .none) try writer.print(
9562 \\target datalayout = {"}
9537 , .{ self.source_filename.slice(self).?, self.source_filename.fmtQ(self) });
9538 if (self.data_layout != .none) try w.print(
9539 \\target datalayout = {f}
95639540 \\
9564 , .{self.data_layout.fmt(self)});
9565 if (self.target_triple != .none) try writer.print(
9566 \\target triple = {"}
9541 , .{self.data_layout.fmtQ(self)});
9542 if (self.target_triple != .none) try w.print(
9543 \\target triple = {f}
95679544 \\
9568 , .{self.target_triple.fmt(self)});
9545 , .{self.target_triple.fmtQ(self)});
95699546 }
95709547
95719548 if (self.module_asm.items.len > 0) {
9572 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9549 if (need_newline) try w.writeByte('\n') else need_newline = true;
95739550 var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n');
95749551 while (line_it.next()) |line| {
9575 try writer.writeAll("module asm ");
9576 try printEscapedString(line, .always_quote, writer);
9577 try writer.writeByte('\n');
9552 try w.writeAll("module asm ");
9553 try printEscapedString(line, .always_quote, w);
9554 try w.writeByte('\n');
95789555 }
95799556 }
95809557
95819558 if (self.types.count() > 0) {
9582 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9583 for (self.types.keys(), self.types.values()) |id, ty| try writer.print(
9584 \\%{} = type {}
9559 if (need_newline) try w.writeByte('\n') else need_newline = true;
9560 for (self.types.keys(), self.types.values()) |id, ty| try w.print(
9561 \\%{f} = type {f}
95859562 \\
9586 , .{ id.fmt(self), ty.fmt(self) });
9563 , .{ id.fmt(self), ty.fmt(self, .default) });
95879564 }
95889565
95899566 if (self.variables.items.len > 0) {
9590 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9567 if (need_newline) try w.writeByte('\n') else need_newline = true;
95919568 for (self.variables.items) |variable| {
95929569 if (variable.global.getReplacement(self) != .none) continue;
95939570 const global = variable.global.ptrConst(self);
95949571 metadata_formatter.need_comma = true;
95959572 defer metadata_formatter.need_comma = undefined;
9596 try writer.print(
9597 \\{} ={}{}{}{}{ }{}{ }{} {s} {%}{ }{, }{}
9573 try w.print(
9574 \\{f} ={f}{f}{f}{f}{f}{f}{f}{f} {s} {f}{f}{f}{f}
95989575 \\
95999576 , .{
96009577 variable.global.fmt(self),
9601 Linkage.fmtOptional(if (global.linkage == .external and
9602 variable.init != .no_init) null else global.linkage),
9578 Linkage.fmtOptional(
9579 if (global.linkage == .external and variable.init != .no_init) null else global.linkage,
9580 ),
96039581 global.preemption,
96049582 global.visibility,
96059583 global.dll_storage_class,
9606 variable.thread_local,
9584 variable.thread_local.fmt(" "),
96079585 global.unnamed_addr,
9608 global.addr_space,
9586 global.addr_space.fmt(" "),
96099587 global.externally_initialized,
96109588 @tagName(variable.mutability),
9611 global.type.fmt(self),
9612 variable.init.fmt(self),
9613 variable.alignment,
9614 try metadata_formatter.fmt("!dbg ", global.dbg),
9589 global.type.fmt(self, .percent),
9590 variable.init.fmt(self, .{ .space = true }),
9591 variable.alignment.fmt(", "),
9592 try metadata_formatter.fmt("!dbg ", global.dbg, null),
96159593 });
96169594 }
96179595 }
96189596
96199597 if (self.aliases.items.len > 0) {
9620 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9598 if (need_newline) try w.writeByte('\n') else need_newline = true;
96219599 for (self.aliases.items) |alias| {
96229600 if (alias.global.getReplacement(self) != .none) continue;
96239601 const global = alias.global.ptrConst(self);
96249602 metadata_formatter.need_comma = true;
96259603 defer metadata_formatter.need_comma = undefined;
9626 try writer.print(
9627 \\{} ={}{}{}{}{ }{} alias {%}, {%}{}
9604 try w.print(
9605 \\{f} ={f}{f}{f}{f}{f}{f} alias {f}, {f}{f}
96289606 \\
96299607 , .{
96309608 alias.global.fmt(self),
......@@ -9632,11 +9610,11 @@ pub fn printUnbuffered(
96329610 global.preemption,
96339611 global.visibility,
96349612 global.dll_storage_class,
9635 alias.thread_local,
9613 alias.thread_local.fmt(" "),
96369614 global.unnamed_addr,
9637 global.type.fmt(self),
9638 alias.aliasee.fmt(self),
9639 try metadata_formatter.fmt("!dbg ", global.dbg),
9615 global.type.fmt(self, .percent),
9616 alias.aliasee.fmt(self, .{ .percent = true }),
9617 try metadata_formatter.fmt("!dbg ", global.dbg, null),
96409618 });
96419619 }
96429620 }
......@@ -9646,17 +9624,17 @@ pub fn printUnbuffered(
96469624
96479625 for (0.., self.functions.items) |function_i, function| {
96489626 if (function.global.getReplacement(self) != .none) continue;
9649 if (need_newline) try writer.writeByte('\n') else need_newline = true;
9627 if (need_newline) try w.writeByte('\n') else need_newline = true;
96509628 const function_index: Function.Index = @enumFromInt(function_i);
96519629 const global = function.global.ptrConst(self);
96529630 const params_len = global.type.functionParameters(self).len;
96539631 const function_attributes = function.attributes.func(self);
9654 if (function_attributes != .none) try writer.print(
9655 \\; Function Attrs:{}
9632 if (function_attributes != .none) try w.print(
9633 \\; Function Attrs:{f}
96569634 \\
9657 , .{function_attributes.fmt(self)});
9658 try writer.print(
9659 \\{s}{}{}{}{}{}{"} {%} {}(
9635 , .{function_attributes.fmt(self, .{})});
9636 try w.print(
9637 \\{s}{f}{f}{f}{f}{f}{f} {f} {f}(
96609638 , .{
96619639 if (function.instructions.len > 0) "define" else "declare",
96629640 global.linkage,
......@@ -9664,45 +9642,45 @@ pub fn printUnbuffered(
96649642 global.visibility,
96659643 global.dll_storage_class,
96669644 function.call_conv,
9667 function.attributes.ret(self).fmt(self),
9668 global.type.functionReturn(self).fmt(self),
9645 function.attributes.ret(self).fmt(self, .{}),
9646 global.type.functionReturn(self).fmt(self, .percent),
96699647 function.global.fmt(self),
96709648 });
96719649 for (0..params_len) |arg| {
9672 if (arg > 0) try writer.writeAll(", ");
9673 try writer.print(
9674 \\{%}{"}
9650 if (arg > 0) try w.writeAll(", ");
9651 try w.print(
9652 \\{f}{f}
96759653 , .{
9676 global.type.functionParameters(self)[arg].fmt(self),
9677 function.attributes.param(arg, self).fmt(self),
9654 global.type.functionParameters(self)[arg].fmt(self, .percent),
9655 function.attributes.param(arg, self).fmt(self, .{}),
96789656 });
96799657 if (function.instructions.len > 0)
9680 try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)})
9658 try w.print(" {f}", .{function.arg(@intCast(arg)).fmt(function_index, self, .{})})
96819659 else
9682 try writer.print(" %{d}", .{arg});
9660 try w.print(" %{d}", .{arg});
96839661 }
96849662 switch (global.type.functionKind(self)) {
96859663 .normal => {},
96869664 .vararg => {
9687 if (params_len > 0) try writer.writeAll(", ");
9688 try writer.writeAll("...");
9665 if (params_len > 0) try w.writeAll(", ");
9666 try w.writeAll("...");
96899667 },
96909668 }
9691 try writer.print("){}{ }", .{ global.unnamed_addr, global.addr_space });
9692 if (function_attributes != .none) try writer.print(" #{d}", .{
9669 try w.print("){f}{f}", .{ global.unnamed_addr, global.addr_space.fmt(" ") });
9670 if (function_attributes != .none) try w.print(" #{d}", .{
96939671 (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index,
96949672 });
96959673 {
96969674 metadata_formatter.need_comma = false;
96979675 defer metadata_formatter.need_comma = undefined;
9698 try writer.print("{ }{}", .{
9699 function.alignment,
9700 try metadata_formatter.fmt(" !dbg ", global.dbg),
9676 try w.print("{f}{f}", .{
9677 function.alignment.fmt(" "),
9678 try metadata_formatter.fmt(" !dbg ", global.dbg, null),
97019679 });
97029680 }
97039681 if (function.instructions.len > 0) {
97049682 var block_incoming_len: u32 = undefined;
9705 try writer.writeAll(" {\n");
9683 try w.writeAll(" {\n");
97069684 var maybe_dbg_index: ?u32 = null;
97079685 for (params_len..function.instructions.len) |instruction_i| {
97089686 const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i);
......@@ -9800,11 +9778,11 @@ pub fn printUnbuffered(
98009778 .xor,
98019779 => |tag| {
98029780 const extra = function.extraData(Function.Instruction.Binary, instruction.data);
9803 try writer.print(" %{} = {s} {%}, {}", .{
9781 try w.print(" %{f} = {s} {f}, {f}", .{
98049782 instruction_index.name(&function).fmt(self),
98059783 @tagName(tag),
9806 extra.lhs.fmt(function_index, self),
9807 extra.rhs.fmt(function_index, self),
9784 extra.lhs.fmt(function_index, self, .{ .percent = true }),
9785 extra.rhs.fmt(function_index, self, .{ .percent = true }),
98089786 });
98099787 },
98109788 .addrspacecast,
......@@ -9822,73 +9800,76 @@ pub fn printUnbuffered(
98229800 .zext,
98239801 => |tag| {
98249802 const extra = function.extraData(Function.Instruction.Cast, instruction.data);
9825 try writer.print(" %{} = {s} {%} to {%}", .{
9803 try w.print(" %{f} = {s} {f} to {f}", .{
98269804 instruction_index.name(&function).fmt(self),
98279805 @tagName(tag),
9828 extra.val.fmt(function_index, self),
9829 extra.type.fmt(self),
9806 extra.val.fmt(function_index, self, .{ .percent = true }),
9807 extra.type.fmt(self, .percent),
98309808 });
98319809 },
98329810 .alloca,
98339811 .@"alloca inalloca",
98349812 => |tag| {
98359813 const extra = function.extraData(Function.Instruction.Alloca, instruction.data);
9836 try writer.print(" %{} = {s} {%}{,%}{, }{, }", .{
9814 try w.print(" %{f} = {s} {f}{f}{f}{f}", .{
98379815 instruction_index.name(&function).fmt(self),
98389816 @tagName(tag),
9839 extra.type.fmt(self),
9817 extra.type.fmt(self, .percent),
98409818 Value.fmt(switch (extra.len) {
98419819 .@"1" => .none,
98429820 else => extra.len,
9843 }, function_index, self),
9844 extra.info.alignment,
9845 extra.info.addr_space,
9821 }, function_index, self, .{
9822 .comma = true,
9823 .percent = true,
9824 }),
9825 extra.info.alignment.fmt(", "),
9826 extra.info.addr_space.fmt(", "),
98469827 });
98479828 },
98489829 .arg => unreachable,
98499830 .atomicrmw => |tag| {
98509831 const extra =
98519832 function.extraData(Function.Instruction.AtomicRmw, instruction.data);
9852 try writer.print(" %{} = {s}{ } {s} {%}, {%}{ }{ }{, }", .{
9833 try w.print(" %{f} = {t}{f} {t} {f}, {f}{f}{f}{f}", .{
98539834 instruction_index.name(&function).fmt(self),
9854 @tagName(tag),
9855 extra.info.access_kind,
9856 @tagName(extra.info.atomic_rmw_operation),
9857 extra.ptr.fmt(function_index, self),
9858 extra.val.fmt(function_index, self),
9859 extra.info.sync_scope,
9860 extra.info.success_ordering,
9861 extra.info.alignment,
9835 tag,
9836 extra.info.access_kind.fmt(" "),
9837 extra.info.atomic_rmw_operation,
9838 extra.ptr.fmt(function_index, self, .{ .percent = true }),
9839 extra.val.fmt(function_index, self, .{ .percent = true }),
9840 extra.info.sync_scope.fmt(" "),
9841 extra.info.success_ordering.fmt(" "),
9842 extra.info.alignment.fmt(", "),
98629843 });
98639844 },
98649845 .block => {
98659846 block_incoming_len = instruction.data;
98669847 const name = instruction_index.name(&function);
98679848 if (@intFromEnum(instruction_index) > params_len)
9868 try writer.writeByte('\n');
9869 try writer.print("{}:\n", .{name.fmt(self)});
9849 try w.writeByte('\n');
9850 try w.print("{f}:\n", .{name.fmt(self)});
98709851 continue;
98719852 },
98729853 .br => |tag| {
98739854 const target: Function.Block.Index = @enumFromInt(instruction.data);
9874 try writer.print(" {s} {%}", .{
9875 @tagName(tag), target.toInst(&function).fmt(function_index, self),
9855 try w.print(" {s} {f}", .{
9856 @tagName(tag), target.toInst(&function).fmt(function_index, self, .{ .percent = true }),
98769857 });
98779858 },
98789859 .br_cond => {
98799860 const extra = function.extraData(Function.Instruction.BrCond, instruction.data);
9880 try writer.print(" br {%}, {%}, {%}", .{
9881 extra.cond.fmt(function_index, self),
9882 extra.then.toInst(&function).fmt(function_index, self),
9883 extra.@"else".toInst(&function).fmt(function_index, self),
9861 try w.print(" br {f}, {f}, {f}", .{
9862 extra.cond.fmt(function_index, self, .{ .percent = true }),
9863 extra.then.toInst(&function).fmt(function_index, self, .{ .percent = true }),
9864 extra.@"else".toInst(&function).fmt(function_index, self, .{ .percent = true }),
98849865 });
98859866 metadata_formatter.need_comma = true;
98869867 defer metadata_formatter.need_comma = undefined;
98879868 switch (extra.weights) {
98889869 .none => {},
9889 .unpredictable => try writer.writeAll("!unpredictable !{}"),
9890 _ => try writer.print("{}", .{
9891 try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.weights)))),
9870 .unpredictable => try w.writeAll("!unpredictable !{}"),
9871 _ => try w.print("{f}", .{
9872 try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.weights))), null),
98929873 }),
98939874 }
98949875 },
......@@ -9904,42 +9885,42 @@ pub fn printUnbuffered(
99049885 var extra =
99059886 function.extraDataTrail(Function.Instruction.Call, instruction.data);
99069887 const args = extra.trail.next(extra.data.args_len, Value, &function);
9907 try writer.writeAll(" ");
9888 try w.writeAll(" ");
99089889 const ret_ty = extra.data.ty.functionReturn(self);
99099890 switch (ret_ty) {
99109891 .void => {},
9911 else => try writer.print("%{} = ", .{
9892 else => try w.print("%{f} = ", .{
99129893 instruction_index.name(&function).fmt(self),
99139894 }),
99149895 .none => unreachable,
99159896 }
9916 try writer.print("{s}{}{}{} {%} {}(", .{
9917 @tagName(tag),
9897 try w.print("{t}{f}{f}{f} {f} {f}(", .{
9898 tag,
99189899 extra.data.info.call_conv,
9919 extra.data.attributes.ret(self).fmt(self),
9900 extra.data.attributes.ret(self).fmt(self, .{}),
99209901 extra.data.callee.typeOf(function_index, self).pointerAddrSpace(self),
99219902 switch (extra.data.ty.functionKind(self)) {
99229903 .normal => ret_ty,
99239904 .vararg => extra.data.ty,
9924 }.fmt(self),
9925 extra.data.callee.fmt(function_index, self),
9905 }.fmt(self, .percent),
9906 extra.data.callee.fmt(function_index, self, .{}),
99269907 });
99279908 for (0.., args) |arg_index, arg| {
9928 if (arg_index > 0) try writer.writeAll(", ");
9909 if (arg_index > 0) try w.writeAll(", ");
99299910 metadata_formatter.need_comma = false;
99309911 defer metadata_formatter.need_comma = undefined;
9931 try writer.print("{%}{}{}", .{
9932 arg.typeOf(function_index, self).fmt(self),
9933 extra.data.attributes.param(arg_index, self).fmt(self),
9912 try w.print("{f}{f}{f}", .{
9913 arg.typeOf(function_index, self).fmt(self, .percent),
9914 extra.data.attributes.param(arg_index, self).fmt(self, .{}),
99349915 try metadata_formatter.fmtLocal(" ", arg, function_index),
99359916 });
99369917 }
9937 try writer.writeByte(')');
9918 try w.writeByte(')');
99389919 if (extra.data.info.has_op_bundle_cold) {
9939 try writer.writeAll(" [ \"cold\"() ]");
9920 try w.writeAll(" [ \"cold\"() ]");
99409921 }
99419922 const call_function_attributes = extra.data.attributes.func(self);
9942 if (call_function_attributes != .none) try writer.print(" #{d}", .{
9923 if (call_function_attributes != .none) try w.print(" #{d}", .{
99439924 (try attribute_groups.getOrPutValue(
99449925 self.gpa,
99459926 call_function_attributes,
......@@ -9952,27 +9933,27 @@ pub fn printUnbuffered(
99529933 => |tag| {
99539934 const extra =
99549935 function.extraData(Function.Instruction.CmpXchg, instruction.data);
9955 try writer.print(" %{} = {s}{ } {%}, {%}, {%}{ }{ }{ }{, }", .{
9936 try w.print(" %{f} = {t}{f} {f}, {f}, {f}{f}{f}{f}{f}", .{
99569937 instruction_index.name(&function).fmt(self),
9957 @tagName(tag),
9958 extra.info.access_kind,
9959 extra.ptr.fmt(function_index, self),
9960 extra.cmp.fmt(function_index, self),
9961 extra.new.fmt(function_index, self),
9962 extra.info.sync_scope,
9963 extra.info.success_ordering,
9964 extra.info.failure_ordering,
9965 extra.info.alignment,
9938 tag,
9939 extra.info.access_kind.fmt(" "),
9940 extra.ptr.fmt(function_index, self, .{ .percent = true }),
9941 extra.cmp.fmt(function_index, self, .{ .percent = true }),
9942 extra.new.fmt(function_index, self, .{ .percent = true }),
9943 extra.info.sync_scope.fmt(" "),
9944 extra.info.success_ordering.fmt(" "),
9945 extra.info.failure_ordering.fmt(" "),
9946 extra.info.alignment.fmt(", "),
99669947 });
99679948 },
99689949 .extractelement => |tag| {
99699950 const extra =
99709951 function.extraData(Function.Instruction.ExtractElement, instruction.data);
9971 try writer.print(" %{} = {s} {%}, {%}", .{
9952 try w.print(" %{f} = {s} {f}, {f}", .{
99729953 instruction_index.name(&function).fmt(self),
99739954 @tagName(tag),
9974 extra.val.fmt(function_index, self),
9975 extra.index.fmt(function_index, self),
9955 extra.val.fmt(function_index, self, .{ .percent = true }),
9956 extra.index.fmt(function_index, self, .{ .percent = true }),
99769957 });
99779958 },
99789959 .extractvalue => |tag| {
......@@ -9981,29 +9962,29 @@ pub fn printUnbuffered(
99819962 instruction.data,
99829963 );
99839964 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
9984 try writer.print(" %{} = {s} {%}", .{
9965 try w.print(" %{f} = {s} {f}", .{
99859966 instruction_index.name(&function).fmt(self),
99869967 @tagName(tag),
9987 extra.data.val.fmt(function_index, self),
9968 extra.data.val.fmt(function_index, self, .{ .percent = true }),
99889969 });
9989 for (indices) |index| try writer.print(", {d}", .{index});
9970 for (indices) |index| try w.print(", {d}", .{index});
99909971 },
99919972 .fence => |tag| {
99929973 const info: MemoryAccessInfo = @bitCast(instruction.data);
9993 try writer.print(" {s}{ }{ }", .{
9994 @tagName(tag),
9995 info.sync_scope,
9996 info.success_ordering,
9974 try w.print(" {t}{f}{f}", .{
9975 tag,
9976 info.sync_scope.fmt(" "),
9977 info.success_ordering.fmt(" "),
99979978 });
99989979 },
99999980 .fneg,
100009981 .@"fneg fast",
100019982 => |tag| {
100029983 const val: Value = @enumFromInt(instruction.data);
10003 try writer.print(" %{} = {s} {%}", .{
9984 try w.print(" %{f} = {s} {f}", .{
100049985 instruction_index.name(&function).fmt(self),
100059986 @tagName(tag),
10006 val.fmt(function_index, self),
9987 val.fmt(function_index, self, .{ .percent = true }),
100079988 });
100089989 },
100099990 .getelementptr,
......@@ -10014,14 +9995,14 @@ pub fn printUnbuffered(
100149995 instruction.data,
100159996 );
100169997 const indices = extra.trail.next(extra.data.indices_len, Value, &function);
10017 try writer.print(" %{} = {s} {%}, {%}", .{
9998 try w.print(" %{f} = {s} {f}, {f}", .{
100189999 instruction_index.name(&function).fmt(self),
1001910000 @tagName(tag),
10020 extra.data.type.fmt(self),
10021 extra.data.base.fmt(function_index, self),
10001 extra.data.type.fmt(self, .percent),
10002 extra.data.base.fmt(function_index, self, .{ .percent = true }),
1002210003 });
10023 for (indices) |index| try writer.print(", {%}", .{
10024 index.fmt(function_index, self),
10004 for (indices) |index| try w.print(", {f}", .{
10005 index.fmt(function_index, self, .{ .percent = true }),
1002510006 });
1002610007 },
1002710008 .indirectbr => |tag| {
......@@ -10029,54 +10010,54 @@ pub fn printUnbuffered(
1002910010 function.extraDataTrail(Function.Instruction.IndirectBr, instruction.data);
1003010011 const targets =
1003110012 extra.trail.next(extra.data.targets_len, Function.Block.Index, &function);
10032 try writer.print(" {s} {%}, [", .{
10013 try w.print(" {s} {f}, [", .{
1003310014 @tagName(tag),
10034 extra.data.addr.fmt(function_index, self),
10015 extra.data.addr.fmt(function_index, self, .{ .percent = true }),
1003510016 });
1003610017 for (0.., targets) |target_index, target| {
10037 if (target_index > 0) try writer.writeAll(", ");
10038 try writer.print("{%}", .{
10039 target.toInst(&function).fmt(function_index, self),
10018 if (target_index > 0) try w.writeAll(", ");
10019 try w.print("{f}", .{
10020 target.toInst(&function).fmt(function_index, self, .{ .percent = true }),
1004010021 });
1004110022 }
10042 try writer.writeByte(']');
10023 try w.writeByte(']');
1004310024 },
1004410025 .insertelement => |tag| {
1004510026 const extra =
1004610027 function.extraData(Function.Instruction.InsertElement, instruction.data);
10047 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10028 try w.print(" %{f} = {s} {f}, {f}, {f}", .{
1004810029 instruction_index.name(&function).fmt(self),
1004910030 @tagName(tag),
10050 extra.val.fmt(function_index, self),
10051 extra.elem.fmt(function_index, self),
10052 extra.index.fmt(function_index, self),
10031 extra.val.fmt(function_index, self, .{ .percent = true }),
10032 extra.elem.fmt(function_index, self, .{ .percent = true }),
10033 extra.index.fmt(function_index, self, .{ .percent = true }),
1005310034 });
1005410035 },
1005510036 .insertvalue => |tag| {
1005610037 var extra =
1005710038 function.extraDataTrail(Function.Instruction.InsertValue, instruction.data);
1005810039 const indices = extra.trail.next(extra.data.indices_len, u32, &function);
10059 try writer.print(" %{} = {s} {%}, {%}", .{
10040 try w.print(" %{f} = {s} {f}, {f}", .{
1006010041 instruction_index.name(&function).fmt(self),
1006110042 @tagName(tag),
10062 extra.data.val.fmt(function_index, self),
10063 extra.data.elem.fmt(function_index, self),
10043 extra.data.val.fmt(function_index, self, .{ .percent = true }),
10044 extra.data.elem.fmt(function_index, self, .{ .percent = true }),
1006410045 });
10065 for (indices) |index| try writer.print(", {d}", .{index});
10046 for (indices) |index| try w.print(", {d}", .{index});
1006610047 },
1006710048 .load,
1006810049 .@"load atomic",
1006910050 => |tag| {
1007010051 const extra = function.extraData(Function.Instruction.Load, instruction.data);
10071 try writer.print(" %{} = {s}{ } {%}, {%}{ }{ }{, }", .{
10052 try w.print(" %{f} = {t}{f} {f}, {f}{f}{f}{f}", .{
1007210053 instruction_index.name(&function).fmt(self),
10073 @tagName(tag),
10074 extra.info.access_kind,
10075 extra.type.fmt(self),
10076 extra.ptr.fmt(function_index, self),
10077 extra.info.sync_scope,
10078 extra.info.success_ordering,
10079 extra.info.alignment,
10054 tag,
10055 extra.info.access_kind.fmt(" "),
10056 extra.type.fmt(self, .percent),
10057 extra.ptr.fmt(function_index, self, .{ .percent = true }),
10058 extra.info.sync_scope.fmt(" "),
10059 extra.info.success_ordering.fmt(" "),
10060 extra.info.alignment.fmt(", "),
1008010061 });
1008110062 },
1008210063 .phi,
......@@ -10086,64 +10067,64 @@ pub fn printUnbuffered(
1008610067 const vals = extra.trail.next(block_incoming_len, Value, &function);
1008710068 const blocks =
1008810069 extra.trail.next(block_incoming_len, Function.Block.Index, &function);
10089 try writer.print(" %{} = {s} {%} ", .{
10070 try w.print(" %{f} = {s} {f} ", .{
1009010071 instruction_index.name(&function).fmt(self),
1009110072 @tagName(tag),
10092 vals[0].typeOf(function_index, self).fmt(self),
10073 vals[0].typeOf(function_index, self).fmt(self, .percent),
1009310074 });
1009410075 for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| {
10095 if (incoming_index > 0) try writer.writeAll(", ");
10096 try writer.print("[ {}, {} ]", .{
10097 incoming_val.fmt(function_index, self),
10098 incoming_block.toInst(&function).fmt(function_index, self),
10076 if (incoming_index > 0) try w.writeAll(", ");
10077 try w.print("[ {f}, {f} ]", .{
10078 incoming_val.fmt(function_index, self, .{}),
10079 incoming_block.toInst(&function).fmt(function_index, self, .{}),
1009910080 });
1010010081 }
1010110082 },
1010210083 .ret => |tag| {
1010310084 const val: Value = @enumFromInt(instruction.data);
10104 try writer.print(" {s} {%}", .{
10085 try w.print(" {s} {f}", .{
1010510086 @tagName(tag),
10106 val.fmt(function_index, self),
10087 val.fmt(function_index, self, .{ .percent = true }),
1010710088 });
1010810089 },
1010910090 .@"ret void",
1011010091 .@"unreachable",
10111 => |tag| try writer.print(" {s}", .{@tagName(tag)}),
10092 => |tag| try w.print(" {s}", .{@tagName(tag)}),
1011210093 .select,
1011310094 .@"select fast",
1011410095 => |tag| {
1011510096 const extra = function.extraData(Function.Instruction.Select, instruction.data);
10116 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10097 try w.print(" %{f} = {s} {f}, {f}, {f}", .{
1011710098 instruction_index.name(&function).fmt(self),
1011810099 @tagName(tag),
10119 extra.cond.fmt(function_index, self),
10120 extra.lhs.fmt(function_index, self),
10121 extra.rhs.fmt(function_index, self),
10100 extra.cond.fmt(function_index, self, .{ .percent = true }),
10101 extra.lhs.fmt(function_index, self, .{ .percent = true }),
10102 extra.rhs.fmt(function_index, self, .{ .percent = true }),
1012210103 });
1012310104 },
1012410105 .shufflevector => |tag| {
1012510106 const extra =
1012610107 function.extraData(Function.Instruction.ShuffleVector, instruction.data);
10127 try writer.print(" %{} = {s} {%}, {%}, {%}", .{
10108 try w.print(" %{f} = {s} {f}, {f}, {f}", .{
1012810109 instruction_index.name(&function).fmt(self),
1012910110 @tagName(tag),
10130 extra.lhs.fmt(function_index, self),
10131 extra.rhs.fmt(function_index, self),
10132 extra.mask.fmt(function_index, self),
10111 extra.lhs.fmt(function_index, self, .{ .percent = true }),
10112 extra.rhs.fmt(function_index, self, .{ .percent = true }),
10113 extra.mask.fmt(function_index, self, .{ .percent = true }),
1013310114 });
1013410115 },
1013510116 .store,
1013610117 .@"store atomic",
1013710118 => |tag| {
1013810119 const extra = function.extraData(Function.Instruction.Store, instruction.data);
10139 try writer.print(" {s}{ } {%}, {%}{ }{ }{, }", .{
10140 @tagName(tag),
10141 extra.info.access_kind,
10142 extra.val.fmt(function_index, self),
10143 extra.ptr.fmt(function_index, self),
10144 extra.info.sync_scope,
10145 extra.info.success_ordering,
10146 extra.info.alignment,
10120 try w.print(" {t}{f} {f}, {f}{f}{f}{f}", .{
10121 tag,
10122 extra.info.access_kind.fmt(" "),
10123 extra.val.fmt(function_index, self, .{ .percent = true }),
10124 extra.ptr.fmt(function_index, self, .{ .percent = true }),
10125 extra.info.sync_scope.fmt(" "),
10126 extra.info.success_ordering.fmt(" "),
10127 extra.info.alignment.fmt(", "),
1014710128 });
1014810129 },
1014910130 .@"switch" => |tag| {
......@@ -10152,80 +10133,80 @@ pub fn printUnbuffered(
1015210133 const vals = extra.trail.next(extra.data.cases_len, Constant, &function);
1015310134 const blocks =
1015410135 extra.trail.next(extra.data.cases_len, Function.Block.Index, &function);
10155 try writer.print(" {s} {%}, {%} [\n", .{
10136 try w.print(" {s} {f}, {f} [\n", .{
1015610137 @tagName(tag),
10157 extra.data.val.fmt(function_index, self),
10158 extra.data.default.toInst(&function).fmt(function_index, self),
10138 extra.data.val.fmt(function_index, self, .{ .percent = true }),
10139 extra.data.default.toInst(&function).fmt(function_index, self, .{ .percent = true }),
1015910140 });
10160 for (vals, blocks) |case_val, case_block| try writer.print(
10161 " {%}, {%}\n",
10141 for (vals, blocks) |case_val, case_block| try w.print(
10142 " {f}, {f}\n",
1016210143 .{
10163 case_val.fmt(self),
10164 case_block.toInst(&function).fmt(function_index, self),
10144 case_val.fmt(self, .{ .percent = true }),
10145 case_block.toInst(&function).fmt(function_index, self, .{ .percent = true }),
1016510146 },
1016610147 );
10167 try writer.writeAll(" ]");
10148 try w.writeAll(" ]");
1016810149 metadata_formatter.need_comma = true;
1016910150 defer metadata_formatter.need_comma = undefined;
1017010151 switch (extra.data.weights) {
1017110152 .none => {},
10172 .unpredictable => try writer.writeAll("!unpredictable !{}"),
10173 _ => try writer.print("{}", .{
10174 try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.data.weights)))),
10153 .unpredictable => try w.writeAll("!unpredictable !{}"),
10154 _ => try w.print("{f}", .{
10155 try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.data.weights))), null),
1017510156 }),
1017610157 }
1017710158 },
1017810159 .va_arg => |tag| {
1017910160 const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
10180 try writer.print(" %{} = {s} {%}, {%}", .{
10161 try w.print(" %{f} = {s} {f}, {f}", .{
1018110162 instruction_index.name(&function).fmt(self),
1018210163 @tagName(tag),
10183 extra.list.fmt(function_index, self),
10184 extra.type.fmt(self),
10164 extra.list.fmt(function_index, self, .{ .percent = true }),
10165 extra.type.fmt(self, .percent),
1018510166 });
1018610167 },
1018710168 }
1018810169
1018910170 if (maybe_dbg_index) |dbg_index| {
10190 try writer.print(", !dbg !{}", .{dbg_index});
10171 try w.print(", !dbg !{d}", .{dbg_index});
1019110172 }
10192 try writer.writeByte('\n');
10173 try w.writeByte('\n');
1019310174 }
10194 try writer.writeByte('}');
10175 try w.writeByte('}');
1019510176 }
10196 try writer.writeByte('\n');
10177 try w.writeByte('\n');
1019710178 }
1019810179
1019910180 if (attribute_groups.count() > 0) {
10200 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10181 if (need_newline) try w.writeByte('\n') else need_newline = true;
1020110182 for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group|
10202 try writer.print(
10203 \\attributes #{d} = {{{#"} }}
10183 try w.print(
10184 \\attributes #{d} = {{{f} }}
1020410185 \\
10205 , .{ attribute_group_index, attribute_group.fmt(self) });
10186 , .{ attribute_group_index, attribute_group.fmt(self, .{ .pound = true, .quote = true }) });
1020610187 }
1020710188
1020810189 if (self.metadata_named.count() > 0) {
10209 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10190 if (need_newline) try w.writeByte('\n') else need_newline = true;
1021010191 for (self.metadata_named.keys(), self.metadata_named.values()) |name, data| {
1021110192 const elements: []const Metadata =
1021210193 @ptrCast(self.metadata_extra.items[data.index..][0..data.len]);
10213 try writer.writeByte('!');
10214 try printEscapedString(name.slice(self), .quote_unless_valid_identifier, writer);
10215 try writer.writeAll(" = !{");
10194 try w.writeByte('!');
10195 try printEscapedString(name.slice(self), .quote_unless_valid_identifier, w);
10196 try w.writeAll(" = !{");
1021610197 metadata_formatter.need_comma = false;
1021710198 defer metadata_formatter.need_comma = undefined;
10218 for (elements) |element| try writer.print("{}", .{try metadata_formatter.fmt("", element)});
10219 try writer.writeAll("}\n");
10199 for (elements) |element| try w.print("{f}", .{try metadata_formatter.fmt("", element, null)});
10200 try w.writeAll("}\n");
1022010201 }
1022110202 }
1022210203
1022310204 if (metadata_formatter.map.count() > 0) {
10224 if (need_newline) try writer.writeByte('\n') else need_newline = true;
10205 if (need_newline) try w.writeByte('\n') else need_newline = true;
1022510206 var metadata_index: usize = 0;
1022610207 while (metadata_index < metadata_formatter.map.count()) : (metadata_index += 1) {
1022710208 @setEvalBranchQuota(10_000);
10228 try writer.print("!{} = ", .{metadata_index});
10209 try w.print("!{d} = ", .{metadata_index});
1022910210 metadata_formatter.need_comma = false;
1023010211 defer metadata_formatter.need_comma = undefined;
1023110212
......@@ -10238,7 +10219,7 @@ pub fn printUnbuffered(
1023810219 .scope = location.scope,
1023910220 .inlinedAt = location.inlined_at,
1024010221 .isImplicitCode = false,
10241 }, writer);
10222 }, w);
1024210223 continue;
1024310224 },
1024410225 .metadata => |metadata| self.metadata_items.get(@intFromEnum(metadata)),
......@@ -10254,7 +10235,7 @@ pub fn printUnbuffered(
1025410235 .checksumkind = null,
1025510236 .checksum = null,
1025610237 .source = null,
10257 }, writer);
10238 }, w);
1025810239 },
1025910240 .compile_unit,
1026010241 .@"compile_unit optimized",
......@@ -10285,7 +10266,7 @@ pub fn printUnbuffered(
1028510266 .rangesBaseAddress = null,
1028610267 .sysroot = null,
1028710268 .sdk = null,
10288 }, writer);
10269 }, w);
1028910270 },
1029010271 .subprogram,
1029110272 .@"subprogram local",
......@@ -10319,7 +10300,7 @@ pub fn printUnbuffered(
1031910300 .thrownTypes = null,
1032010301 .annotations = null,
1032110302 .targetFuncName = null,
10322 }, writer);
10303 }, w);
1032310304 },
1032410305 .lexical_block => {
1032510306 const extra = self.metadataExtraData(Metadata.LexicalBlock, metadata_item.data);
......@@ -10328,7 +10309,7 @@ pub fn printUnbuffered(
1032810309 .file = extra.file,
1032910310 .line = extra.line,
1033010311 .column = extra.column,
10331 }, writer);
10312 }, w);
1033210313 },
1033310314 .location => {
1033410315 const extra = self.metadataExtraData(Metadata.Location, metadata_item.data);
......@@ -10338,7 +10319,7 @@ pub fn printUnbuffered(
1033810319 .scope = extra.scope,
1033910320 .inlinedAt = extra.inlined_at,
1034010321 .isImplicitCode = false,
10341 }, writer);
10322 }, w);
1034210323 },
1034310324 .basic_bool_type,
1034410325 .basic_unsigned_type,
......@@ -10367,7 +10348,7 @@ pub fn printUnbuffered(
1036710348 else => unreachable,
1036810349 }),
1036910350 .flags = null,
10370 }, writer);
10351 }, w);
1037110352 },
1037210353 .composite_struct_type,
1037310354 .composite_union_type,
......@@ -10412,7 +10393,7 @@ pub fn printUnbuffered(
1041210393 .allocated = null,
1041310394 .rank = null,
1041410395 .annotations = null,
10415 }, writer);
10396 }, w);
1041610397 },
1041710398 .derived_pointer_type,
1041810399 .derived_member_type,
......@@ -10445,7 +10426,7 @@ pub fn printUnbuffered(
1044510426 .extraData = null,
1044610427 .dwarfAddressSpace = null,
1044710428 .annotations = null,
10448 }, writer);
10429 }, w);
1044910430 },
1045010431 .subroutine_type => {
1045110432 const extra = self.metadataExtraData(Metadata.SubroutineType, metadata_item.data);
......@@ -10453,7 +10434,7 @@ pub fn printUnbuffered(
1045310434 .flags = null,
1045410435 .cc = null,
1045510436 .types = extra.types_tuple,
10456 }, writer);
10437 }, w);
1045710438 },
1045810439 .enumerator_unsigned,
1045910440 .enumerator_signed_positive,
......@@ -10503,7 +10484,7 @@ pub fn printUnbuffered(
1050310484 => false,
1050410485 else => unreachable,
1050510486 },
10506 }, writer);
10487 }, w);
1050710488 },
1050810489 .subrange => {
1050910490 const extra = self.metadataExtraData(Metadata.Subrange, metadata_item.data);
......@@ -10512,34 +10493,34 @@ pub fn printUnbuffered(
1051210493 .lowerBound = extra.lower_bound,
1051310494 .upperBound = null,
1051410495 .stride = null,
10515 }, writer);
10496 }, w);
1051610497 },
1051710498 .tuple => {
1051810499 var extra = self.metadataExtraDataTrail(Metadata.Tuple, metadata_item.data);
1051910500 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
10520 try writer.writeAll("!{");
10521 for (elements) |element| try writer.print("{[element]%}", .{
10522 .element = try metadata_formatter.fmt("", element),
10501 try w.writeAll("!{");
10502 for (elements) |element| try w.print("{[element]f}", .{
10503 .element = try metadata_formatter.fmt("", element, .{ .percent = true }),
1052310504 });
10524 try writer.writeAll("}\n");
10505 try w.writeAll("}\n");
1052510506 },
1052610507 .str_tuple => {
1052710508 var extra = self.metadataExtraDataTrail(Metadata.StrTuple, metadata_item.data);
1052810509 const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
10529 try writer.print("!{{{[str]%}", .{
10530 .str = try metadata_formatter.fmt("", extra.data.str),
10510 try w.print("!{{{[str]f}", .{
10511 .str = try metadata_formatter.fmt("", extra.data.str, .{ .percent = true }),
1053110512 });
10532 for (elements) |element| try writer.print("{[element]%}", .{
10533 .element = try metadata_formatter.fmt("", element),
10513 for (elements) |element| try w.print("{[element]f}", .{
10514 .element = try metadata_formatter.fmt("", element, .{ .percent = true }),
1053410515 });
10535 try writer.writeAll("}\n");
10516 try w.writeAll("}\n");
1053610517 },
1053710518 .module_flag => {
1053810519 const extra = self.metadataExtraData(Metadata.ModuleFlag, metadata_item.data);
10539 try writer.print("!{{{[behavior]%}{[name]%}{[constant]%}}}\n", .{
10540 .behavior = try metadata_formatter.fmt("", extra.behavior),
10541 .name = try metadata_formatter.fmt("", extra.name),
10542 .constant = try metadata_formatter.fmt("", extra.constant),
10520 try w.print("!{{{[behavior]f}{[name]f}{[constant]f}}}\n", .{
10521 .behavior = try metadata_formatter.fmt("", extra.behavior, .{ .percent = true }),
10522 .name = try metadata_formatter.fmt("", extra.name, .{ .percent = true }),
10523 .constant = try metadata_formatter.fmt("", extra.constant, .{ .percent = true }),
1054310524 });
1054410525 },
1054510526 .local_var => {
......@@ -10554,7 +10535,7 @@ pub fn printUnbuffered(
1055410535 .flags = null,
1055510536 .@"align" = null,
1055610537 .annotations = null,
10557 }, writer);
10538 }, w);
1055810539 },
1055910540 .parameter => {
1056010541 const extra = self.metadataExtraData(Metadata.Parameter, metadata_item.data);
......@@ -10568,7 +10549,7 @@ pub fn printUnbuffered(
1056810549 .flags = null,
1056910550 .@"align" = null,
1057010551 .annotations = null,
10571 }, writer);
10552 }, w);
1057210553 },
1057310554 .global_var,
1057410555 .@"global_var local",
......@@ -10591,7 +10572,7 @@ pub fn printUnbuffered(
1059110572 .templateParams = null,
1059210573 .@"align" = null,
1059310574 .annotations = null,
10594 }, writer);
10575 }, w);
1059510576 },
1059610577 .global_var_expression => {
1059710578 const extra =
......@@ -10599,7 +10580,7 @@ pub fn printUnbuffered(
1059910580 try metadata_formatter.specialized(.@"!", .DIGlobalVariableExpression, .{
1060010581 .@"var" = extra.variable,
1060110582 .expr = extra.expression,
10602 }, writer);
10583 }, w);
1060310584 },
1060410585 }
1060510586 }
......@@ -10618,22 +10599,18 @@ fn isValidIdentifier(id: []const u8) bool {
1061810599}
1061910600
1062010601const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier };
10621fn printEscapedString(
10622 slice: []const u8,
10623 quotes: QuoteBehavior,
10624 writer: anytype,
10625) @TypeOf(writer).Error!void {
10602fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, w: *Writer) Writer.Error!void {
1062610603 const need_quotes = switch (quotes) {
1062710604 .always_quote => true,
1062810605 .quote_unless_valid_identifier => !isValidIdentifier(slice),
1062910606 };
10630 if (need_quotes) try writer.writeByte('"');
10607 if (need_quotes) try w.writeByte('"');
1063110608 for (slice) |byte| switch (byte) {
10632 '\\' => try writer.writeAll("\\\\"),
10633 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte),
10634 else => try writer.print("\\{X:0>2}", .{byte}),
10609 '\\' => try w.writeAll("\\\\"),
10610 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try w.writeByte(byte),
10611 else => try w.print("\\{X:0>2}", .{byte}),
1063510612 };
10636 if (need_quotes) try writer.writeByte('"');
10613 if (need_quotes) try w.writeByte('"');
1063710614}
1063810615
1063910616fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void {
......@@ -12018,7 +11995,7 @@ pub fn metadataStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args:
1201811995}
1201911996
1202011997pub fn metadataStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) MetadataString {
12021 self.metadata_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable;
11998 self.metadata_string_bytes.printAssumeCapacity(fmt_str, fmt_args);
1202211999 return self.trailingMetadataStringAssumeCapacity();
1202312000}
1202412001
......@@ -15261,12 +15238,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
1526115238 return bitcode.toOwnedSlice();
1526215239}
1526315240
15264const Allocator = std.mem.Allocator;
15265const assert = std.debug.assert;
15266const bitcode_writer = @import("bitcode_writer.zig");
15267const Builder = @This();
15268const builtin = @import("builtin");
15269const DW = std.dwarf;
15270const ir = @import("ir.zig");
15271const log = std.log.scoped(.llvm);
15272const std = @import("../../std.zig");
15241const FormatFlags = struct {
15242 comma: bool = false,
15243 space: bool = false,
15244 percent: bool = false,
15245
15246 fn onlyPercent(f: FormatFlags) bool {
15247 return !f.comma and !f.space and f.percent;
15248 }
15249};
lib/std/zig/parser_test.zig+11-11
......@@ -1,3 +1,9 @@
1const std = @import("std");
2const mem = std.mem;
3const print = std.debug.print;
4const io = std.io;
5const maxInt = std.math.maxInt;
6
17test "zig fmt: remove extra whitespace at start and end of file with comment between" {
28 try testTransform(
39 \\
......@@ -2738,11 +2744,11 @@ test "zig fmt: preserve spacing" {
27382744 \\const std = @import("std");
27392745 \\
27402746 \\pub fn main() !void {
2741 \\ var stdout_file = std.io.getStdOut;
2742 \\ var stdout_file = std.io.getStdOut;
2747 \\ var stdout_file = std.lol.abcd;
2748 \\ var stdout_file = std.lol.abcd;
27432749 \\
2744 \\ var stdout_file = std.io.getStdOut;
2745 \\ var stdout_file = std.io.getStdOut;
2750 \\ var stdout_file = std.lol.abcd;
2751 \\ var stdout_file = std.lol.abcd;
27462752 \\}
27472753 \\
27482754 );
......@@ -6315,16 +6321,10 @@ test "ampersand" {
63156321 , &.{});
63166322}
63176323
6318const std = @import("std");
6319const mem = std.mem;
6320const print = std.debug.print;
6321const io = std.io;
6322const maxInt = std.math.maxInt;
6323
63246324var fixed_buffer_mem: [100 * 1024]u8 = undefined;
63256325
63266326fn testParse(source: [:0]const u8, allocator: mem.Allocator, anything_changed: *bool) ![]u8 {
6327 const stderr = io.getStdErr().writer();
6327 const stderr = std.fs.File.stderr().deprecatedWriter();
63286328
63296329 var tree = try std.zig.Ast.parse(allocator, source, .zig);
63306330 defer tree.deinit(allocator);
lib/std/zig/perf_test.zig+2-2
......@@ -22,8 +22,8 @@ pub fn main() !void {
2222 const bytes_per_sec_float = @as(f64, @floatFromInt(source.len * iterations)) / elapsed_s;
2323 const bytes_per_sec = @as(u64, @intFromFloat(@floor(bytes_per_sec_float)));
2424
25 var stdout_file = std.io.getStdOut();
26 const stdout = stdout_file.writer();
25 var stdout_file: std.fs.File = .stdout();
26 const stdout = stdout_file.deprecatedWriter();
2727 try stdout.print("parsing speed: {:.2}/s, {:.2} used \n", .{
2828 fmtIntSizeBin(bytes_per_sec),
2929 fmtIntSizeBin(memory_used),
lib/std/zig/render.zig+4-4
......@@ -1564,7 +1564,7 @@ fn renderBuiltinCall(
15641564 defer r.gpa.free(new_string);
15651565
15661566 try renderToken(r, builtin_token + 1, .none); // (
1567 try ais.writer().print("\"{}\"", .{std.zig.fmtEscapes(new_string)});
1567 try ais.writer().print("\"{f}\"", .{std.zig.fmtString(new_string)});
15681568 return renderToken(r, str_lit_token + 1, space); // )
15691569 }
15701570 }
......@@ -2872,7 +2872,7 @@ fn renderIdentifierContents(writer: anytype, bytes: []const u8) !void {
28722872 .success => |codepoint| {
28732873 if (codepoint <= 0x7f) {
28742874 const buf = [1]u8{@as(u8, @intCast(codepoint))};
2875 try std.fmt.format(writer, "{}", .{std.zig.fmtEscapes(&buf)});
2875 try std.fmt.format(writer, "{f}", .{std.zig.fmtString(&buf)});
28762876 } else {
28772877 try writer.writeAll(escape_sequence);
28782878 }
......@@ -2884,7 +2884,7 @@ fn renderIdentifierContents(writer: anytype, bytes: []const u8) !void {
28842884 },
28852885 0x00...('\\' - 1), ('\\' + 1)...0x7f => {
28862886 const buf = [1]u8{byte};
2887 try std.fmt.format(writer, "{}", .{std.zig.fmtEscapes(&buf)});
2887 try std.fmt.format(writer, "{f}", .{std.zig.fmtString(&buf)});
28882888 pos += 1;
28892889 },
28902890 0x80...0xff => {
......@@ -3245,7 +3245,7 @@ fn AutoIndentingStream(comptime UnderlyingWriter: type) type {
32453245 return struct {
32463246 const Self = @This();
32473247 pub const WriteError = UnderlyingWriter.Error;
3248 pub const Writer = std.io.Writer(*Self, WriteError, write);
3248 pub const Writer = std.io.GenericWriter(*Self, WriteError, write);
32493249
32503250 pub const IndentType = enum {
32513251 normal,
lib/std/zig/string_literal.zig+3-10
......@@ -44,14 +44,7 @@ pub const Error = union(enum) {
4444 raw_string: []const u8,
4545 };
4646
47 fn formatMessage(
48 self: FormatMessage,
49 comptime f: []const u8,
50 options: std.fmt.FormatOptions,
51 writer: anytype,
52 ) !void {
53 _ = f;
54 _ = options;
47 fn formatMessage(self: FormatMessage, writer: *std.io.Writer) std.io.Writer.Error!void {
5548 switch (self.err) {
5649 .invalid_escape_character => |bad_index| try writer.print(
5750 "invalid escape character: '{c}'",
......@@ -93,7 +86,7 @@ pub const Error = union(enum) {
9386 }
9487 }
9588
96 pub fn fmt(self: @This(), raw_string: []const u8) std.fmt.Formatter(formatMessage) {
89 pub fn fmt(self: @This(), raw_string: []const u8) std.fmt.Formatter(FormatMessage, formatMessage) {
9790 return .{ .data = .{
9891 .err = self,
9992 .raw_string = raw_string,
......@@ -322,7 +315,7 @@ test parseCharLiteral {
322315 );
323316}
324317
325/// Parses `bytes` as a Zig string literal and writes the result to the std.io.Writer type.
318/// Parses `bytes` as a Zig string literal and writes the result to the `std.io.GenericWriter` type.
326319/// Asserts `bytes` has '"' at beginning and end.
327320pub fn parseWrite(writer: anytype, bytes: []const u8) error{OutOfMemory}!Result {
328321 assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"');
lib/std/zig/system/linux.zig+4-4
......@@ -391,7 +391,7 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
391391 const current_arch = builtin.cpu.arch;
392392 switch (current_arch) {
393393 .arm, .armeb, .thumb, .thumbeb => {
394 return ArmCpuinfoParser.parse(current_arch, f.reader()) catch null;
394 return ArmCpuinfoParser.parse(current_arch, f.deprecatedReader()) catch null;
395395 },
396396 .aarch64, .aarch64_be => {
397397 const registers = [12]u64{
......@@ -413,13 +413,13 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
413413 return core;
414414 },
415415 .sparc64 => {
416 return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null;
416 return SparcCpuinfoParser.parse(current_arch, f.deprecatedReader()) catch null;
417417 },
418418 .powerpc, .powerpcle, .powerpc64, .powerpc64le => {
419 return PowerpcCpuinfoParser.parse(current_arch, f.reader()) catch null;
419 return PowerpcCpuinfoParser.parse(current_arch, f.deprecatedReader()) catch null;
420420 },
421421 .riscv64, .riscv32 => {
422 return RiscvCpuinfoParser.parse(current_arch, f.reader()) catch null;
422 return RiscvCpuinfoParser.parse(current_arch, f.deprecatedReader()) catch null;
423423 },
424424 else => {},
425425 }
lib/std/zip.zig+12-12
......@@ -106,7 +106,7 @@ pub const EndRecord = extern struct {
106106/// Find and return the end record for the given seekable zip stream.
107107/// Note that `seekable_stream` must be an instance of `std.io.SeekableStream` and
108108/// its context must also have a `.reader()` method that returns an instance of
109/// `std.io.Reader`.
109/// `std.io.GenericReader`.
110110pub fn findEndRecord(seekable_stream: anytype, stream_len: u64) !EndRecord {
111111 var buf: [@sizeOf(EndRecord) + std.math.maxInt(u16)]u8 = undefined;
112112 const record_len_max = @min(stream_len, buf.len);
......@@ -124,7 +124,7 @@ pub fn findEndRecord(seekable_stream: anytype, stream_len: u64) !EndRecord {
124124
125125 try seekable_stream.seekTo(stream_len - @as(u64, new_loaded_len));
126126 const read_buf: []u8 = buf[buf.len - new_loaded_len ..][0..read_len];
127 const len = try seekable_stream.context.reader().readAll(read_buf);
127 const len = try (if (@TypeOf(seekable_stream.context) == std.fs.File) seekable_stream.context.deprecatedReader() else seekable_stream.context.reader()).readAll(read_buf);
128128 if (len != read_len)
129129 return error.ZipTruncated;
130130 loaded_len = new_loaded_len;
......@@ -295,7 +295,7 @@ pub fn Iterator(comptime SeekableStream: type) type {
295295 if (locator_end_offset > stream_len)
296296 return error.ZipTruncated;
297297 try stream.seekTo(stream_len - locator_end_offset);
298 const locator = try stream.context.reader().readStructEndian(EndLocator64, .little);
298 const locator = try (if (@TypeOf(stream.context) == std.fs.File) stream.context.deprecatedReader() else stream.context.reader()).readStructEndian(EndLocator64, .little);
299299 if (!std.mem.eql(u8, &locator.signature, &end_locator64_sig))
300300 return error.ZipBadLocatorSig;
301301 if (locator.zip64_disk_count != 0)
......@@ -305,7 +305,7 @@ pub fn Iterator(comptime SeekableStream: type) type {
305305
306306 try stream.seekTo(locator.record_file_offset);
307307
308 const record64 = try stream.context.reader().readStructEndian(EndRecord64, .little);
308 const record64 = try (if (@TypeOf(stream.context) == std.fs.File) stream.context.deprecatedReader() else stream.context.reader()).readStructEndian(EndRecord64, .little);
309309
310310 if (!std.mem.eql(u8, &record64.signature, &end_record64_sig))
311311 return error.ZipBadEndRecord64Sig;
......@@ -357,7 +357,7 @@ pub fn Iterator(comptime SeekableStream: type) type {
357357
358358 const header_zip_offset = self.cd_zip_offset + self.cd_record_offset;
359359 try self.stream.seekTo(header_zip_offset);
360 const header = try self.stream.context.reader().readStructEndian(CentralDirectoryFileHeader, .little);
360 const header = try (if (@TypeOf(self.stream.context) == std.fs.File) self.stream.context.deprecatedReader() else self.stream.context.reader()).readStructEndian(CentralDirectoryFileHeader, .little);
361361 if (!std.mem.eql(u8, &header.signature, &central_file_header_sig))
362362 return error.ZipBadCdOffset;
363363
......@@ -386,7 +386,7 @@ pub fn Iterator(comptime SeekableStream: type) type {
386386
387387 {
388388 try self.stream.seekTo(header_zip_offset + @sizeOf(CentralDirectoryFileHeader) + header.filename_len);
389 const len = try self.stream.context.reader().readAll(extra);
389 const len = try (if (@TypeOf(self.stream.context) == std.fs.File) self.stream.context.deprecatedReader() else self.stream.context.reader()).readAll(extra);
390390 if (len != extra.len)
391391 return error.ZipTruncated;
392392 }
......@@ -449,7 +449,7 @@ pub fn Iterator(comptime SeekableStream: type) type {
449449 try stream.seekTo(self.header_zip_offset + @sizeOf(CentralDirectoryFileHeader));
450450
451451 {
452 const len = try stream.context.reader().readAll(filename);
452 const len = try (if (@TypeOf(stream.context) == std.fs.File) stream.context.deprecatedReader() else stream.context.reader()).readAll(filename);
453453 if (len != filename.len)
454454 return error.ZipBadFileOffset;
455455 }
......@@ -457,7 +457,7 @@ pub fn Iterator(comptime SeekableStream: type) type {
457457 const local_data_header_offset: u64 = local_data_header_offset: {
458458 const local_header = blk: {
459459 try stream.seekTo(self.file_offset);
460 break :blk try stream.context.reader().readStructEndian(LocalFileHeader, .little);
460 break :blk try (if (@TypeOf(stream.context) == std.fs.File) stream.context.deprecatedReader() else stream.context.reader()).readStructEndian(LocalFileHeader, .little);
461461 };
462462 if (!std.mem.eql(u8, &local_header.signature, &local_file_header_sig))
463463 return error.ZipBadFileOffset;
......@@ -483,7 +483,7 @@ pub fn Iterator(comptime SeekableStream: type) type {
483483
484484 {
485485 try stream.seekTo(self.file_offset + @sizeOf(LocalFileHeader) + local_header.filename_len);
486 const len = try stream.context.reader().readAll(extra);
486 const len = try (if (@TypeOf(stream.context) == std.fs.File) stream.context.deprecatedReader() else stream.context.reader()).readAll(extra);
487487 if (len != extra.len)
488488 return error.ZipTruncated;
489489 }
......@@ -552,12 +552,12 @@ pub fn Iterator(comptime SeekableStream: type) type {
552552 @as(u64, @sizeOf(LocalFileHeader)) +
553553 local_data_header_offset;
554554 try stream.seekTo(local_data_file_offset);
555 var limited_reader = std.io.limitedReader(stream.context.reader(), self.compressed_size);
555 var limited_reader = std.io.limitedReader((if (@TypeOf(stream.context) == std.fs.File) stream.context.deprecatedReader() else stream.context.reader()), self.compressed_size);
556556 const crc = try decompress(
557557 self.compression_method,
558558 self.uncompressed_size,
559559 limited_reader.reader(),
560 out_file.writer(),
560 out_file.deprecatedWriter(),
561561 );
562562 if (limited_reader.bytes_left != 0)
563563 return error.ZipDecompressTruncated;
......@@ -617,7 +617,7 @@ pub const ExtractOptions = struct {
617617/// Extract the zipped files inside `seekable_stream` to the given `dest` directory.
618618/// Note that `seekable_stream` must be an instance of `std.io.SeekableStream` and
619619/// its context must also have a `.reader()` method that returns an instance of
620/// `std.io.Reader`.
620/// `std.io.GenericReader`.
621621pub fn extract(dest: std.fs.Dir, seekable_stream: anytype, options: ExtractOptions) !void {
622622 const SeekableStream = @TypeOf(seekable_stream);
623623 var iter = try Iterator(SeekableStream).init(seekable_stream);
lib/std/zip/test.zig+1-1
......@@ -33,7 +33,7 @@ pub fn expectFiles(
3333 var file = try dir.openFile(normalized_sub_path, .{});
3434 defer file.close();
3535 var content_buf: [4096]u8 = undefined;
36 const n = try file.reader().readAll(&content_buf);
36 const n = try file.deprecatedReader().readAll(&content_buf);
3737 try testing.expectEqualStrings(test_file.content, content_buf[0..n]);
3838 }
3939}
lib/std/zon/parse.zig+111-130
......@@ -64,22 +64,14 @@ pub const Error = union(enum) {
6464 }
6565 };
6666
67 fn formatMessage(
68 self: []const u8,
69 comptime f: []const u8,
70 options: std.fmt.FormatOptions,
71 writer: anytype,
72 ) !void {
73 _ = f;
74 _ = options;
75
67 fn formatMessage(self: []const u8, w: *std.io.Writer) std.io.Writer.Error!void {
7668 // Just writes the string for now, but we're keeping this behind a formatter so we have
7769 // the option to extend it in the future to print more advanced messages (like `Error`
7870 // does) without breaking the API.
79 try writer.writeAll(self);
71 try w.writeAll(self);
8072 }
8173
82 pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Formatter(Note.formatMessage) {
74 pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Formatter([]const u8, Note.formatMessage) {
8375 return .{ .data = switch (self) {
8476 .zoir => |note| note.msg.get(diag.zoir),
8577 .type_check => |note| note.msg,
......@@ -155,21 +147,14 @@ pub const Error = union(enum) {
155147 diag: *const Diagnostics,
156148 };
157149
158 fn formatMessage(
159 self: FormatMessage,
160 comptime f: []const u8,
161 options: std.fmt.FormatOptions,
162 writer: anytype,
163 ) !void {
164 _ = f;
165 _ = options;
150 fn formatMessage(self: FormatMessage, w: *std.io.Writer) std.io.Writer.Error!void {
166151 switch (self.err) {
167 .zoir => |err| try writer.writeAll(err.msg.get(self.diag.zoir)),
168 .type_check => |tc| try writer.writeAll(tc.message),
152 .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)),
153 .type_check => |tc| try w.writeAll(tc.message),
169154 }
170155 }
171156
172 pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Formatter(formatMessage) {
157 pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Formatter(FormatMessage, formatMessage) {
173158 return .{ .data = .{
174159 .err = self,
175160 .diag = diag,
......@@ -241,25 +226,18 @@ pub const Diagnostics = struct {
241226 return .{ .diag = self };
242227 }
243228
244 pub fn format(
245 self: *const @This(),
246 comptime fmt: []const u8,
247 options: std.fmt.FormatOptions,
248 writer: anytype,
249 ) !void {
250 _ = fmt;
251 _ = options;
229 pub fn format(self: *const @This(), w: *std.io.Writer) std.io.Writer.Error!void {
252230 var errors = self.iterateErrors();
253231 while (errors.next()) |err| {
254232 const loc = err.getLocation(self);
255233 const msg = err.fmtMessage(self);
256 try writer.print("{}:{}: error: {}\n", .{ loc.line + 1, loc.column + 1, msg });
234 try w.print("{d}:{d}: error: {f}\n", .{ loc.line + 1, loc.column + 1, msg });
257235
258236 var notes = err.iterateNotes(self);
259237 while (notes.next()) |note| {
260238 const note_loc = note.getLocation(self);
261239 const note_msg = note.fmtMessage(self);
262 try writer.print("{}:{}: note: {s}\n", .{
240 try w.print("{d}:{d}: note: {f}\n", .{
263241 note_loc.line + 1,
264242 note_loc.column + 1,
265243 note_msg,
......@@ -646,7 +624,7 @@ const Parser = struct {
646624 .failure => |err| {
647625 const token = self.ast.nodeMainToken(ast_node);
648626 const raw_string = self.ast.tokenSlice(token);
649 return self.failTokenFmt(token, @intCast(err.offset()), "{s}", .{err.fmt(raw_string)});
627 return self.failTokenFmt(token, @intCast(err.offset()), "{f}", .{err.fmt(raw_string)});
650628 },
651629 }
652630
......@@ -1087,7 +1065,10 @@ const Parser = struct {
10871065 try writer.writeAll(msg);
10881066 inline for (info.fields, 0..) |field_info, i| {
10891067 if (i != 0) try writer.writeAll(", ");
1090 try writer.print("'{p_}'", .{std.zig.fmtId(field_info.name)});
1068 try writer.print("'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{
1069 .allow_primitive = true,
1070 .allow_underscore = true,
1071 })});
10911072 }
10921073 break :b .{
10931074 .token = token,
......@@ -1298,7 +1279,7 @@ test "std.zon ast errors" {
12981279 error.ParseZon,
12991280 fromSlice(struct {}, gpa, ".{.x = 1 .y = 2}", &diag, .{}),
13001281 );
1301 try std.testing.expectFmt("1:13: error: expected ',' after initializer\n", "{}", .{diag});
1282 try std.testing.expectFmt("1:13: error: expected ',' after initializer\n", "{f}", .{diag});
13021283}
13031284
13041285test "std.zon comments" {
......@@ -1320,7 +1301,7 @@ test "std.zon comments" {
13201301 , &diag, .{}));
13211302 try std.testing.expectFmt(
13221303 "1:1: error: expected expression, found 'a document comment'\n",
1323 "{}",
1304 "{f}",
13241305 .{diag},
13251306 );
13261307 }
......@@ -1341,7 +1322,7 @@ test "std.zon failure/oom formatting" {
13411322 &diag,
13421323 .{},
13431324 ));
1344 try std.testing.expectFmt("", "{}", .{diag});
1325 try std.testing.expectFmt("", "{f}", .{diag});
13451326}
13461327
13471328test "std.zon fromSlice syntax error" {
......@@ -1421,7 +1402,7 @@ test "std.zon unions" {
14211402 \\1:4: note: supported: 'x', 'y'
14221403 \\
14231404 ,
1424 "{}",
1405 "{f}",
14251406 .{diag},
14261407 );
14271408 }
......@@ -1435,7 +1416,7 @@ test "std.zon unions" {
14351416 error.ParseZon,
14361417 fromSlice(Union, gpa, ".{.x=1}", &diag, .{}),
14371418 );
1438 try std.testing.expectFmt("1:6: error: expected type 'void'\n", "{}", .{diag});
1419 try std.testing.expectFmt("1:6: error: expected type 'void'\n", "{f}", .{diag});
14391420 }
14401421
14411422 // Extra field
......@@ -1447,7 +1428,7 @@ test "std.zon unions" {
14471428 error.ParseZon,
14481429 fromSlice(Union, gpa, ".{.x = 1.5, .y = true}", &diag, .{}),
14491430 );
1450 try std.testing.expectFmt("1:2: error: expected union\n", "{}", .{diag});
1431 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
14511432 }
14521433
14531434 // No fields
......@@ -1459,7 +1440,7 @@ test "std.zon unions" {
14591440 error.ParseZon,
14601441 fromSlice(Union, gpa, ".{}", &diag, .{}),
14611442 );
1462 try std.testing.expectFmt("1:2: error: expected union\n", "{}", .{diag});
1443 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
14631444 }
14641445
14651446 // Enum literals cannot coerce into untagged unions
......@@ -1468,7 +1449,7 @@ test "std.zon unions" {
14681449 var diag: Diagnostics = .{};
14691450 defer diag.deinit(gpa);
14701451 try std.testing.expectError(error.ParseZon, fromSlice(Union, gpa, ".x", &diag, .{}));
1471 try std.testing.expectFmt("1:2: error: expected union\n", "{}", .{diag});
1452 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
14721453 }
14731454
14741455 // Unknown field for enum literal coercion
......@@ -1482,7 +1463,7 @@ test "std.zon unions" {
14821463 \\1:2: note: supported: 'x'
14831464 \\
14841465 ,
1485 "{}",
1466 "{f}",
14861467 .{diag},
14871468 );
14881469 }
......@@ -1493,7 +1474,7 @@ test "std.zon unions" {
14931474 var diag: Diagnostics = .{};
14941475 defer diag.deinit(gpa);
14951476 try std.testing.expectError(error.ParseZon, fromSlice(Union, gpa, ".x", &diag, .{}));
1496 try std.testing.expectFmt("1:2: error: expected union\n", "{}", .{diag});
1477 try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag});
14971478 }
14981479}
14991480
......@@ -1549,7 +1530,7 @@ test "std.zon structs" {
15491530 \\1:12: note: supported: 'x', 'y'
15501531 \\
15511532 ,
1552 "{}",
1533 "{f}",
15531534 .{diag},
15541535 );
15551536 }
......@@ -1567,7 +1548,7 @@ test "std.zon structs" {
15671548 \\1:4: error: duplicate struct field name
15681549 \\1:12: note: duplicate name here
15691550 \\
1570 , "{}", .{diag});
1551 , "{f}", .{diag});
15711552 }
15721553
15731554 // Ignore unknown fields
......@@ -1592,7 +1573,7 @@ test "std.zon structs" {
15921573 \\1:4: error: unexpected field 'x'
15931574 \\1:4: note: none expected
15941575 \\
1595 , "{}", .{diag});
1576 , "{f}", .{diag});
15961577 }
15971578
15981579 // Missing field
......@@ -1604,7 +1585,7 @@ test "std.zon structs" {
16041585 error.ParseZon,
16051586 fromSlice(Vec2, gpa, ".{.x=1.5}", &diag, .{}),
16061587 );
1607 try std.testing.expectFmt("1:2: error: missing required field y\n", "{}", .{diag});
1588 try std.testing.expectFmt("1:2: error: missing required field y\n", "{f}", .{diag});
16081589 }
16091590
16101591 // Default field
......@@ -1631,7 +1612,7 @@ test "std.zon structs" {
16311612 try std.testing.expectFmt(
16321613 \\1:18: error: cannot initialize comptime field
16331614 \\
1634 , "{}", .{diag});
1615 , "{f}", .{diag});
16351616 }
16361617
16371618 // Enum field (regression test, we were previously getting the field name in an
......@@ -1661,7 +1642,7 @@ test "std.zon structs" {
16611642 \\1:1: error: types are not available in ZON
16621643 \\1:1: note: replace the type with '.'
16631644 \\
1664 , "{}", .{diag});
1645 , "{f}", .{diag});
16651646 }
16661647
16671648 // Arrays
......@@ -1674,7 +1655,7 @@ test "std.zon structs" {
16741655 \\1:1: error: types are not available in ZON
16751656 \\1:1: note: replace the type with '.'
16761657 \\
1677 , "{}", .{diag});
1658 , "{f}", .{diag});
16781659 }
16791660
16801661 // Slices
......@@ -1687,7 +1668,7 @@ test "std.zon structs" {
16871668 \\1:1: error: types are not available in ZON
16881669 \\1:1: note: replace the type with '.'
16891670 \\
1690 , "{}", .{diag});
1671 , "{f}", .{diag});
16911672 }
16921673
16931674 // Tuples
......@@ -1706,7 +1687,7 @@ test "std.zon structs" {
17061687 \\1:1: error: types are not available in ZON
17071688 \\1:1: note: replace the type with '.'
17081689 \\
1709 , "{}", .{diag});
1690 , "{f}", .{diag});
17101691 }
17111692
17121693 // Nested
......@@ -1719,7 +1700,7 @@ test "std.zon structs" {
17191700 \\1:9: error: types are not available in ZON
17201701 \\1:9: note: replace the type with '.'
17211702 \\
1722 , "{}", .{diag});
1703 , "{f}", .{diag});
17231704 }
17241705 }
17251706}
......@@ -1764,7 +1745,7 @@ test "std.zon tuples" {
17641745 error.ParseZon,
17651746 fromSlice(Tuple, gpa, ".{0.5, true, 123}", &diag, .{}),
17661747 );
1767 try std.testing.expectFmt("1:14: error: index 2 outside of tuple length 2\n", "{}", .{diag});
1748 try std.testing.expectFmt("1:14: error: index 2 outside of tuple length 2\n", "{f}", .{diag});
17681749 }
17691750
17701751 // Extra field
......@@ -1778,7 +1759,7 @@ test "std.zon tuples" {
17781759 );
17791760 try std.testing.expectFmt(
17801761 "1:2: error: missing tuple field with index 1\n",
1781 "{}",
1762 "{f}",
17821763 .{diag},
17831764 );
17841765 }
......@@ -1792,7 +1773,7 @@ test "std.zon tuples" {
17921773 error.ParseZon,
17931774 fromSlice(Tuple, gpa, ".{.foo = 10.0}", &diag, .{}),
17941775 );
1795 try std.testing.expectFmt("1:2: error: expected tuple\n", "{}", .{diag});
1776 try std.testing.expectFmt("1:2: error: expected tuple\n", "{f}", .{diag});
17961777 }
17971778
17981779 // Struct with missing field names
......@@ -1804,7 +1785,7 @@ test "std.zon tuples" {
18041785 error.ParseZon,
18051786 fromSlice(Struct, gpa, ".{10.0}", &diag, .{}),
18061787 );
1807 try std.testing.expectFmt("1:2: error: expected struct\n", "{}", .{diag});
1788 try std.testing.expectFmt("1:2: error: expected struct\n", "{f}", .{diag});
18081789 }
18091790
18101791 // Comptime field
......@@ -1824,7 +1805,7 @@ test "std.zon tuples" {
18241805 try std.testing.expectFmt(
18251806 \\1:9: error: cannot initialize comptime field
18261807 \\
1827 , "{}", .{diag});
1808 , "{f}", .{diag});
18281809 }
18291810}
18301811
......@@ -1936,7 +1917,7 @@ test "std.zon arrays and slices" {
19361917 );
19371918 try std.testing.expectFmt(
19381919 "1:3: error: index 0 outside of array of length 0\n",
1939 "{}",
1920 "{f}",
19401921 .{diag},
19411922 );
19421923 }
......@@ -1951,7 +1932,7 @@ test "std.zon arrays and slices" {
19511932 );
19521933 try std.testing.expectFmt(
19531934 "1:8: error: index 1 outside of array of length 1\n",
1954 "{}",
1935 "{f}",
19551936 .{diag},
19561937 );
19571938 }
......@@ -1966,7 +1947,7 @@ test "std.zon arrays and slices" {
19661947 );
19671948 try std.testing.expectFmt(
19681949 "1:2: error: expected 2 array elements; found 1\n",
1969 "{}",
1950 "{f}",
19701951 .{diag},
19711952 );
19721953 }
......@@ -1981,7 +1962,7 @@ test "std.zon arrays and slices" {
19811962 );
19821963 try std.testing.expectFmt(
19831964 "1:2: error: expected 3 array elements; found 0\n",
1984 "{}",
1965 "{f}",
19851966 .{diag},
19861967 );
19871968 }
......@@ -1996,7 +1977,7 @@ test "std.zon arrays and slices" {
19961977 error.ParseZon,
19971978 fromSlice([3]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
19981979 );
1999 try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{}", .{diag});
1980 try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag});
20001981 }
20011982
20021983 // Slice
......@@ -2007,7 +1988,7 @@ test "std.zon arrays and slices" {
20071988 error.ParseZon,
20081989 fromSlice([]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}),
20091990 );
2010 try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{}", .{diag});
1991 try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag});
20111992 }
20121993 }
20131994
......@@ -2021,7 +2002,7 @@ test "std.zon arrays and slices" {
20212002 error.ParseZon,
20222003 fromSlice([3]u8, gpa, "'a'", &diag, .{}),
20232004 );
2024 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2005 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
20252006 }
20262007
20272008 // Slice
......@@ -2032,7 +2013,7 @@ test "std.zon arrays and slices" {
20322013 error.ParseZon,
20332014 fromSlice([]u8, gpa, "'a'", &diag, .{}),
20342015 );
2035 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2016 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
20362017 }
20372018 }
20382019
......@@ -2046,7 +2027,7 @@ test "std.zon arrays and slices" {
20462027 );
20472028 try std.testing.expectFmt(
20482029 "1:3: error: pointers are not available in ZON\n",
2049 "{}",
2030 "{f}",
20502031 .{diag},
20512032 );
20522033 }
......@@ -2085,7 +2066,7 @@ test "std.zon string literal" {
20852066 error.ParseZon,
20862067 fromSlice([]u8, gpa, "\"abcd\"", &diag, .{}),
20872068 );
2088 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2069 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
20892070 }
20902071
20912072 {
......@@ -2095,7 +2076,7 @@ test "std.zon string literal" {
20952076 error.ParseZon,
20962077 fromSlice([]u8, gpa, "\\\\abcd", &diag, .{}),
20972078 );
2098 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2079 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
20992080 }
21002081 }
21012082
......@@ -2112,7 +2093,7 @@ test "std.zon string literal" {
21122093 error.ParseZon,
21132094 fromSlice([4:0]u8, gpa, "\"abcd\"", &diag, .{}),
21142095 );
2115 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2096 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
21162097 }
21172098
21182099 {
......@@ -2122,7 +2103,7 @@ test "std.zon string literal" {
21222103 error.ParseZon,
21232104 fromSlice([4:0]u8, gpa, "\\\\abcd", &diag, .{}),
21242105 );
2125 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2106 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
21262107 }
21272108 }
21282109
......@@ -2164,7 +2145,7 @@ test "std.zon string literal" {
21642145 error.ParseZon,
21652146 fromSlice([:1]const u8, gpa, "\"foo\"", &diag, .{}),
21662147 );
2167 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2148 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
21682149 }
21692150
21702151 {
......@@ -2174,7 +2155,7 @@ test "std.zon string literal" {
21742155 error.ParseZon,
21752156 fromSlice([:1]const u8, gpa, "\\\\foo", &diag, .{}),
21762157 );
2177 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2158 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
21782159 }
21792160 }
21802161
......@@ -2186,7 +2167,7 @@ test "std.zon string literal" {
21862167 error.ParseZon,
21872168 fromSlice([]const u8, gpa, "true", &diag, .{}),
21882169 );
2189 try std.testing.expectFmt("1:1: error: expected string\n", "{}", .{diag});
2170 try std.testing.expectFmt("1:1: error: expected string\n", "{f}", .{diag});
21902171 }
21912172
21922173 // Expecting string literal, getting an incompatible tuple
......@@ -2197,7 +2178,7 @@ test "std.zon string literal" {
21972178 error.ParseZon,
21982179 fromSlice([]const u8, gpa, ".{false}", &diag, .{}),
21992180 );
2200 try std.testing.expectFmt("1:3: error: expected type 'u8'\n", "{}", .{diag});
2181 try std.testing.expectFmt("1:3: error: expected type 'u8'\n", "{f}", .{diag});
22012182 }
22022183
22032184 // Invalid string literal
......@@ -2208,7 +2189,7 @@ test "std.zon string literal" {
22082189 error.ParseZon,
22092190 fromSlice([]const i8, gpa, "\"\\a\"", &diag, .{}),
22102191 );
2211 try std.testing.expectFmt("1:3: error: invalid escape character: 'a'\n", "{}", .{diag});
2192 try std.testing.expectFmt("1:3: error: invalid escape character: 'a'\n", "{f}", .{diag});
22122193 }
22132194
22142195 // Slice wrong child type
......@@ -2220,7 +2201,7 @@ test "std.zon string literal" {
22202201 error.ParseZon,
22212202 fromSlice([]const i8, gpa, "\"a\"", &diag, .{}),
22222203 );
2223 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2204 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
22242205 }
22252206
22262207 {
......@@ -2230,7 +2211,7 @@ test "std.zon string literal" {
22302211 error.ParseZon,
22312212 fromSlice([]const i8, gpa, "\\\\a", &diag, .{}),
22322213 );
2233 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2214 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
22342215 }
22352216 }
22362217
......@@ -2243,7 +2224,7 @@ test "std.zon string literal" {
22432224 error.ParseZon,
22442225 fromSlice([]align(2) const u8, gpa, "\"abc\"", &diag, .{}),
22452226 );
2246 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2227 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
22472228 }
22482229
22492230 {
......@@ -2253,7 +2234,7 @@ test "std.zon string literal" {
22532234 error.ParseZon,
22542235 fromSlice([]align(2) const u8, gpa, "\\\\abc", &diag, .{}),
22552236 );
2256 try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag});
2237 try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag});
22572238 }
22582239 }
22592240
......@@ -2327,7 +2308,7 @@ test "std.zon enum literals" {
23272308 \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
23282309 \\
23292310 ,
2330 "{}",
2311 "{f}",
23312312 .{diag},
23322313 );
23332314 }
......@@ -2345,7 +2326,7 @@ test "std.zon enum literals" {
23452326 \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"'
23462327 \\
23472328 ,
2348 "{}",
2329 "{f}",
23492330 .{diag},
23502331 );
23512332 }
......@@ -2358,7 +2339,7 @@ test "std.zon enum literals" {
23582339 error.ParseZon,
23592340 fromSlice(Enum, gpa, "true", &diag, .{}),
23602341 );
2361 try std.testing.expectFmt("1:1: error: expected enum literal\n", "{}", .{diag});
2342 try std.testing.expectFmt("1:1: error: expected enum literal\n", "{f}", .{diag});
23622343 }
23632344
23642345 // Test embedded nulls in an identifier
......@@ -2371,7 +2352,7 @@ test "std.zon enum literals" {
23712352 );
23722353 try std.testing.expectFmt(
23732354 "1:2: error: identifier cannot contain null bytes\n",
2374 "{}",
2355 "{f}",
23752356 .{diag},
23762357 );
23772358 }
......@@ -2397,13 +2378,13 @@ test "std.zon parse bool" {
23972378 \\1:2: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
23982379 \\1:2: note: precede identifier with '.' for an enum literal
23992380 \\
2400 , "{}", .{diag});
2381 , "{f}", .{diag});
24012382 }
24022383 {
24032384 var diag: Diagnostics = .{};
24042385 defer diag.deinit(gpa);
24052386 try std.testing.expectError(error.ParseZon, fromSlice(bool, gpa, "123", &diag, .{}));
2406 try std.testing.expectFmt("1:1: error: expected type 'bool'\n", "{}", .{diag});
2387 try std.testing.expectFmt("1:1: error: expected type 'bool'\n", "{f}", .{diag});
24072388 }
24082389}
24092390
......@@ -2476,7 +2457,7 @@ test "std.zon parse int" {
24762457 ));
24772458 try std.testing.expectFmt(
24782459 "1:1: error: type 'i66' cannot represent value\n",
2479 "{}",
2460 "{f}",
24802461 .{diag},
24812462 );
24822463 }
......@@ -2492,7 +2473,7 @@ test "std.zon parse int" {
24922473 ));
24932474 try std.testing.expectFmt(
24942475 "1:1: error: type 'i66' cannot represent value\n",
2495 "{}",
2476 "{f}",
24962477 .{diag},
24972478 );
24982479 }
......@@ -2581,7 +2562,7 @@ test "std.zon parse int" {
25812562 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "32a32", &diag, .{}));
25822563 try std.testing.expectFmt(
25832564 "1:3: error: invalid digit 'a' for decimal base\n",
2584 "{}",
2565 "{f}",
25852566 .{diag},
25862567 );
25872568 }
......@@ -2591,7 +2572,7 @@ test "std.zon parse int" {
25912572 var diag: Diagnostics = .{};
25922573 defer diag.deinit(gpa);
25932574 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "true", &diag, .{}));
2594 try std.testing.expectFmt("1:1: error: expected type 'u8'\n", "{}", .{diag});
2575 try std.testing.expectFmt("1:1: error: expected type 'u8'\n", "{f}", .{diag});
25952576 }
25962577
25972578 // Failing because an int is out of range
......@@ -2601,7 +2582,7 @@ test "std.zon parse int" {
26012582 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "256", &diag, .{}));
26022583 try std.testing.expectFmt(
26032584 "1:1: error: type 'u8' cannot represent value\n",
2604 "{}",
2585 "{f}",
26052586 .{diag},
26062587 );
26072588 }
......@@ -2613,7 +2594,7 @@ test "std.zon parse int" {
26132594 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-129", &diag, .{}));
26142595 try std.testing.expectFmt(
26152596 "1:1: error: type 'i8' cannot represent value\n",
2616 "{}",
2597 "{f}",
26172598 .{diag},
26182599 );
26192600 }
......@@ -2625,7 +2606,7 @@ test "std.zon parse int" {
26252606 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1", &diag, .{}));
26262607 try std.testing.expectFmt(
26272608 "1:1: error: type 'u8' cannot represent value\n",
2628 "{}",
2609 "{f}",
26292610 .{diag},
26302611 );
26312612 }
......@@ -2637,7 +2618,7 @@ test "std.zon parse int" {
26372618 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "1.5", &diag, .{}));
26382619 try std.testing.expectFmt(
26392620 "1:1: error: type 'u8' cannot represent value\n",
2640 "{}",
2621 "{f}",
26412622 .{diag},
26422623 );
26432624 }
......@@ -2649,7 +2630,7 @@ test "std.zon parse int" {
26492630 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1.0", &diag, .{}));
26502631 try std.testing.expectFmt(
26512632 "1:1: error: type 'u8' cannot represent value\n",
2652 "{}",
2633 "{f}",
26532634 .{diag},
26542635 );
26552636 }
......@@ -2664,7 +2645,7 @@ test "std.zon parse int" {
26642645 \\1:2: note: use '0' for an integer zero
26652646 \\1:2: note: use '-0.0' for a floating-point signed zero
26662647 \\
2667 , "{}", .{diag});
2648 , "{f}", .{diag});
26682649 }
26692650
26702651 // Negative integer zero casted to float
......@@ -2677,7 +2658,7 @@ test "std.zon parse int" {
26772658 \\1:2: note: use '0' for an integer zero
26782659 \\1:2: note: use '-0.0' for a floating-point signed zero
26792660 \\
2680 , "{}", .{diag});
2661 , "{f}", .{diag});
26812662 }
26822663
26832664 // Negative float 0 is allowed
......@@ -2693,7 +2674,7 @@ test "std.zon parse int" {
26932674 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "--2", &diag, .{}));
26942675 try std.testing.expectFmt(
26952676 "1:1: error: expected number or 'inf' after '-'\n",
2696 "{}",
2677 "{f}",
26972678 .{diag},
26982679 );
26992680 }
......@@ -2707,7 +2688,7 @@ test "std.zon parse int" {
27072688 );
27082689 try std.testing.expectFmt(
27092690 "1:1: error: expected number or 'inf' after '-'\n",
2710 "{}",
2691 "{f}",
27112692 .{diag},
27122693 );
27132694 }
......@@ -2717,7 +2698,7 @@ test "std.zon parse int" {
27172698 var diag: Diagnostics = .{};
27182699 defer diag.deinit(gpa);
27192700 try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "0xg", &diag, .{}));
2720 try std.testing.expectFmt("1:3: error: invalid digit 'g' for hex base\n", "{}", .{diag});
2701 try std.testing.expectFmt("1:3: error: invalid digit 'g' for hex base\n", "{f}", .{diag});
27212702 }
27222703
27232704 // Notes on invalid int literal
......@@ -2729,7 +2710,7 @@ test "std.zon parse int" {
27292710 \\1:1: error: number '0123' has leading zero
27302711 \\1:1: note: use '0o' prefix for octal literals
27312712 \\
2732 , "{}", .{diag});
2713 , "{f}", .{diag});
27332714 }
27342715}
27352716
......@@ -2742,7 +2723,7 @@ test "std.zon negative char" {
27422723 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-'a'", &diag, .{}));
27432724 try std.testing.expectFmt(
27442725 "1:1: error: expected number or 'inf' after '-'\n",
2745 "{}",
2726 "{f}",
27462727 .{diag},
27472728 );
27482729 }
......@@ -2752,7 +2733,7 @@ test "std.zon negative char" {
27522733 try std.testing.expectError(error.ParseZon, fromSlice(i16, gpa, "-'a'", &diag, .{}));
27532734 try std.testing.expectFmt(
27542735 "1:1: error: expected number or 'inf' after '-'\n",
2755 "{}",
2736 "{f}",
27562737 .{diag},
27572738 );
27582739 }
......@@ -2841,7 +2822,7 @@ test "std.zon parse float" {
28412822 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-nan", &diag, .{}));
28422823 try std.testing.expectFmt(
28432824 "1:1: error: expected number or 'inf' after '-'\n",
2844 "{}",
2825 "{f}",
28452826 .{diag},
28462827 );
28472828 }
......@@ -2851,7 +2832,7 @@ test "std.zon parse float" {
28512832 var diag: Diagnostics = .{};
28522833 defer diag.deinit(gpa);
28532834 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{}));
2854 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{}", .{diag});
2835 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
28552836 }
28562837
28572838 // nan as int not allowed
......@@ -2859,7 +2840,7 @@ test "std.zon parse float" {
28592840 var diag: Diagnostics = .{};
28602841 defer diag.deinit(gpa);
28612842 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{}));
2862 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{}", .{diag});
2843 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
28632844 }
28642845
28652846 // inf as int not allowed
......@@ -2867,7 +2848,7 @@ test "std.zon parse float" {
28672848 var diag: Diagnostics = .{};
28682849 defer diag.deinit(gpa);
28692850 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "inf", &diag, .{}));
2870 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{}", .{diag});
2851 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
28712852 }
28722853
28732854 // -inf as int not allowed
......@@ -2875,7 +2856,7 @@ test "std.zon parse float" {
28752856 var diag: Diagnostics = .{};
28762857 defer diag.deinit(gpa);
28772858 try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-inf", &diag, .{}));
2878 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{}", .{diag});
2859 try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag});
28792860 }
28802861
28812862 // Bad identifier as float
......@@ -2888,7 +2869,7 @@ test "std.zon parse float" {
28882869 \\1:1: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan'
28892870 \\1:1: note: precede identifier with '.' for an enum literal
28902871 \\
2891 , "{}", .{diag});
2872 , "{f}", .{diag});
28922873 }
28932874
28942875 {
......@@ -2897,7 +2878,7 @@ test "std.zon parse float" {
28972878 try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-foo", &diag, .{}));
28982879 try std.testing.expectFmt(
28992880 "1:1: error: expected number or 'inf' after '-'\n",
2900 "{}",
2881 "{f}",
29012882 .{diag},
29022883 );
29032884 }
......@@ -2910,7 +2891,7 @@ test "std.zon parse float" {
29102891 error.ParseZon,
29112892 fromSlice(f32, gpa, "\"foo\"", &diag, .{}),
29122893 );
2913 try std.testing.expectFmt("1:1: error: expected type 'f32'\n", "{}", .{diag});
2894 try std.testing.expectFmt("1:1: error: expected type 'f32'\n", "{f}", .{diag});
29142895 }
29152896}
29162897
......@@ -3154,7 +3135,7 @@ test "std.zon vector" {
31543135 );
31553136 try std.testing.expectFmt(
31563137 "1:2: error: expected 2 vector elements; found 1\n",
3157 "{}",
3138 "{f}",
31583139 .{diag},
31593140 );
31603141 }
......@@ -3169,7 +3150,7 @@ test "std.zon vector" {
31693150 );
31703151 try std.testing.expectFmt(
31713152 "1:2: error: expected 2 vector elements; found 3\n",
3172 "{}",
3153 "{f}",
31733154 .{diag},
31743155 );
31753156 }
......@@ -3184,7 +3165,7 @@ test "std.zon vector" {
31843165 );
31853166 try std.testing.expectFmt(
31863167 "1:8: error: expected type 'f32'\n",
3187 "{}",
3168 "{f}",
31883169 .{diag},
31893170 );
31903171 }
......@@ -3197,7 +3178,7 @@ test "std.zon vector" {
31973178 error.ParseZon,
31983179 fromSlice(@Vector(3, u8), gpa, "true", &diag, .{}),
31993180 );
3200 try std.testing.expectFmt("1:1: error: expected type '@Vector(3, u8)'\n", "{}", .{diag});
3181 try std.testing.expectFmt("1:1: error: expected type '@Vector(3, u8)'\n", "{f}", .{diag});
32013182 }
32023183
32033184 // Elements should get freed on error
......@@ -3208,7 +3189,7 @@ test "std.zon vector" {
32083189 error.ParseZon,
32093190 fromSlice(@Vector(3, *u8), gpa, ".{1, true, 3}", &diag, .{}),
32103191 );
3211 try std.testing.expectFmt("1:6: error: expected type 'u8'\n", "{}", .{diag});
3192 try std.testing.expectFmt("1:6: error: expected type 'u8'\n", "{f}", .{diag});
32123193 }
32133194}
32143195
......@@ -3332,7 +3313,7 @@ test "std.zon add pointers" {
33323313 error.ParseZon,
33333314 fromSlice(*const ?*const u8, gpa, "true", &diag, .{}),
33343315 );
3335 try std.testing.expectFmt("1:1: error: expected type '?u8'\n", "{}", .{diag});
3316 try std.testing.expectFmt("1:1: error: expected type '?u8'\n", "{f}", .{diag});
33363317 }
33373318
33383319 {
......@@ -3342,7 +3323,7 @@ test "std.zon add pointers" {
33423323 error.ParseZon,
33433324 fromSlice(*const ?*const f32, gpa, "true", &diag, .{}),
33443325 );
3345 try std.testing.expectFmt("1:1: error: expected type '?f32'\n", "{}", .{diag});
3326 try std.testing.expectFmt("1:1: error: expected type '?f32'\n", "{f}", .{diag});
33463327 }
33473328
33483329 {
......@@ -3352,7 +3333,7 @@ test "std.zon add pointers" {
33523333 error.ParseZon,
33533334 fromSlice(*const ?*const @Vector(3, u8), gpa, "true", &diag, .{}),
33543335 );
3355 try std.testing.expectFmt("1:1: error: expected type '?@Vector(3, u8)'\n", "{}", .{diag});
3336 try std.testing.expectFmt("1:1: error: expected type '?@Vector(3, u8)'\n", "{f}", .{diag});
33563337 }
33573338
33583339 {
......@@ -3362,7 +3343,7 @@ test "std.zon add pointers" {
33623343 error.ParseZon,
33633344 fromSlice(*const ?*const bool, gpa, "10", &diag, .{}),
33643345 );
3365 try std.testing.expectFmt("1:1: error: expected type '?bool'\n", "{}", .{diag});
3346 try std.testing.expectFmt("1:1: error: expected type '?bool'\n", "{f}", .{diag});
33663347 }
33673348
33683349 {
......@@ -3372,7 +3353,7 @@ test "std.zon add pointers" {
33723353 error.ParseZon,
33733354 fromSlice(*const ?*const struct { a: i32 }, gpa, "true", &diag, .{}),
33743355 );
3375 try std.testing.expectFmt("1:1: error: expected optional struct\n", "{}", .{diag});
3356 try std.testing.expectFmt("1:1: error: expected optional struct\n", "{f}", .{diag});
33763357 }
33773358
33783359 {
......@@ -3382,7 +3363,7 @@ test "std.zon add pointers" {
33823363 error.ParseZon,
33833364 fromSlice(*const ?*const struct { i32 }, gpa, "true", &diag, .{}),
33843365 );
3385 try std.testing.expectFmt("1:1: error: expected optional tuple\n", "{}", .{diag});
3366 try std.testing.expectFmt("1:1: error: expected optional tuple\n", "{f}", .{diag});
33863367 }
33873368
33883369 {
......@@ -3392,7 +3373,7 @@ test "std.zon add pointers" {
33923373 error.ParseZon,
33933374 fromSlice(*const ?*const union { x: void }, gpa, "true", &diag, .{}),
33943375 );
3395 try std.testing.expectFmt("1:1: error: expected optional union\n", "{}", .{diag});
3376 try std.testing.expectFmt("1:1: error: expected optional union\n", "{f}", .{diag});
33963377 }
33973378
33983379 {
......@@ -3402,7 +3383,7 @@ test "std.zon add pointers" {
34023383 error.ParseZon,
34033384 fromSlice(*const ?*const [3]u8, gpa, "true", &diag, .{}),
34043385 );
3405 try std.testing.expectFmt("1:1: error: expected optional array\n", "{}", .{diag});
3386 try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
34063387 }
34073388
34083389 {
......@@ -3412,7 +3393,7 @@ test "std.zon add pointers" {
34123393 error.ParseZon,
34133394 fromSlice(?[3]u8, gpa, "true", &diag, .{}),
34143395 );
3415 try std.testing.expectFmt("1:1: error: expected optional array\n", "{}", .{diag});
3396 try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
34163397 }
34173398
34183399 {
......@@ -3422,7 +3403,7 @@ test "std.zon add pointers" {
34223403 error.ParseZon,
34233404 fromSlice(*const ?*const []u8, gpa, "true", &diag, .{}),
34243405 );
3425 try std.testing.expectFmt("1:1: error: expected optional array\n", "{}", .{diag});
3406 try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
34263407 }
34273408
34283409 {
......@@ -3432,7 +3413,7 @@ test "std.zon add pointers" {
34323413 error.ParseZon,
34333414 fromSlice(?[]u8, gpa, "true", &diag, .{}),
34343415 );
3435 try std.testing.expectFmt("1:1: error: expected optional array\n", "{}", .{diag});
3416 try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag});
34363417 }
34373418
34383419 {
......@@ -3442,7 +3423,7 @@ test "std.zon add pointers" {
34423423 error.ParseZon,
34433424 fromSlice(*const ?*const []const u8, gpa, "true", &diag, .{}),
34443425 );
3445 try std.testing.expectFmt("1:1: error: expected optional string\n", "{}", .{diag});
3426 try std.testing.expectFmt("1:1: error: expected optional string\n", "{f}", .{diag});
34463427 }
34473428
34483429 {
......@@ -3452,7 +3433,7 @@ test "std.zon add pointers" {
34523433 error.ParseZon,
34533434 fromSlice(*const ?*const enum { foo }, gpa, "true", &diag, .{}),
34543435 );
3455 try std.testing.expectFmt("1:1: error: expected optional enum literal\n", "{}", .{diag});
3436 try std.testing.expectFmt("1:1: error: expected optional enum literal\n", "{f}", .{diag});
34563437 }
34573438}
34583439
lib/std/zon/stringify.zig+5-4
......@@ -615,7 +615,8 @@ pub fn Serializer(Writer: type) type {
615615
616616 /// Serialize an integer.
617617 pub fn int(self: *Self, val: anytype) Writer.Error!void {
618 try std.fmt.formatInt(val, 10, .lower, .{}, self.writer);
618 //try self.writer.printInt(val, 10, .lower, .{});
619 try std.fmt.format(self.writer, "{d}", .{val});
619620 }
620621
621622 /// Serialize a float.
......@@ -645,7 +646,7 @@ pub fn Serializer(Writer: type) type {
645646 ///
646647 /// Escapes the identifier if necessary.
647648 pub fn ident(self: *Self, name: []const u8) Writer.Error!void {
648 try self.writer.print(".{p_}", .{std.zig.fmtId(name)});
649 try self.writer.print(".{f}", .{std.zig.fmtIdPU(name)});
649650 }
650651
651652 /// Serialize `val` as a Unicode codepoint.
......@@ -658,7 +659,7 @@ pub fn Serializer(Writer: type) type {
658659 var buf: [8]u8 = undefined;
659660 const len = std.unicode.utf8Encode(val, &buf) catch return error.InvalidCodepoint;
660661 const str = buf[0..len];
661 try std.fmt.format(self.writer, "'{'}'", .{std.zig.fmtEscapes(str)});
662 try std.fmt.format(self.writer, "'{f}'", .{std.zig.fmtChar(str)});
662663 }
663664
664665 /// Like `value`, but always serializes `val` as a tuple.
......@@ -716,7 +717,7 @@ pub fn Serializer(Writer: type) type {
716717
717718 /// Like `value`, but always serializes `val` as a string.
718719 pub fn string(self: *Self, val: []const u8) Writer.Error!void {
719 try std.fmt.format(self.writer, "\"{}\"", .{std.zig.fmtEscapes(val)});
720 try std.fmt.format(self.writer, "\"{f}\"", .{std.zig.fmtString(val)});
720721 }
721722
722723 /// Options for formatting multiline strings.
lib/ubsan_rt.zig+37-60
......@@ -119,14 +119,7 @@ const Value = extern struct {
119119 }
120120 }
121121
122 pub fn format(
123 value: Value,
124 comptime fmt: []const u8,
125 _: std.fmt.FormatOptions,
126 writer: anytype,
127 ) !void {
128 comptime assert(fmt.len == 0);
129
122 pub fn format(value: Value, writer: *std.io.Writer) std.io.Writer.Error!void {
130123 // Work around x86_64 backend limitation.
131124 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) {
132125 try writer.writeAll("(unknown)");
......@@ -136,12 +129,12 @@ const Value = extern struct {
136129 switch (value.td.kind) {
137130 .integer => {
138131 if (value.td.isSigned()) {
139 try writer.print("{}", .{value.getSignedInteger()});
132 try writer.print("{d}", .{value.getSignedInteger()});
140133 } else {
141 try writer.print("{}", .{value.getUnsignedInteger()});
134 try writer.print("{d}", .{value.getUnsignedInteger()});
142135 }
143136 },
144 .float => try writer.print("{}", .{value.getFloat()}),
137 .float => try writer.print("{d}", .{value.getFloat()}),
145138 .unknown => try writer.writeAll("(unknown)"),
146139 }
147140 }
......@@ -172,17 +165,12 @@ fn overflowHandler(
172165 ) callconv(.c) noreturn {
173166 const lhs: Value = .{ .handle = lhs_handle, .td = data.td };
174167 const rhs: Value = .{ .handle = rhs_handle, .td = data.td };
175
176 const is_signed = data.td.isSigned();
177 const fmt = "{s} integer overflow: " ++ "{} " ++
178 operator ++ " {} cannot be represented in type {s}";
179
180 panic(@returnAddress(), fmt, .{
181 if (is_signed) "signed" else "unsigned",
182 lhs,
183 rhs,
184 data.td.getName(),
185 });
168 const signed_str = if (data.td.isSigned()) "signed" else "unsigned";
169 panic(
170 @returnAddress(),
171 "{s} integer overflow: {f} " ++ operator ++ " {f} cannot be represented in type {s}",
172 .{ signed_str, lhs, rhs, data.td.getName() },
173 );
186174 }
187175 };
188176
......@@ -201,11 +189,9 @@ fn negationHandler(
201189 value_handle: ValueHandle,
202190) callconv(.c) noreturn {
203191 const value: Value = .{ .handle = value_handle, .td = data.td };
204 panic(
205 @returnAddress(),
206 "negation of {} cannot be represented in type {s}",
207 .{ value, data.td.getName() },
208 );
192 panic(@returnAddress(), "negation of {f} cannot be represented in type {s}", .{
193 value, data.td.getName(),
194 });
209195}
210196
211197fn divRemHandlerAbort(
......@@ -225,11 +211,9 @@ fn divRemHandler(
225211 const rhs: Value = .{ .handle = rhs_handle, .td = data.td };
226212
227213 if (rhs.isMinusOne()) {
228 panic(
229 @returnAddress(),
230 "division of {} by -1 cannot be represented in type {s}",
231 .{ lhs, data.td.getName() },
232 );
214 panic(@returnAddress(), "division of {f} by -1 cannot be represented in type {s}", .{
215 lhs, data.td.getName(),
216 });
233217 } else panic(@returnAddress(), "division by zero", .{});
234218}
235219
......@@ -269,8 +253,8 @@ fn alignmentAssumptionHandler(
269253 if (maybe_offset) |offset| {
270254 panic(
271255 @returnAddress(),
272 "assumption of {} byte alignment (with offset of {} byte) for pointer of type {s} failed\n" ++
273 "offset address is {} aligned, misalignment offset is {} bytes",
256 "assumption of {f} byte alignment (with offset of {d} byte) for pointer of type {s} failed\n" ++
257 "offset address is {d} aligned, misalignment offset is {d} bytes",
274258 .{
275259 alignment,
276260 @intFromPtr(offset),
......@@ -282,8 +266,8 @@ fn alignmentAssumptionHandler(
282266 } else {
283267 panic(
284268 @returnAddress(),
285 "assumption of {} byte alignment for pointer of type {s} failed\n" ++
286 "address is {} aligned, misalignment offset is {} bytes",
269 "assumption of {f} byte alignment for pointer of type {s} failed\n" ++
270 "address is {d} aligned, misalignment offset is {d} bytes",
287271 .{
288272 alignment,
289273 data.td.getName(),
......@@ -320,21 +304,21 @@ fn shiftOob(
320304 rhs.getPositiveInteger() >= data.lhs_type.getIntegerSize())
321305 {
322306 if (rhs.isNegative()) {
323 panic(@returnAddress(), "shift exponent {} is negative", .{rhs});
307 panic(@returnAddress(), "shift exponent {f} is negative", .{rhs});
324308 } else {
325309 panic(
326310 @returnAddress(),
327 "shift exponent {} is too large for {}-bit type {s}",
311 "shift exponent {f} is too large for {d}-bit type {s}",
328312 .{ rhs, data.lhs_type.getIntegerSize(), data.lhs_type.getName() },
329313 );
330314 }
331315 } else {
332316 if (lhs.isNegative()) {
333 panic(@returnAddress(), "left shift of negative value {}", .{lhs});
317 panic(@returnAddress(), "left shift of negative value {f}", .{lhs});
334318 } else {
335319 panic(
336320 @returnAddress(),
337 "left shift of {} by {} places cannot be represented in type {s}",
321 "left shift of {f} by {f} places cannot be represented in type {s}",
338322 .{ lhs, rhs, data.lhs_type.getName() },
339323 );
340324 }
......@@ -359,11 +343,10 @@ fn outOfBounds(
359343 index_handle: ValueHandle,
360344) callconv(.c) noreturn {
361345 const index: Value = .{ .handle = index_handle, .td = data.index_type };
362 panic(
363 @returnAddress(),
364 "index {} out of bounds for type {s}",
365 .{ index, data.array_type.getName() },
366 );
346 panic(@returnAddress(), "index {f} out of bounds for type {s}", .{
347 index,
348 data.array_type.getName(),
349 });
367350}
368351
369352const PointerOverflowData = extern struct {
......@@ -387,7 +370,7 @@ fn pointerOverflow(
387370 if (result == 0) {
388371 panic(@returnAddress(), "applying zero offset to null pointer", .{});
389372 } else {
390 panic(@returnAddress(), "applying non-zero offset {} to null pointer", .{result});
373 panic(@returnAddress(), "applying non-zero offset {d} to null pointer", .{result});
391374 }
392375 } else {
393376 if (result == 0) {
......@@ -483,7 +466,7 @@ fn typeMismatch(
483466 } else if (!std.mem.isAligned(handle, alignment)) {
484467 panic(
485468 @returnAddress(),
486 "{s} misaligned address 0x{x} for type {s}, which requires {} byte alignment",
469 "{s} misaligned address 0x{x} for type {s}, which requires {d} byte alignment",
487470 .{ data.kind.getName(), handle, data.td.getName(), alignment },
488471 );
489472 } else {
......@@ -531,7 +514,7 @@ fn nonNullArgAbort(data: *const NonNullArgData) callconv(.c) noreturn {
531514fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn {
532515 panic(
533516 @returnAddress(),
534 "null pointer passed as argument {}, which is declared to never be null",
517 "null pointer passed as argument {d}, which is declared to never be null",
535518 .{data.arg_index},
536519 );
537520}
......@@ -553,11 +536,9 @@ fn loadInvalidValue(
553536 value_handle: ValueHandle,
554537) callconv(.c) noreturn {
555538 const value: Value = .{ .handle = value_handle, .td = data.td };
556 panic(
557 @returnAddress(),
558 "load of value {}, which is not valid for type {s}",
559 .{ value, data.td.getName() },
560 );
539 panic(@returnAddress(), "load of value {f}, which is not valid for type {s}", .{
540 value, data.td.getName(),
541 });
561542}
562543
563544const InvalidBuiltinData = extern struct {
......@@ -596,11 +577,7 @@ fn vlaBoundNotPositive(
596577 bound_handle: ValueHandle,
597578) callconv(.c) noreturn {
598579 const bound: Value = .{ .handle = bound_handle, .td = data.td };
599 panic(
600 @returnAddress(),
601 "variable length array bound evaluates to non-positive value {}",
602 .{bound},
603 );
580 panic(@returnAddress(), "variable length array bound evaluates to non-positive value {f}", .{bound});
604581}
605582
606583const FloatCastOverflowData = extern struct {
......@@ -631,13 +608,13 @@ fn floatCastOverflow(
631608 if (@as(u16, ptr[0]) + @as(u16, ptr[1]) < 2 or ptr[0] == 0xFF or ptr[1] == 0xFF) {
632609 const data: *const FloatCastOverflowData = @ptrCast(data_handle);
633610 const from_value: Value = .{ .handle = from_handle, .td = data.from };
634 panic(@returnAddress(), "{} is outside the range of representable values of type {s}", .{
611 panic(@returnAddress(), "{f} is outside the range of representable values of type {s}", .{
635612 from_value, data.to.getName(),
636613 });
637614 } else {
638615 const data: *const FloatCastOverflowDataV2 = @ptrCast(data_handle);
639616 const from_value: Value = .{ .handle = from_handle, .td = data.from };
640 panic(@returnAddress(), "{} is outside the range of representable values of type {s}", .{
617 panic(@returnAddress(), "{f} is outside the range of representable values of type {s}", .{
641618 from_value, data.to.getName(),
642619 });
643620 }
src/Air.zig+8-9
......@@ -746,7 +746,9 @@ pub const Inst = struct {
746746 /// Dest slice may have any alignment; source pointer may have any alignment.
747747 /// The two memory regions must not overlap.
748748 /// Result type is always void.
749 ///
749750 /// Uses the `bin_op` field. LHS is the dest slice. RHS is the source pointer.
751 ///
750752 /// If the length is compile-time known (due to the destination or
751753 /// source being a pointer-to-array), then it is guaranteed to be
752754 /// greater than zero.
......@@ -758,7 +760,9 @@ pub const Inst = struct {
758760 /// Dest slice may have any alignment; source pointer may have any alignment.
759761 /// The two memory regions may overlap.
760762 /// Result type is always void.
763 ///
761764 /// Uses the `bin_op` field. LHS is the dest slice. RHS is the source pointer.
765 ///
762766 /// If the length is compile-time known (due to the destination or
763767 /// source being a pointer-to-array), then it is guaranteed to be
764768 /// greater than zero.
......@@ -957,18 +961,13 @@ pub const Inst = struct {
957961 return index.unwrap().target;
958962 }
959963
960 pub fn format(
961 index: Index,
962 comptime _: []const u8,
963 _: std.fmt.FormatOptions,
964 writer: anytype,
965 ) @TypeOf(writer).Error!void {
966 try writer.writeByte('%');
964 pub fn format(index: Index, w: *std.io.Writer) std.io.Writer.Error!void {
965 try w.writeByte('%');
967966 switch (index.unwrap()) {
968967 .ref => {},
969 .target => try writer.writeByte('t'),
968 .target => try w.writeByte('t'),
970969 }
971 try writer.print("{d}", .{@as(u31, @truncate(@intFromEnum(index)))});
970 try w.print("{d}", .{@as(u31, @truncate(@intFromEnum(index)))});
972971 }
973972 };
974973
src/Air/Liveness.zig+25-25
......@@ -1299,10 +1299,10 @@ fn analyzeOperands(
12991299
13001300 // This logic must synchronize with `will_die_immediately` in `AnalyzeBigOperands.init`.
13011301 const immediate_death = if (data.live_set.remove(inst)) blk: {
1302 log.debug("[{}] %{}: removed from live set", .{ pass, @intFromEnum(inst) });
1302 log.debug("[{}] %{d}: removed from live set", .{ pass, @intFromEnum(inst) });
13031303 break :blk false;
13041304 } else blk: {
1305 log.debug("[{}] %{}: immediate death", .{ pass, @intFromEnum(inst) });
1305 log.debug("[{}] %{d}: immediate death", .{ pass, @intFromEnum(inst) });
13061306 break :blk true;
13071307 };
13081308
......@@ -1323,7 +1323,7 @@ fn analyzeOperands(
13231323 const mask = @as(Bpi, 1) << @as(OperandInt, @intCast(i));
13241324
13251325 if ((try data.live_set.fetchPut(gpa, operand, {})) == null) {
1326 log.debug("[{}] %{}: added %{} to live set (operand dies here)", .{ pass, @intFromEnum(inst), operand });
1326 log.debug("[{}] %{d}: added %{d} to live set (operand dies here)", .{ pass, @intFromEnum(inst), operand });
13271327 tomb_bits |= mask;
13281328 }
13291329 }
......@@ -1462,19 +1462,19 @@ fn analyzeInstBlock(
14621462 },
14631463
14641464 .main_analysis => {
1465 log.debug("[{}] %{}: block live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) });
1465 log.debug("[{}] %{f}: block live set is {f}", .{ pass, inst, fmtInstSet(&data.live_set) });
14661466 // We can move the live set because the body should have a noreturn
14671467 // instruction which overrides the set.
14681468 try data.block_scopes.put(gpa, inst, .{
14691469 .live_set = data.live_set.move(),
14701470 });
14711471 defer {
1472 log.debug("[{}] %{}: popped block scope", .{ pass, inst });
1472 log.debug("[{}] %{f}: popped block scope", .{ pass, inst });
14731473 var scope = data.block_scopes.fetchRemove(inst).?.value;
14741474 scope.live_set.deinit(gpa);
14751475 }
14761476
1477 log.debug("[{}] %{}: pushed new block scope", .{ pass, inst });
1477 log.debug("[{}] %{f}: pushed new block scope", .{ pass, inst });
14781478 try analyzeBody(a, pass, data, body);
14791479
14801480 // If the block is noreturn, block deaths not only aren't useful, they're impossible to
......@@ -1501,7 +1501,7 @@ fn analyzeInstBlock(
15011501 }
15021502 assert(measured_num == num_deaths); // post-live-set should be a subset of pre-live-set
15031503 try a.special.put(gpa, inst, extra_index);
1504 log.debug("[{}] %{}: block deaths are {}", .{
1504 log.debug("[{}] %{f}: block deaths are {f}", .{
15051505 pass,
15061506 inst,
15071507 fmtInstList(@ptrCast(a.extra.items[extra_index + 1 ..][0..num_deaths])),
......@@ -1538,7 +1538,7 @@ fn writeLoopInfo(
15381538 const block_inst = key.*;
15391539 a.extra.appendAssumeCapacity(@intFromEnum(block_inst));
15401540 }
1541 log.debug("[{}] %{}: includes breaks to {}", .{ LivenessPass.loop_analysis, inst, fmtInstSet(&data.breaks) });
1541 log.debug("[{}] %{f}: includes breaks to {f}", .{ LivenessPass.loop_analysis, inst, fmtInstSet(&data.breaks) });
15421542
15431543 // Now we put the live operands from the loop body in too
15441544 const num_live = data.live_set.count();
......@@ -1550,7 +1550,7 @@ fn writeLoopInfo(
15501550 const alive = key.*;
15511551 a.extra.appendAssumeCapacity(@intFromEnum(alive));
15521552 }
1553 log.debug("[{}] %{}: maintain liveness of {}", .{ LivenessPass.loop_analysis, inst, fmtInstSet(&data.live_set) });
1553 log.debug("[{}] %{f}: maintain liveness of {f}", .{ LivenessPass.loop_analysis, inst, fmtInstSet(&data.live_set) });
15541554
15551555 try a.special.put(gpa, inst, extra_index);
15561556
......@@ -1591,7 +1591,7 @@ fn resolveLoopLiveSet(
15911591 try data.live_set.ensureUnusedCapacity(gpa, @intCast(loop_live.len));
15921592 for (loop_live) |alive| data.live_set.putAssumeCapacity(alive, {});
15931593
1594 log.debug("[{}] %{}: block live set is {}", .{ LivenessPass.main_analysis, inst, fmtInstSet(&data.live_set) });
1594 log.debug("[{}] %{f}: block live set is {f}", .{ LivenessPass.main_analysis, inst, fmtInstSet(&data.live_set) });
15951595
15961596 for (breaks) |block_inst| {
15971597 // We might break to this block, so include every operand that the block needs alive
......@@ -1604,7 +1604,7 @@ fn resolveLoopLiveSet(
16041604 }
16051605 }
16061606
1607 log.debug("[{}] %{}: loop live set is {}", .{ LivenessPass.main_analysis, inst, fmtInstSet(&data.live_set) });
1607 log.debug("[{}] %{f}: loop live set is {f}", .{ LivenessPass.main_analysis, inst, fmtInstSet(&data.live_set) });
16081608}
16091609
16101610fn analyzeInstLoop(
......@@ -1642,7 +1642,7 @@ fn analyzeInstLoop(
16421642 .live_set = data.live_set.move(),
16431643 });
16441644 defer {
1645 log.debug("[{}] %{}: popped loop block scop", .{ pass, inst });
1645 log.debug("[{}] %{f}: popped loop block scop", .{ pass, inst });
16461646 var scope = data.block_scopes.fetchRemove(inst).?.value;
16471647 scope.live_set.deinit(gpa);
16481648 }
......@@ -1743,13 +1743,13 @@ fn analyzeInstCondBr(
17431743 }
17441744 }
17451745
1746 log.debug("[{}] %{}: 'then' branch mirrored deaths are {}", .{ pass, inst, fmtInstList(then_mirrored_deaths.items) });
1747 log.debug("[{}] %{}: 'else' branch mirrored deaths are {}", .{ pass, inst, fmtInstList(else_mirrored_deaths.items) });
1746 log.debug("[{}] %{f}: 'then' branch mirrored deaths are {f}", .{ pass, inst, fmtInstList(then_mirrored_deaths.items) });
1747 log.debug("[{}] %{f}: 'else' branch mirrored deaths are {f}", .{ pass, inst, fmtInstList(else_mirrored_deaths.items) });
17481748
17491749 data.live_set.deinit(gpa);
17501750 data.live_set = then_live.move(); // Really the union of both live sets
17511751
1752 log.debug("[{}] %{}: new live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) });
1752 log.debug("[{}] %{f}: new live set is {f}", .{ pass, inst, fmtInstSet(&data.live_set) });
17531753
17541754 // Write the mirrored deaths to `extra`
17551755 const then_death_count = @as(u32, @intCast(then_mirrored_deaths.items.len));
......@@ -1817,7 +1817,7 @@ fn analyzeInstSwitchBr(
18171817 });
18181818 }
18191819 defer if (is_dispatch_loop) {
1820 log.debug("[{}] %{}: popped loop block scop", .{ pass, inst });
1820 log.debug("[{}] %{f}: popped loop block scop", .{ pass, inst });
18211821 var scope = data.block_scopes.fetchRemove(inst).?.value;
18221822 scope.live_set.deinit(gpa);
18231823 };
......@@ -1875,13 +1875,13 @@ fn analyzeInstSwitchBr(
18751875 }
18761876
18771877 for (mirrored_deaths, 0..) |mirrored, i| {
1878 log.debug("[{}] %{}: case {} mirrored deaths are {}", .{ pass, inst, i, fmtInstList(mirrored.items) });
1878 log.debug("[{}] %{f}: case {} mirrored deaths are {f}", .{ pass, inst, i, fmtInstList(mirrored.items) });
18791879 }
18801880
18811881 data.live_set.deinit(gpa);
18821882 data.live_set = all_alive.move();
18831883
1884 log.debug("[{}] %{}: new live set is {}", .{ pass, inst, fmtInstSet(&data.live_set) });
1884 log.debug("[{}] %{f}: new live set is {f}", .{ pass, inst, fmtInstSet(&data.live_set) });
18851885 }
18861886
18871887 const else_death_count = @as(u32, @intCast(mirrored_deaths[ncases].items.len));
......@@ -1980,7 +1980,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type {
19801980
19811981 .main_analysis => {
19821982 if ((try big.data.live_set.fetchPut(gpa, operand, {})) == null) {
1983 log.debug("[{}] %{}: added %{} to live set (operand dies here)", .{ pass, big.inst, operand });
1983 log.debug("[{}] %{f}: added %{f} to live set (operand dies here)", .{ pass, big.inst, operand });
19841984 big.extra_tombs[extra_byte] |= @as(u32, 1) << extra_bit;
19851985 }
19861986 },
......@@ -2036,15 +2036,15 @@ fn fmtInstSet(set: *const std.AutoHashMapUnmanaged(Air.Inst.Index, void)) FmtIns
20362036const FmtInstSet = struct {
20372037 set: *const std.AutoHashMapUnmanaged(Air.Inst.Index, void),
20382038
2039 pub fn format(val: FmtInstSet, comptime _: []const u8, _: std.fmt.FormatOptions, w: anytype) !void {
2039 pub fn format(val: FmtInstSet, w: *std.io.Writer) std.io.Writer.Error!void {
20402040 if (val.set.count() == 0) {
20412041 try w.writeAll("[no instructions]");
20422042 return;
20432043 }
20442044 var it = val.set.keyIterator();
2045 try w.print("%{}", .{it.next().?.*});
2045 try w.print("%{f}", .{it.next().?.*});
20462046 while (it.next()) |key| {
2047 try w.print(" %{}", .{key.*});
2047 try w.print(" %{f}", .{key.*});
20482048 }
20492049 }
20502050};
......@@ -2056,14 +2056,14 @@ fn fmtInstList(list: []const Air.Inst.Index) FmtInstList {
20562056const FmtInstList = struct {
20572057 list: []const Air.Inst.Index,
20582058
2059 pub fn format(val: FmtInstList, comptime _: []const u8, _: std.fmt.FormatOptions, w: anytype) !void {
2059 pub fn format(val: FmtInstList, w: *std.io.Writer) std.io.Writer.Error!void {
20602060 if (val.list.len == 0) {
20612061 try w.writeAll("[no instructions]");
20622062 return;
20632063 }
2064 try w.print("%{}", .{val.list[0]});
2064 try w.print("%{f}", .{val.list[0]});
20652065 for (val.list[1..]) |inst| {
2066 try w.print(" %{}", .{inst});
2066 try w.print(" %{f}", .{inst});
20672067 }
20682068 }
20692069};
src/Air/Liveness/Verify.zig+12-10
......@@ -73,7 +73,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
7373 .trap, .unreach => {
7474 try self.verifyInstOperands(inst, .{ .none, .none, .none });
7575 // This instruction terminates the function, so everything should be dead
76 if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
76 if (self.live.count() > 0) return invalid("%{f}: instructions still alive", .{inst});
7777 },
7878
7979 // unary
......@@ -166,7 +166,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
166166 const un_op = data[@intFromEnum(inst)].un_op;
167167 try self.verifyInstOperands(inst, .{ un_op, .none, .none });
168168 // This instruction terminates the function, so everything should be dead
169 if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
169 if (self.live.count() > 0) return invalid("%{f}: instructions still alive", .{inst});
170170 },
171171 .dbg_var_ptr,
172172 .dbg_var_val,
......@@ -450,7 +450,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
450450 .repeat => {
451451 const repeat = data[@intFromEnum(inst)].repeat;
452452 const expected_live = self.loops.get(repeat.loop_inst) orelse
453 return invalid("%{}: loop %{} not in scope", .{ @intFromEnum(inst), @intFromEnum(repeat.loop_inst) });
453 return invalid("%{d}: loop %{d} not in scope", .{ @intFromEnum(inst), @intFromEnum(repeat.loop_inst) });
454454
455455 try self.verifyMatchingLiveness(repeat.loop_inst, expected_live);
456456 },
......@@ -460,7 +460,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
460460 try self.verifyOperand(inst, br.operand, self.liveness.operandDies(inst, 0));
461461
462462 const expected_live = self.loops.get(br.block_inst) orelse
463 return invalid("%{}: loop %{} not in scope", .{ @intFromEnum(inst), @intFromEnum(br.block_inst) });
463 return invalid("%{d}: loop %{d} not in scope", .{ @intFromEnum(inst), @intFromEnum(br.block_inst) });
464464
465465 try self.verifyMatchingLiveness(br.block_inst, expected_live);
466466 },
......@@ -511,7 +511,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
511511
512512 // The same stuff should be alive after the loop as before it.
513513 const gop = try self.loops.getOrPut(self.gpa, inst);
514 if (gop.found_existing) return invalid("%{}: loop already exists", .{@intFromEnum(inst)});
514 if (gop.found_existing) return invalid("%{d}: loop already exists", .{@intFromEnum(inst)});
515515 defer {
516516 var live = self.loops.fetchRemove(inst).?;
517517 live.value.deinit(self.gpa);
......@@ -560,7 +560,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
560560 // after the loop as before it.
561561 {
562562 const gop = try self.loops.getOrPut(self.gpa, inst);
563 if (gop.found_existing) return invalid("%{}: loop already exists", .{@intFromEnum(inst)});
563 if (gop.found_existing) return invalid("%{d}: loop already exists", .{@intFromEnum(inst)});
564564 gop.value_ptr.* = self.live.move();
565565 }
566566 defer {
......@@ -601,9 +601,11 @@ fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies
601601 return;
602602 };
603603 if (dies) {
604 if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand });
604 if (!self.live.remove(operand)) return invalid("%{f}: dead operand %{f} reused and killed again", .{
605 inst, operand,
606 });
605607 } else {
606 if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand });
608 if (!self.live.contains(operand)) return invalid("%{f}: dead operand %{f} reused", .{ inst, operand });
607609 }
608610}
609611
......@@ -628,9 +630,9 @@ fn verifyInst(self: *Verify, inst: Air.Inst.Index) Error!void {
628630}
629631
630632fn verifyMatchingLiveness(self: *Verify, block: Air.Inst.Index, live: LiveMap) Error!void {
631 if (self.live.count() != live.count()) return invalid("%{}: different deaths across branches", .{block});
633 if (self.live.count() != live.count()) return invalid("%{f}: different deaths across branches", .{block});
632634 var live_it = self.live.keyIterator();
633 while (live_it.next()) |live_inst| if (!live.contains(live_inst.*)) return invalid("%{}: different deaths across branches", .{block});
635 while (live_it.next()) |live_inst| if (!live.contains(live_inst.*)) return invalid("%{f}: different deaths across branches", .{block});
634636}
635637
636638fn invalid(comptime fmt: []const u8, args: anytype) error{LivenessInvalid} {
src/Air/print.zig+104-98
......@@ -1,6 +1,5 @@
11const std = @import("std");
22const Allocator = std.mem.Allocator;
3const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
43
54const build_options = @import("build_options");
65const Zcu = @import("../Zcu.zig");
......@@ -9,7 +8,7 @@ const Type = @import("../Type.zig");
98const Air = @import("../Air.zig");
109const InternPool = @import("../InternPool.zig");
1110
12pub fn write(air: Air, stream: anytype, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
11pub fn write(air: Air, stream: *std.io.Writer, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
1312 comptime std.debug.assert(build_options.enable_debug_extensions);
1413 const instruction_bytes = air.instructions.len *
1514 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
......@@ -25,20 +24,20 @@ pub fn write(air: Air, stream: anytype, pt: Zcu.PerThread, liveness: ?Air.Livene
2524
2625 // zig fmt: off
2726 stream.print(
28 \\# Total AIR+Liveness bytes: {}
29 \\# AIR Instructions: {d} ({})
30 \\# AIR Extra Data: {d} ({})
31 \\# Liveness tomb_bits: {}
32 \\# Liveness Extra Data: {d} ({})
33 \\# Liveness special table: {d} ({})
27 \\# Total AIR+Liveness bytes: {Bi}
28 \\# AIR Instructions: {d} ({Bi})
29 \\# AIR Extra Data: {d} ({Bi})
30 \\# Liveness tomb_bits: {Bi}
31 \\# Liveness Extra Data: {d} ({Bi})
32 \\# Liveness special table: {d} ({Bi})
3433 \\
3534 , .{
36 fmtIntSizeBin(total_bytes),
37 air.instructions.len, fmtIntSizeBin(instruction_bytes),
38 air.extra.items.len, fmtIntSizeBin(extra_bytes),
39 fmtIntSizeBin(tomb_bytes),
40 if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes),
41 if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes),
35 total_bytes,
36 air.instructions.len, instruction_bytes,
37 air.extra.items.len, extra_bytes,
38 tomb_bytes,
39 if (liveness) |l| l.extra.len else 0, liveness_extra_bytes,
40 if (liveness) |l| l.special.count() else 0, liveness_special_bytes,
4241 }) catch return;
4342 // zig fmt: on
4443
......@@ -55,7 +54,7 @@ pub fn write(air: Air, stream: anytype, pt: Zcu.PerThread, liveness: ?Air.Livene
5554
5655pub fn writeInst(
5756 air: Air,
58 stream: anytype,
57 stream: *std.io.Writer,
5958 inst: Air.Inst.Index,
6059 pt: Zcu.PerThread,
6160 liveness: ?Air.Liveness,
......@@ -73,11 +72,15 @@ pub fn writeInst(
7372}
7473
7574pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
76 air.write(std.io.getStdErr().writer(), pt, liveness);
75 const stderr_bw = std.debug.lockStderrWriter(&.{});
76 defer std.debug.unlockStderrWriter();
77 air.write(stderr_bw, pt, liveness);
7778}
7879
7980pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
80 air.writeInst(std.io.getStdErr().writer(), inst, pt, liveness);
81 const stderr_bw = std.debug.lockStderrWriter(&.{});
82 defer std.debug.unlockStderrWriter();
83 air.writeInst(stderr_bw, inst, pt, liveness);
8184}
8285
8386const Writer = struct {
......@@ -88,17 +91,19 @@ const Writer = struct {
8891 indent: usize,
8992 skip_body: bool,
9093
91 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
94 const Error = std.io.Writer.Error;
95
96 fn writeBody(w: *Writer, s: *std.io.Writer, body: []const Air.Inst.Index) Error!void {
9297 for (body) |inst| {
9398 try w.writeInst(s, inst);
9499 try s.writeByte('\n');
95100 }
96101 }
97102
98 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
103 fn writeInst(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
99104 const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)];
100 try s.writeByteNTimes(' ', w.indent);
101 try s.print("{}{c}= {s}(", .{
105 try s.splatByteAll(' ', w.indent);
106 try s.print("{f}{c}= {s}(", .{
102107 inst,
103108 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
104109 @tagName(tag),
......@@ -335,47 +340,48 @@ const Writer = struct {
335340 try s.writeByte(')');
336341 }
337342
338 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
343 fn writeBinOp(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
339344 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
340345 try w.writeOperand(s, inst, 0, bin_op.lhs);
341346 try s.writeAll(", ");
342347 try w.writeOperand(s, inst, 1, bin_op.rhs);
343348 }
344349
345 fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
350 fn writeUnOp(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
346351 const un_op = w.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
347352 try w.writeOperand(s, inst, 0, un_op);
348353 }
349354
350 fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
355 fn writeNoOp(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
351356 _ = w;
357 _ = s;
352358 _ = inst;
353359 // no-op, no argument to write
354360 }
355361
356 fn writeType(w: *Writer, s: anytype, ty: Type) !void {
362 fn writeType(w: *Writer, s: *std.io.Writer, ty: Type) !void {
357363 return ty.print(s, w.pt);
358364 }
359365
360 fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
366 fn writeTy(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
361367 const ty = w.air.instructions.items(.data)[@intFromEnum(inst)].ty;
362368 try w.writeType(s, ty);
363369 }
364370
365 fn writeArg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
371 fn writeArg(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
366372 const arg = w.air.instructions.items(.data)[@intFromEnum(inst)].arg;
367373 try w.writeType(s, arg.ty.toType());
368374 try s.print(", {d}", .{arg.zir_param_index});
369375 }
370376
371 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
377 fn writeTyOp(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
372378 const ty_op = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
373379 try w.writeType(s, ty_op.ty.toType());
374380 try s.writeAll(", ");
375381 try w.writeOperand(s, inst, 0, ty_op.operand);
376382 }
377383
378 fn writeBlock(w: *Writer, s: anytype, tag: Air.Inst.Tag, inst: Air.Inst.Index) @TypeOf(s).Error!void {
384 fn writeBlock(w: *Writer, s: *std.io.Writer, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void {
379385 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
380386 try w.writeType(s, ty_pl.ty.toType());
381387 const body: []const Air.Inst.Index = @ptrCast(switch (tag) {
......@@ -408,15 +414,15 @@ const Writer = struct {
408414 w.indent += 2;
409415 try w.writeBody(s, body);
410416 w.indent = old_indent;
411 try s.writeByteNTimes(' ', w.indent);
417 try s.splatByteAll(' ', w.indent);
412418 try s.writeAll("}");
413419
414420 for (liveness_block.deaths) |operand| {
415 try s.print(" {}!", .{operand});
421 try s.print(" {f}!", .{operand});
416422 }
417423 }
418424
419 fn writeLoop(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
425 fn writeLoop(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
420426 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
421427 const extra = w.air.extraData(Air.Block, ty_pl.payload);
422428 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
......@@ -428,11 +434,11 @@ const Writer = struct {
428434 w.indent += 2;
429435 try w.writeBody(s, body);
430436 w.indent = old_indent;
431 try s.writeByteNTimes(' ', w.indent);
437 try s.splatByteAll(' ', w.indent);
432438 try s.writeAll("}");
433439 }
434440
435 fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
441 fn writeAggregateInit(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
436442 const zcu = w.pt.zcu;
437443 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
438444 const vector_ty = ty_pl.ty.toType();
......@@ -448,7 +454,7 @@ const Writer = struct {
448454 try s.writeAll("]");
449455 }
450456
451 fn writeUnionInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
457 fn writeUnionInit(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
452458 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
453459 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
454460
......@@ -456,7 +462,7 @@ const Writer = struct {
456462 try w.writeOperand(s, inst, 0, extra.init);
457463 }
458464
459 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
465 fn writeStructField(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
460466 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
461467 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
462468
......@@ -464,7 +470,7 @@ const Writer = struct {
464470 try s.print(", {d}", .{extra.field_index});
465471 }
466472
467 fn writeTyPlBin(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
473 fn writeTyPlBin(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
468474 const data = w.air.instructions.items(.data);
469475 const ty_pl = data[@intFromEnum(inst)].ty_pl;
470476 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
......@@ -477,7 +483,7 @@ const Writer = struct {
477483 try w.writeOperand(s, inst, 1, extra.rhs);
478484 }
479485
480 fn writeCmpxchg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
486 fn writeCmpxchg(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
481487 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
482488 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
483489
......@@ -491,7 +497,7 @@ const Writer = struct {
491497 });
492498 }
493499
494 fn writeMulAdd(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
500 fn writeMulAdd(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
495501 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
496502 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
497503
......@@ -502,7 +508,7 @@ const Writer = struct {
502508 try w.writeOperand(s, inst, 2, pl_op.operand);
503509 }
504510
505 fn writeShuffleOne(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
511 fn writeShuffleOne(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
506512 const unwrapped = w.air.unwrapShuffleOne(w.pt.zcu, inst);
507513 try w.writeType(s, unwrapped.result_ty);
508514 try s.writeAll(", ");
......@@ -512,13 +518,13 @@ const Writer = struct {
512518 if (mask_idx > 0) try s.writeAll(", ");
513519 switch (mask_elem.unwrap()) {
514520 .elem => |idx| try s.print("elem {d}", .{idx}),
515 .value => |val| try s.print("val {}", .{Value.fromInterned(val).fmtValue(w.pt)}),
521 .value => |val| try s.print("val {f}", .{Value.fromInterned(val).fmtValue(w.pt)}),
516522 }
517523 }
518524 try s.writeByte(']');
519525 }
520526
521 fn writeShuffleTwo(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
527 fn writeShuffleTwo(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
522528 const unwrapped = w.air.unwrapShuffleTwo(w.pt.zcu, inst);
523529 try w.writeType(s, unwrapped.result_ty);
524530 try s.writeAll(", ");
......@@ -537,7 +543,7 @@ const Writer = struct {
537543 try s.writeByte(']');
538544 }
539545
540 fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
546 fn writeSelect(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
541547 const zcu = w.pt.zcu;
542548 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
543549 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
......@@ -552,14 +558,14 @@ const Writer = struct {
552558 try w.writeOperand(s, inst, 2, extra.rhs);
553559 }
554560
555 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
561 fn writeReduce(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
556562 const reduce = w.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
557563
558564 try w.writeOperand(s, inst, 0, reduce.operand);
559565 try s.print(", {s}", .{@tagName(reduce.operation)});
560566 }
561567
562 fn writeCmpVector(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
568 fn writeCmpVector(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
563569 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
564570 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
565571
......@@ -569,7 +575,7 @@ const Writer = struct {
569575 try w.writeOperand(s, inst, 1, extra.rhs);
570576 }
571577
572 fn writeVectorStoreElem(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
578 fn writeVectorStoreElem(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
573579 const data = w.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem;
574580 const extra = w.air.extraData(Air.VectorCmp, data.payload).data;
575581
......@@ -580,21 +586,21 @@ const Writer = struct {
580586 try w.writeOperand(s, inst, 2, extra.rhs);
581587 }
582588
583 fn writeRuntimeNavPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
589 fn writeRuntimeNavPtr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
584590 const ip = &w.pt.zcu.intern_pool;
585591 const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
586592 try w.writeType(s, .fromInterned(ty_nav.ty));
587 try s.print(", '{}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
593 try s.print(", '{f}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
588594 }
589595
590 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
596 fn writeAtomicLoad(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
591597 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
592598
593599 try w.writeOperand(s, inst, 0, atomic_load.ptr);
594600 try s.print(", {s}", .{@tagName(atomic_load.order)});
595601 }
596602
597 fn writePrefetch(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
603 fn writePrefetch(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
598604 const prefetch = w.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
599605
600606 try w.writeOperand(s, inst, 0, prefetch.ptr);
......@@ -605,10 +611,10 @@ const Writer = struct {
605611
606612 fn writeAtomicStore(
607613 w: *Writer,
608 s: anytype,
614 s: *std.io.Writer,
609615 inst: Air.Inst.Index,
610616 order: std.builtin.AtomicOrder,
611 ) @TypeOf(s).Error!void {
617 ) Error!void {
612618 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
613619 try w.writeOperand(s, inst, 0, bin_op.lhs);
614620 try s.writeAll(", ");
......@@ -616,7 +622,7 @@ const Writer = struct {
616622 try s.print(", {s}", .{@tagName(order)});
617623 }
618624
619 fn writeAtomicRmw(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
625 fn writeAtomicRmw(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
620626 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
621627 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
622628
......@@ -626,7 +632,7 @@ const Writer = struct {
626632 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
627633 }
628634
629 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
635 fn writeFieldParentPtr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
630636 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
631637 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
632638
......@@ -634,7 +640,7 @@ const Writer = struct {
634640 try s.print(", {d}", .{extra.field_index});
635641 }
636642
637 fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
643 fn writeAssembly(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
638644 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
639645 const extra = w.air.extraData(Air.Asm, ty_pl.payload);
640646 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
......@@ -704,22 +710,22 @@ const Writer = struct {
704710 }
705711 }
706712 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];
707 try s.print(", \"{}\"", .{std.zig.fmtEscapes(asm_source)});
713 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});
708714 }
709715
710 fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
716 fn writeDbgStmt(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
711717 const dbg_stmt = w.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
712718 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
713719 }
714720
715 fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
721 fn writeDbgVar(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
716722 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
717723 try w.writeOperand(s, inst, 0, pl_op.operand);
718724 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
719 try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))});
725 try s.print(", \"{f}\"", .{std.zig.fmtString(name.toSlice(w.air))});
720726 }
721727
722 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
728 fn writeCall(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
723729 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
724730 const extra = w.air.extraData(Air.Call, pl_op.payload);
725731 const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len]));
......@@ -732,19 +738,19 @@ const Writer = struct {
732738 try s.writeAll("]");
733739 }
734740
735 fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
741 fn writeBr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
736742 const br = w.air.instructions.items(.data)[@intFromEnum(inst)].br;
737743 try w.writeInstIndex(s, br.block_inst, false);
738744 try s.writeAll(", ");
739745 try w.writeOperand(s, inst, 0, br.operand);
740746 }
741747
742 fn writeRepeat(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
748 fn writeRepeat(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
743749 const repeat = w.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
744750 try w.writeInstIndex(s, repeat.loop_inst, false);
745751 }
746752
747 fn writeTry(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
753 fn writeTry(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
748754 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
749755 const extra = w.air.extraData(Air.Try, pl_op.payload);
750756 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
......@@ -760,25 +766,25 @@ const Writer = struct {
760766 w.indent += 2;
761767
762768 if (liveness_condbr.else_deaths.len != 0) {
763 try s.writeByteNTimes(' ', w.indent);
769 try s.splatByteAll(' ', w.indent);
764770 for (liveness_condbr.else_deaths, 0..) |operand, i| {
765771 if (i != 0) try s.writeAll(" ");
766 try s.print("{}!", .{operand});
772 try s.print("{f}!", .{operand});
767773 }
768774 try s.writeAll("\n");
769775 }
770776 try w.writeBody(s, body);
771777
772778 w.indent = old_indent;
773 try s.writeByteNTimes(' ', w.indent);
779 try s.splatByteAll(' ', w.indent);
774780 try s.writeAll("}");
775781
776782 for (liveness_condbr.then_deaths) |operand| {
777 try s.print(" {}!", .{operand});
783 try s.print(" {f}!", .{operand});
778784 }
779785 }
780786
781 fn writeTryPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
787 fn writeTryPtr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
782788 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
783789 const extra = w.air.extraData(Air.TryPtr, ty_pl.payload);
784790 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
......@@ -797,25 +803,25 @@ const Writer = struct {
797803 w.indent += 2;
798804
799805 if (liveness_condbr.else_deaths.len != 0) {
800 try s.writeByteNTimes(' ', w.indent);
806 try s.splatByteAll(' ', w.indent);
801807 for (liveness_condbr.else_deaths, 0..) |operand, i| {
802808 if (i != 0) try s.writeAll(" ");
803 try s.print("{}!", .{operand});
809 try s.print("{f}!", .{operand});
804810 }
805811 try s.writeAll("\n");
806812 }
807813 try w.writeBody(s, body);
808814
809815 w.indent = old_indent;
810 try s.writeByteNTimes(' ', w.indent);
816 try s.splatByteAll(' ', w.indent);
811817 try s.writeAll("}");
812818
813819 for (liveness_condbr.then_deaths) |operand| {
814 try s.print(" {}!", .{operand});
820 try s.print(" {f}!", .{operand});
815821 }
816822 }
817823
818 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
824 fn writeCondBr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
819825 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
820826 const extra = w.air.extraData(Air.CondBr, pl_op.payload);
821827 const then_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.then_body_len]);
......@@ -839,16 +845,16 @@ const Writer = struct {
839845 w.indent += 2;
840846
841847 if (liveness_condbr.then_deaths.len != 0) {
842 try s.writeByteNTimes(' ', w.indent);
848 try s.splatByteAll(' ', w.indent);
843849 for (liveness_condbr.then_deaths, 0..) |operand, i| {
844850 if (i != 0) try s.writeAll(" ");
845 try s.print("{}!", .{operand});
851 try s.print("{f}!", .{operand});
846852 }
847853 try s.writeAll("\n");
848854 }
849855
850856 try w.writeBody(s, then_body);
851 try s.writeByteNTimes(' ', old_indent);
857 try s.splatByteAll(' ', old_indent);
852858 try s.writeAll("},");
853859 if (extra.data.branch_hints.false != .none) {
854860 try s.print(" {s}", .{@tagName(extra.data.branch_hints.false)});
......@@ -859,10 +865,10 @@ const Writer = struct {
859865 try s.writeAll(" {\n");
860866
861867 if (liveness_condbr.else_deaths.len != 0) {
862 try s.writeByteNTimes(' ', w.indent);
868 try s.splatByteAll(' ', w.indent);
863869 for (liveness_condbr.else_deaths, 0..) |operand, i| {
864870 if (i != 0) try s.writeAll(" ");
865 try s.print("{}!", .{operand});
871 try s.print("{f}!", .{operand});
866872 }
867873 try s.writeAll("\n");
868874 }
......@@ -870,11 +876,11 @@ const Writer = struct {
870876 try w.writeBody(s, else_body);
871877 w.indent = old_indent;
872878
873 try s.writeByteNTimes(' ', old_indent);
879 try s.splatByteAll(' ', old_indent);
874880 try s.writeAll("}");
875881 }
876882
877 fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
883 fn writeSwitchBr(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
878884 const switch_br = w.air.unwrapSwitch(inst);
879885
880886 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
......@@ -916,17 +922,17 @@ const Writer = struct {
916922
917923 const deaths = liveness.deaths[case.idx];
918924 if (deaths.len != 0) {
919 try s.writeByteNTimes(' ', w.indent);
925 try s.splatByteAll(' ', w.indent);
920926 for (deaths, 0..) |operand, i| {
921927 if (i != 0) try s.writeAll(" ");
922 try s.print("{}!", .{operand});
928 try s.print("{f}!", .{operand});
923929 }
924930 try s.writeAll("\n");
925931 }
926932
927933 try w.writeBody(s, case.body);
928934 w.indent -= 2;
929 try s.writeByteNTimes(' ', w.indent);
935 try s.splatByteAll(' ', w.indent);
930936 try s.writeAll("}");
931937 }
932938
......@@ -942,47 +948,47 @@ const Writer = struct {
942948
943949 const deaths = liveness.deaths[liveness.deaths.len - 1];
944950 if (deaths.len != 0) {
945 try s.writeByteNTimes(' ', w.indent);
951 try s.splatByteAll(' ', w.indent);
946952 for (deaths, 0..) |operand, i| {
947953 if (i != 0) try s.writeAll(" ");
948 try s.print("{}!", .{operand});
954 try s.print("{f}!", .{operand});
949955 }
950956 try s.writeAll("\n");
951957 }
952958
953959 try w.writeBody(s, else_body);
954960 w.indent -= 2;
955 try s.writeByteNTimes(' ', w.indent);
961 try s.splatByteAll(' ', w.indent);
956962 try s.writeAll("}");
957963 }
958964
959965 try s.writeAll("\n");
960 try s.writeByteNTimes(' ', old_indent);
966 try s.splatByteAll(' ', old_indent);
961967 }
962968
963 fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
969 fn writeWasmMemorySize(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
964970 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
965971 try s.print("{d}", .{pl_op.payload});
966972 }
967973
968 fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
974 fn writeWasmMemoryGrow(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
969975 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
970976 try s.print("{d}, ", .{pl_op.payload});
971977 try w.writeOperand(s, inst, 0, pl_op.operand);
972978 }
973979
974 fn writeWorkDimension(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
980 fn writeWorkDimension(w: *Writer, s: *std.io.Writer, inst: Air.Inst.Index) Error!void {
975981 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
976982 try s.print("{d}", .{pl_op.payload});
977983 }
978984
979985 fn writeOperand(
980986 w: *Writer,
981 s: anytype,
987 s: *std.io.Writer,
982988 inst: Air.Inst.Index,
983989 op_index: usize,
984990 operand: Air.Inst.Ref,
985 ) @TypeOf(s).Error!void {
991 ) Error!void {
986992 const small_tomb_bits = Air.Liveness.bpi - 1;
987993 const dies = if (w.liveness) |liveness| blk: {
988994 if (op_index < small_tomb_bits)
......@@ -1004,16 +1010,16 @@ const Writer = struct {
10041010
10051011 fn writeInstRef(
10061012 w: *Writer,
1007 s: anytype,
1013 s: *std.io.Writer,
10081014 operand: Air.Inst.Ref,
10091015 dies: bool,
1010 ) @TypeOf(s).Error!void {
1016 ) Error!void {
10111017 if (@intFromEnum(operand) < InternPool.static_len) {
10121018 return s.print("@{}", .{operand});
10131019 } else if (operand.toInterned()) |ip_index| {
10141020 const pt = w.pt;
10151021 const ty = Type.fromInterned(pt.zcu.intern_pool.indexToKey(ip_index).typeOf());
1016 try s.print("<{}, {}>", .{
1022 try s.print("<{f}, {f}>", .{
10171023 ty.fmt(pt),
10181024 Value.fromInterned(ip_index).fmtValue(pt),
10191025 });
......@@ -1024,12 +1030,12 @@ const Writer = struct {
10241030
10251031 fn writeInstIndex(
10261032 w: *Writer,
1027 s: anytype,
1033 s: *std.io.Writer,
10281034 inst: Air.Inst.Index,
10291035 dies: bool,
1030 ) @TypeOf(s).Error!void {
1036 ) Error!void {
10311037 _ = w;
1032 try s.print("{}", .{inst});
1038 try s.print("{f}", .{inst});
10331039 if (dies) try s.writeByte('!');
10341040 }
10351041
src/Builtin.zig+40-40
......@@ -51,60 +51,60 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
5151 const zig_backend = opts.zig_backend;
5252
5353 @setEvalBranchQuota(4000);
54 try buffer.writer().print(
54 try buffer.print(
5555 \\const std = @import("std");
5656 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
5757 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
5858 \\pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable;
5959 \\pub const zig_version_string = "{s}";
60 \\pub const zig_backend = std.builtin.CompilerBackend.{p_};
60 \\pub const zig_backend = std.builtin.CompilerBackend.{f};
6161 \\
62 \\pub const output_mode: std.builtin.OutputMode = .{p_};
63 \\pub const link_mode: std.builtin.LinkMode = .{p_};
64 \\pub const unwind_tables: std.builtin.UnwindTables = .{p_};
62 \\pub const output_mode: std.builtin.OutputMode = .{f};
63 \\pub const link_mode: std.builtin.LinkMode = .{f};
64 \\pub const unwind_tables: std.builtin.UnwindTables = .{f};
6565 \\pub const is_test = {};
6666 \\pub const single_threaded = {};
67 \\pub const abi: std.Target.Abi = .{p_};
67 \\pub const abi: std.Target.Abi = .{f};
6868 \\pub const cpu: std.Target.Cpu = .{{
69 \\ .arch = .{p_},
70 \\ .model = &std.Target.{p_}.cpu.{p_},
71 \\ .features = std.Target.{p_}.featureSet(&.{{
69 \\ .arch = .{f},
70 \\ .model = &std.Target.{f}.cpu.{f},
71 \\ .features = std.Target.{f}.featureSet(&.{{
7272 \\
7373 , .{
7474 build_options.version,
75 std.zig.fmtId(@tagName(zig_backend)),
76 std.zig.fmtId(@tagName(opts.output_mode)),
77 std.zig.fmtId(@tagName(opts.link_mode)),
78 std.zig.fmtId(@tagName(opts.unwind_tables)),
75 std.zig.fmtIdPU(@tagName(zig_backend)),
76 std.zig.fmtIdPU(@tagName(opts.output_mode)),
77 std.zig.fmtIdPU(@tagName(opts.link_mode)),
78 std.zig.fmtIdPU(@tagName(opts.unwind_tables)),
7979 opts.is_test,
8080 opts.single_threaded,
81 std.zig.fmtId(@tagName(target.abi)),
82 std.zig.fmtId(@tagName(target.cpu.arch)),
83 std.zig.fmtId(arch_family_name),
84 std.zig.fmtId(target.cpu.model.name),
85 std.zig.fmtId(arch_family_name),
81 std.zig.fmtIdPU(@tagName(target.abi)),
82 std.zig.fmtIdPU(@tagName(target.cpu.arch)),
83 std.zig.fmtIdPU(arch_family_name),
84 std.zig.fmtIdPU(target.cpu.model.name),
85 std.zig.fmtIdPU(arch_family_name),
8686 });
8787
8888 for (target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| {
8989 const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize));
9090 const is_enabled = target.cpu.features.isEnabled(index);
9191 if (is_enabled) {
92 try buffer.writer().print(" .{p_},\n", .{std.zig.fmtId(feature.name)});
92 try buffer.print(" .{f},\n", .{std.zig.fmtIdPU(feature.name)});
9393 }
9494 }
95 try buffer.writer().print(
95 try buffer.print(
9696 \\ }}),
9797 \\}};
9898 \\pub const os: std.Target.Os = .{{
99 \\ .tag = .{p_},
99 \\ .tag = .{f},
100100 \\ .version_range = .{{
101101 ,
102 .{std.zig.fmtId(@tagName(target.os.tag))},
102 .{std.zig.fmtIdPU(@tagName(target.os.tag))},
103103 );
104104
105105 switch (target.os.versionRange()) {
106106 .none => try buffer.appendSlice(" .none = {} },\n"),
107 .semver => |semver| try buffer.writer().print(
107 .semver => |semver| try buffer.print(
108108 \\ .semver = .{{
109109 \\ .min = .{{
110110 \\ .major = {},
......@@ -127,7 +127,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
127127 semver.max.minor,
128128 semver.max.patch,
129129 }),
130 .linux => |linux| try buffer.writer().print(
130 .linux => |linux| try buffer.print(
131131 \\ .linux = .{{
132132 \\ .range = .{{
133133 \\ .min = .{{
......@@ -164,7 +164,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
164164
165165 linux.android,
166166 }),
167 .hurd => |hurd| try buffer.writer().print(
167 .hurd => |hurd| try buffer.print(
168168 \\ .hurd = .{{
169169 \\ .range = .{{
170170 \\ .min = .{{
......@@ -198,10 +198,10 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
198198 hurd.glibc.minor,
199199 hurd.glibc.patch,
200200 }),
201 .windows => |windows| try buffer.writer().print(
201 .windows => |windows| try buffer.print(
202202 \\ .windows = .{{
203 \\ .min = {c},
204 \\ .max = {c},
203 \\ .min = {f},
204 \\ .max = {f},
205205 \\ }}}},
206206 \\
207207 , .{ windows.min, windows.max }),
......@@ -217,7 +217,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
217217 );
218218
219219 if (target.dynamic_linker.get()) |dl| {
220 try buffer.writer().print(
220 try buffer.print(
221221 \\ .dynamic_linker = .init("{s}"),
222222 \\}};
223223 \\
......@@ -237,9 +237,9 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
237237 // knows libc will provide it, and likewise c.zig will not export memcpy.
238238 const link_libc = opts.link_libc;
239239
240 try buffer.writer().print(
241 \\pub const object_format: std.Target.ObjectFormat = .{p_};
242 \\pub const mode: std.builtin.OptimizeMode = .{p_};
240 try buffer.print(
241 \\pub const object_format: std.Target.ObjectFormat = .{f};
242 \\pub const mode: std.builtin.OptimizeMode = .{f};
243243 \\pub const link_libc = {};
244244 \\pub const link_libcpp = {};
245245 \\pub const have_error_return_tracing = {};
......@@ -249,12 +249,12 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
249249 \\pub const position_independent_code = {};
250250 \\pub const position_independent_executable = {};
251251 \\pub const strip_debug_info = {};
252 \\pub const code_model: std.builtin.CodeModel = .{p_};
252 \\pub const code_model: std.builtin.CodeModel = .{f};
253253 \\pub const omit_frame_pointer = {};
254254 \\
255255 , .{
256 std.zig.fmtId(@tagName(target.ofmt)),
257 std.zig.fmtId(@tagName(opts.optimize_mode)),
256 std.zig.fmtIdPU(@tagName(target.ofmt)),
257 std.zig.fmtIdPU(@tagName(opts.optimize_mode)),
258258 link_libc,
259259 opts.link_libcpp,
260260 opts.error_tracing,
......@@ -264,15 +264,15 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
264264 opts.pic,
265265 opts.pie,
266266 opts.strip,
267 std.zig.fmtId(@tagName(opts.code_model)),
267 std.zig.fmtIdPU(@tagName(opts.code_model)),
268268 opts.omit_frame_pointer,
269269 });
270270
271271 if (target.os.tag == .wasi) {
272 try buffer.writer().print(
273 \\pub const wasi_exec_model: std.builtin.WasiExecModel = .{p_};
272 try buffer.print(
273 \\pub const wasi_exec_model: std.builtin.WasiExecModel = .{f};
274274 \\
275 , .{std.zig.fmtId(@tagName(opts.wasi_exec_model))});
275 , .{std.zig.fmtIdPU(@tagName(opts.wasi_exec_model))});
276276 }
277277
278278 if (opts.is_test) {
......@@ -317,7 +317,7 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void {
317317 if (root_dir.statFile(sub_path)) |stat| {
318318 if (stat.size != file.source.?.len) {
319319 std.log.warn(
320 "the cached file '{}' had the wrong size. Expected {d}, found {d}. " ++
320 "the cached file '{f}' had the wrong size. Expected {d}, found {d}. " ++
321321 "Overwriting with correct file contents now",
322322 .{ file.path.fmt(comp), file.source.?.len, stat.size },
323323 );
src/Compilation.zig+40-45
......@@ -399,9 +399,7 @@ pub const Path = struct {
399399 const Formatter = struct {
400400 p: Path,
401401 comp: *Compilation,
402 pub fn format(f: Formatter, comptime unused_fmt: []const u8, options: std.fmt.FormatOptions, w: anytype) !void {
403 comptime assert(unused_fmt.len == 0);
404 _ = options;
402 pub fn format(f: Formatter, w: *std.io.Writer) std.io.Writer.Error!void {
405403 const root_path: []const u8 = switch (f.p.root) {
406404 .zig_lib => f.comp.dirs.zig_lib.path orelse ".",
407405 .global_cache => f.comp.dirs.global_cache.path orelse ".",
......@@ -730,10 +728,10 @@ pub const Directories = struct {
730728 };
731729
732730 if (std.mem.eql(u8, zig_lib.path orelse "", global_cache.path orelse "")) {
733 fatal("zig lib directory '{}' cannot be equal to global cache directory '{}'", .{ zig_lib, global_cache });
731 fatal("zig lib directory '{f}' cannot be equal to global cache directory '{f}'", .{ zig_lib, global_cache });
734732 }
735733 if (std.mem.eql(u8, zig_lib.path orelse "", local_cache.path orelse "")) {
736 fatal("zig lib directory '{}' cannot be equal to local cache directory '{}'", .{ zig_lib, local_cache });
734 fatal("zig lib directory '{f}' cannot be equal to local cache directory '{f}'", .{ zig_lib, local_cache });
737735 }
738736
739737 return .{
......@@ -1001,7 +999,7 @@ pub const CObject = struct {
1001999
10021000 var line = std.ArrayList(u8).init(eb.gpa);
10031001 defer line.deinit();
1004 file.reader().readUntilDelimiterArrayList(&line, '\n', 1 << 10) catch break :source_line 0;
1002 file.deprecatedReader().readUntilDelimiterArrayList(&line, '\n', 1 << 10) catch break :source_line 0;
10051003
10061004 break :source_line try eb.addString(line.items);
10071005 };
......@@ -1069,7 +1067,7 @@ pub const CObject = struct {
10691067
10701068 const file = try std.fs.cwd().openFile(path, .{});
10711069 defer file.close();
1072 var br = std.io.bufferedReader(file.reader());
1070 var br = std.io.bufferedReader(file.deprecatedReader());
10731071 const reader = br.reader();
10741072 var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = reader.any() });
10751073 defer bc.deinit();
......@@ -1875,7 +1873,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
18751873 if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: {
18761874 std.debug.lockStdErr();
18771875 defer std.debug.unlockStdErr();
1878 const stderr = std.io.getStdErr().writer();
1876 const stderr = std.fs.File.stderr().deprecatedWriter();
18791877 nosuspend {
18801878 stderr.print("compilation: {s}\n", .{options.root_name}) catch break :print;
18811879 stderr.print(" target: {s}\n", .{try target.zigTriple(arena)}) catch break :print;
......@@ -2689,7 +2687,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
26892687 const is_hit = man.hit() catch |err| switch (err) {
26902688 error.CacheCheckFailed => switch (man.diagnostic) {
26912689 .none => unreachable,
2692 .manifest_create, .manifest_read, .manifest_lock, .manifest_seek => |e| return comp.setMiscFailure(
2690 .manifest_create, .manifest_read, .manifest_lock => |e| return comp.setMiscFailure(
26932691 .check_whole_cache,
26942692 "failed to check cache: {s} {s}",
26952693 .{ @tagName(man.diagnostic), @errorName(e) },
......@@ -2699,7 +2697,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
26992697 const prefix = man.cache.prefixes()[pp.prefix];
27002698 return comp.setMiscFailure(
27012699 .check_whole_cache,
2702 "failed to check cache: '{}{s}' {s} {s}",
2700 "failed to check cache: '{f}{s}' {s} {s}",
27032701 .{ prefix, pp.sub_path, @tagName(man.diagnostic), @errorName(op.err) },
27042702 );
27052703 },
......@@ -2916,7 +2914,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
29162914 renameTmpIntoCache(comp.dirs.local_cache, tmp_dir_sub_path, o_sub_path) catch |err| {
29172915 return comp.setMiscFailure(
29182916 .rename_results,
2919 "failed to rename compilation results ('{}{s}') into local cache ('{}{s}'): {s}",
2917 "failed to rename compilation results ('{f}{s}') into local cache ('{f}{s}'): {s}",
29202918 .{
29212919 comp.dirs.local_cache, tmp_dir_sub_path,
29222920 comp.dirs.local_cache, o_sub_path,
......@@ -2983,7 +2981,7 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat
29832981 break @intCast(i);
29842982 }
29852983 } else std.debug.panic(
2986 "missing prefix directory '{s}' ('{}') for '{s}'",
2984 "missing prefix directory '{s}' ('{f}') for '{s}'",
29872985 .{ @tagName(path.root), want_prefix_dir, path.sub_path },
29882986 );
29892987
......@@ -3322,7 +3320,7 @@ fn emitFromCObject(
33223320 emit_path.root_dir.handle,
33233321 emit_path.sub_path,
33243322 .{},
3325 ) catch |err| log.err("unable to copy '{}' to '{}': {s}", .{
3323 ) catch |err| log.err("unable to copy '{f}' to '{f}': {s}", .{
33263324 src_path,
33273325 emit_path,
33283326 @errorName(err),
......@@ -3670,7 +3668,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
36703668 .illegal_zig_import => try bundle.addString("this compiler implementation does not allow importing files from this directory"),
36713669 },
36723670 .src_loc = try bundle.addSourceLocation(.{
3673 .src_path = try bundle.printString("{}", .{file.path.fmt(comp)}),
3671 .src_path = try bundle.printString("{f}", .{file.path.fmt(comp)}),
36743672 .span_start = start,
36753673 .span_main = start,
36763674 .span_end = @intCast(end),
......@@ -3717,7 +3715,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
37173715 assert(!is_retryable);
37183716 // AstGen/ZoirGen succeeded with errors. Note that this may include AST errors.
37193717 _ = try file.getTree(zcu); // Tree must be loaded.
3720 const path = try std.fmt.allocPrint(gpa, "{}", .{file.path.fmt(comp)});
3718 const path = try std.fmt.allocPrint(gpa, "{f}", .{file.path.fmt(comp)});
37213719 defer gpa.free(path);
37223720 if (file.zir != null) {
37233721 try bundle.addZirErrorMessages(file.zir.?, file.tree.?, file.source.?, path);
......@@ -3772,9 +3770,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
37723770 if (!refs.contains(anal_unit)) continue;
37733771 }
37743772
3775 std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{}'", .{
3776 error_msg.msg,
3777 zcu.fmtAnalUnit(anal_unit),
3773 std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{f}'", .{
3774 error_msg.msg, zcu.fmtAnalUnit(anal_unit),
37783775 });
37793776
37803777 try addModuleErrorMsg(zcu, &bundle, error_msg.*, added_any_analysis_error);
......@@ -3932,11 +3929,11 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
39323929 // This AU is referenced and has a transitive compile error, meaning it referenced something with a compile error.
39333930 // However, we haven't reported any such error.
39343931 // This is a compiler bug.
3935 const stderr = std.io.getStdErr().writer();
3932 const stderr = std.fs.File.stderr().deprecatedWriter();
39363933 try stderr.writeAll("referenced transitive analysis errors, but none actually emitted\n");
3937 try stderr.print("{} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)});
3934 try stderr.print("{f} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)});
39383935 while (ref) |r| {
3939 try stderr.print("referenced by: {}{s}\n", .{
3936 try stderr.print("referenced by: {f}{s}\n", .{
39403937 zcu.fmtAnalUnit(r.referencer),
39413938 if (zcu.transitive_failed_analysis.contains(r.referencer)) " [transitive failure]" else "",
39423939 });
......@@ -4035,7 +4032,7 @@ pub fn addModuleErrorMsg(
40354032 const err_src_loc = module_err_msg.src_loc.upgrade(zcu);
40364033 const err_source = err_src_loc.file_scope.getSource(zcu) catch |err| {
40374034 try eb.addRootErrorMessage(.{
4038 .msg = try eb.printString("unable to load '{}': {s}", .{
4035 .msg = try eb.printString("unable to load '{f}': {s}", .{
40394036 err_src_loc.file_scope.path.fmt(zcu.comp), @errorName(err),
40404037 }),
40414038 });
......@@ -4098,7 +4095,7 @@ pub fn addModuleErrorMsg(
40984095 }
40994096
41004097 const src_loc = try eb.addSourceLocation(.{
4101 .src_path = try eb.printString("{}", .{err_src_loc.file_scope.path.fmt(zcu.comp)}),
4098 .src_path = try eb.printString("{f}", .{err_src_loc.file_scope.path.fmt(zcu.comp)}),
41024099 .span_start = err_span.start,
41034100 .span_main = err_span.main,
41044101 .span_end = err_span.end,
......@@ -4130,7 +4127,7 @@ pub fn addModuleErrorMsg(
41304127 const gop = try notes.getOrPutContext(gpa, .{
41314128 .msg = try eb.addString(module_note.msg),
41324129 .src_loc = try eb.addSourceLocation(.{
4133 .src_path = try eb.printString("{}", .{note_src_loc.file_scope.path.fmt(zcu.comp)}),
4130 .src_path = try eb.printString("{f}", .{note_src_loc.file_scope.path.fmt(zcu.comp)}),
41344131 .span_start = span.start,
41354132 .span_main = span.main,
41364133 .span_end = span.end,
......@@ -4175,7 +4172,7 @@ fn addReferenceTraceFrame(
41754172 try ref_traces.append(gpa, .{
41764173 .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
41774174 .src_loc = try eb.addSourceLocation(.{
4178 .src_path = try eb.printString("{}", .{src.file_scope.path.fmt(zcu.comp)}),
4175 .src_path = try eb.printString("{f}", .{src.file_scope.path.fmt(zcu.comp)}),
41794176 .span_start = span.start,
41804177 .span_main = span.main,
41814178 .span_end = span.end,
......@@ -4836,7 +4833,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
48364833 var out_dir = docs_path.root_dir.handle.makeOpenPath(docs_path.sub_path, .{}) catch |err| {
48374834 return comp.lockAndSetMiscFailure(
48384835 .docs_copy,
4839 "unable to create output directory '{}': {s}",
4836 "unable to create output directory '{f}': {s}",
48404837 .{ docs_path, @errorName(err) },
48414838 );
48424839 };
......@@ -4856,7 +4853,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
48564853 var tar_file = out_dir.createFile("sources.tar", .{}) catch |err| {
48574854 return comp.lockAndSetMiscFailure(
48584855 .docs_copy,
4859 "unable to create '{}/sources.tar': {s}",
4856 "unable to create '{f}/sources.tar': {s}",
48604857 .{ docs_path, @errorName(err) },
48614858 );
48624859 };
......@@ -4885,7 +4882,7 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8,
48854882 const root_dir, const sub_path = root.openInfo(comp.dirs);
48864883 break :d root_dir.openDir(sub_path, .{ .iterate = true });
48874884 } catch |err| {
4888 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{}': {s}", .{
4885 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {s}", .{
48894886 root.fmt(comp), @errorName(err),
48904887 });
48914888 };
......@@ -4894,7 +4891,7 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8,
48944891 var walker = try mod_dir.walk(comp.gpa);
48954892 defer walker.deinit();
48964893
4897 var archiver = std.tar.writer(tar_file.writer().any());
4894 var archiver = std.tar.writer(tar_file.deprecatedWriter().any());
48984895 archiver.prefix = name;
48994896
49004897 while (try walker.next()) |entry| {
......@@ -4907,13 +4904,13 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8,
49074904 else => continue,
49084905 }
49094906 var file = mod_dir.openFile(entry.path, .{}) catch |err| {
4910 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{}{s}': {s}", .{
4907 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{f}{s}': {s}", .{
49114908 root.fmt(comp), entry.path, @errorName(err),
49124909 });
49134910 };
49144911 defer file.close();
49154912 archiver.writeFile(entry.path, file) catch |err| {
4916 return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{}{s}': {s}", .{
4913 return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{f}{s}': {s}", .{
49174914 root.fmt(comp), entry.path, @errorName(err),
49184915 });
49194916 };
......@@ -5043,7 +5040,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
50435040 var out_dir = docs_path.root_dir.handle.makeOpenPath(docs_path.sub_path, .{}) catch |err| {
50445041 return comp.lockAndSetMiscFailure(
50455042 .docs_copy,
5046 "unable to create output directory '{}': {s}",
5043 "unable to create output directory '{f}': {s}",
50475044 .{ docs_path, @errorName(err) },
50485045 );
50495046 };
......@@ -5055,10 +5052,8 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
50555052 "main.wasm",
50565053 .{},
50575054 ) catch |err| {
5058 return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}' to '{}': {s}", .{
5059 crt_file.full_object_path,
5060 docs_path,
5061 @errorName(err),
5055 return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{f}' to '{f}': {s}", .{
5056 crt_file.full_object_path, docs_path, @errorName(err),
50625057 });
50635058 };
50645059}
......@@ -5131,7 +5126,7 @@ fn workerUpdateBuiltinFile(comp: *Compilation, file: *Zcu.File) void {
51315126 defer comp.mutex.unlock();
51325127 comp.setMiscFailure(
51335128 .write_builtin_zig,
5134 "unable to write '{}': {s}",
5129 "unable to write '{f}': {s}",
51355130 .{ file.path.fmt(comp), @errorName(err) },
51365131 );
51375132 };
......@@ -5852,7 +5847,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
58525847
58535848 try child.spawn();
58545849
5855 const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize));
5850 const stderr = try child.stderr.?.deprecatedReader().readAllAlloc(arena, std.math.maxInt(usize));
58565851
58575852 const term = child.wait() catch |err| {
58585853 return comp.failCObj(c_object, "failed to spawn zig clang {s}: {s}", .{ argv.items[0], @errorName(err) });
......@@ -6012,9 +6007,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
60126007
60136008 // In .rc files, a " within a quoted string is escaped as ""
60146009 const fmtRcEscape = struct {
6015 fn formatRcEscape(bytes: []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
6016 _ = fmt;
6017 _ = options;
6010 fn formatRcEscape(bytes: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void {
60186011 for (bytes) |byte| switch (byte) {
60196012 '"' => try writer.writeAll("\"\""),
60206013 '\\' => try writer.writeAll("\\\\"),
......@@ -6022,7 +6015,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
60226015 };
60236016 }
60246017
6025 pub fn fmtRcEscape(bytes: []const u8) std.fmt.Formatter(formatRcEscape) {
6018 pub fn fmtRcEscape(bytes: []const u8) std.fmt.Formatter([]const u8, formatRcEscape) {
60266019 return .{ .data = bytes };
60276020 }
60286021 }.fmtRcEscape;
......@@ -6036,7 +6029,9 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
60366029 // 24 is RT_MANIFEST
60376030 const resource_type = 24;
60386031
6039 const input = try std.fmt.allocPrint(arena, "{} {} \"{s}\"", .{ resource_id, resource_type, fmtRcEscape(src_path) });
6032 const input = try std.fmt.allocPrint(arena, "{d} {d} \"{f}\"", .{
6033 resource_id, resource_type, fmtRcEscape(src_path),
6034 });
60406035
60416036 try o_dir.writeFile(.{ .sub_path = rc_basename, .data = input });
60426037
......@@ -6251,7 +6246,7 @@ fn spawnZigRc(
62516246 }
62526247
62536248 // Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace)
6254 const stderr_reader = child.stderr.?.reader();
6249 const stderr_reader = child.stderr.?.deprecatedReader();
62556250 const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
62566251
62576252 const term = child.wait() catch |err| {
......@@ -7214,7 +7209,7 @@ pub fn lockAndSetMiscFailure(
72147209pub fn dump_argv(argv: []const []const u8) void {
72157210 std.debug.lockStdErr();
72167211 defer std.debug.unlockStdErr();
7217 const stderr = std.io.getStdErr().writer();
7212 const stderr = std.fs.File.stderr().deprecatedWriter();
72187213 for (argv[0 .. argv.len - 1]) |arg| {
72197214 nosuspend stderr.print("{s} ", .{arg}) catch return;
72207215 }
src/IncrementalDebugServer.zig+5-5
......@@ -142,8 +142,8 @@ fn handleCommand(zcu: *Zcu, output: *std.ArrayListUnmanaged(u8), cmd_str: []cons
142142 const create_gen = zcu.incremental_debug_state.navs.get(nav_index) orelse return w.writeAll("unknown nav index");
143143 const nav = ip.getNav(nav_index);
144144 try w.print(
145 \\name: '{}'
146 \\fqn: '{}'
145 \\name: '{f}'
146 \\fqn: '{f}'
147147 \\status: {s}
148148 \\created on generation: {d}
149149 \\
......@@ -234,7 +234,7 @@ fn handleCommand(zcu: *Zcu, output: *std.ArrayListUnmanaged(u8), cmd_str: []cons
234234 for (unit_info.deps.items, 0..) |dependee, i| {
235235 try w.print("[{d}] ", .{i});
236236 switch (dependee) {
237 .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{}", .{zcu.fmtDependee(dependee)}),
237 .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}),
238238 .nav_val, .nav_ty => |nav| try w.print("{s} {d}", .{ @tagName(dependee), @intFromEnum(nav) }),
239239 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
240240 .struct_type, .union_type, .enum_type => try w.print("type {d}", .{@intFromEnum(ip_index)}),
......@@ -260,7 +260,7 @@ fn handleCommand(zcu: *Zcu, output: *std.ArrayListUnmanaged(u8), cmd_str: []cons
260260 const ip_index: InternPool.Index = @enumFromInt(parseIndex(arg_str) orelse return w.writeAll("malformed ip index"));
261261 const create_gen = zcu.incremental_debug_state.types.get(ip_index) orelse return w.writeAll("unknown type");
262262 try w.print(
263 \\name: '{}'
263 \\name: '{f}'
264264 \\created on generation: {d}
265265 \\
266266 , .{
......@@ -365,7 +365,7 @@ fn printType(ty: Type, zcu: *const Zcu, w: anytype) !void {
365365 .union_type,
366366 .enum_type,
367367 .opaque_type,
368 => try w.print("{}[{d}]", .{ ty.containerTypeName(ip).fmt(ip), @intFromEnum(ty.toIntern()) }),
368 => try w.print("{f}[{d}]", .{ ty.containerTypeName(ip).fmt(ip), @intFromEnum(ty.toIntern()) }),
369369
370370 else => unreachable,
371371 }
src/InternPool.zig+30-31
......@@ -1881,23 +1881,23 @@ pub const NullTerminatedString = enum(u32) {
18811881 const FormatData = struct {
18821882 string: NullTerminatedString,
18831883 ip: *const InternPool,
1884 id: bool,
18841885 };
1885 fn format(
1886 data: FormatData,
1887 comptime specifier: []const u8,
1888 _: std.fmt.FormatOptions,
1889 writer: anytype,
1890 ) @TypeOf(writer).Error!void {
1886 fn format(data: FormatData, writer: *std.io.Writer) std.io.Writer.Error!void {
18911887 const slice = data.string.toSlice(data.ip);
1892 if (comptime std.mem.eql(u8, specifier, "")) {
1888 if (!data.id) {
18931889 try writer.writeAll(slice);
1894 } else if (comptime std.mem.eql(u8, specifier, "i")) {
1895 try writer.print("{p}", .{std.zig.fmtId(slice)});
1896 } else @compileError("invalid format string '" ++ specifier ++ "' for '" ++ @typeName(NullTerminatedString) ++ "'");
1890 } else {
1891 try writer.print("{f}", .{std.zig.fmtIdP(slice)});
1892 }
1893 }
1894
1895 pub fn fmt(string: NullTerminatedString, ip: *const InternPool) std.fmt.Formatter(FormatData, format) {
1896 return .{ .data = .{ .string = string, .ip = ip, .id = false } };
18971897 }
18981898
1899 pub fn fmt(string: NullTerminatedString, ip: *const InternPool) std.fmt.Formatter(format) {
1900 return .{ .data = .{ .string = string, .ip = ip } };
1899 pub fn fmtId(string: NullTerminatedString, ip: *const InternPool) std.fmt.Formatter(FormatData, format) {
1900 return .{ .data = .{ .string = string, .ip = ip, .id = true } };
19011901 }
19021902
19031903 const debug_state = InternPool.debug_state;
......@@ -9750,7 +9750,7 @@ fn finishFuncInstance(
97509750 const fn_namespace = fn_owner_nav.analysis.?.namespace;
97519751
97529752 // TODO: improve this name
9753 const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{}__anon_{d}", .{
9753 const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{f}__anon_{d}", .{
97549754 fn_owner_nav.name.fmt(ip), @intFromEnum(func_index),
97559755 }, .no_embedded_nulls);
97569756 const nav_index = try ip.createNav(gpa, tid, .{
......@@ -11259,8 +11259,9 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
1125911259}
1126011260
1126111261fn dumpAllFallible(ip: *const InternPool) anyerror!void {
11262 var bw = std.io.bufferedWriter(std.io.getStdErr().writer());
11263 const w = bw.writer();
11262 var buffer: [4096]u8 = undefined;
11263 const stderr_bw = std.debug.lockStderrWriter(&buffer);
11264 defer std.debug.unlockStderrWriter();
1126411265 for (ip.locals, 0..) |*local, tid| {
1126511266 const items = local.shared.items.view();
1126611267 for (
......@@ -11269,12 +11270,12 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
1126911270 0..,
1127011271 ) |tag, data, index| {
1127111272 const i = Index.Unwrapped.wrap(.{ .tid = @enumFromInt(tid), .index = @intCast(index) }, ip);
11272 try w.print("${d} = {s}(", .{ i, @tagName(tag) });
11273 try stderr_bw.print("${d} = {s}(", .{ i, @tagName(tag) });
1127311274 switch (tag) {
1127411275 .removed => {},
1127511276
11276 .simple_type => try w.print("{s}", .{@tagName(@as(SimpleType, @enumFromInt(@intFromEnum(i))))}),
11277 .simple_value => try w.print("{s}", .{@tagName(@as(SimpleValue, @enumFromInt(@intFromEnum(i))))}),
11277 .simple_type => try stderr_bw.print("{s}", .{@tagName(@as(SimpleType, @enumFromInt(@intFromEnum(i))))}),
11278 .simple_value => try stderr_bw.print("{s}", .{@tagName(@as(SimpleValue, @enumFromInt(@intFromEnum(i))))}),
1127811279
1127911280 .type_int_signed,
1128011281 .type_int_unsigned,
......@@ -11347,17 +11348,16 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
1134711348 .func_coerced,
1134811349 .union_value,
1134911350 .memoized_call,
11350 => try w.print("{d}", .{data}),
11351 => try stderr_bw.print("{d}", .{data}),
1135111352
1135211353 .opt_null,
1135311354 .type_slice,
1135411355 .only_possible_value,
11355 => try w.print("${d}", .{data}),
11356 => try stderr_bw.print("${d}", .{data}),
1135611357 }
11357 try w.writeAll(")\n");
11358 try stderr_bw.writeAll(")\n");
1135811359 }
1135911360 }
11360 try bw.flush();
1136111361}
1136211362
1136311363pub fn dumpGenericInstances(ip: *const InternPool, allocator: Allocator) void {
......@@ -11369,9 +11369,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
1136911369 defer arena_allocator.deinit();
1137011370 const arena = arena_allocator.allocator();
1137111371
11372 var bw = std.io.bufferedWriter(std.io.getStdErr().writer());
11373 const w = bw.writer();
11374
1137511372 var instances: std.AutoArrayHashMapUnmanaged(Index, std.ArrayListUnmanaged(Index)) = .empty;
1137611373 for (ip.locals, 0..) |*local, tid| {
1137711374 const items = local.shared.items.view().slice();
......@@ -11394,6 +11391,10 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
1139411391 }
1139511392 }
1139611393
11394 var buffer: [4096]u8 = undefined;
11395 const stderr_bw = std.debug.lockStderrWriter(&buffer);
11396 defer std.debug.unlockStderrWriter();
11397
1139711398 const SortContext = struct {
1139811399 values: []std.ArrayListUnmanaged(Index),
1139911400 pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {
......@@ -11405,23 +11406,21 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
1140511406 var it = instances.iterator();
1140611407 while (it.next()) |entry| {
1140711408 const generic_fn_owner_nav = ip.getNav(ip.funcDeclInfo(entry.key_ptr.*).owner_nav);
11408 try w.print("{} ({}): \n", .{ generic_fn_owner_nav.name.fmt(ip), entry.value_ptr.items.len });
11409 try stderr_bw.print("{f} ({d}): \n", .{ generic_fn_owner_nav.name.fmt(ip), entry.value_ptr.items.len });
1140911410 for (entry.value_ptr.items) |index| {
1141011411 const unwrapped_index = index.unwrap(ip);
1141111412 const func = ip.extraFuncInstance(unwrapped_index.tid, unwrapped_index.getExtra(ip), unwrapped_index.getData(ip));
1141211413 const owner_nav = ip.getNav(func.owner_nav);
11413 try w.print(" {}: (", .{owner_nav.name.fmt(ip)});
11414 try stderr_bw.print(" {f}: (", .{owner_nav.name.fmt(ip)});
1141411415 for (func.comptime_args.get(ip)) |arg| {
1141511416 if (arg != .none) {
1141611417 const key = ip.indexToKey(arg);
11417 try w.print(" {} ", .{key});
11418 try stderr_bw.print(" {} ", .{key});
1141811419 }
1141911420 }
11420 try w.writeAll(")\n");
11421 try stderr_bw.writeAll(")\n");
1142111422 }
1142211423 }
11423
11424 try bw.flush();
1142511424}
1142611425
1142711426pub fn getNav(ip: *const InternPool, index: Nav.Index) Nav {
src/Package.zig+1-1
......@@ -134,7 +134,7 @@ pub const Hash = struct {
134134 }
135135 var bin_digest: [Algo.digest_length]u8 = undefined;
136136 Algo.hash(sub_path, &bin_digest, .{});
137 _ = std.fmt.bufPrint(result.bytes[i..], "{}", .{std.fmt.fmtSliceHexLower(&bin_digest)}) catch unreachable;
137 _ = std.fmt.bufPrint(result.bytes[i..], "{x}", .{&bin_digest}) catch unreachable;
138138 return result;
139139 }
140140};
src/Package/Fetch.zig+64-61
......@@ -27,6 +27,22 @@
2727//! All of this must be done with only referring to the state inside this struct
2828//! because this work will be done in a dedicated thread.
2929
30const builtin = @import("builtin");
31const std = @import("std");
32const fs = std.fs;
33const assert = std.debug.assert;
34const ascii = std.ascii;
35const Allocator = std.mem.Allocator;
36const Cache = std.Build.Cache;
37const ThreadPool = std.Thread.Pool;
38const WaitGroup = std.Thread.WaitGroup;
39const Fetch = @This();
40const git = @import("Fetch/git.zig");
41const Package = @import("../Package.zig");
42const Manifest = Package.Manifest;
43const ErrorBundle = std.zig.ErrorBundle;
44const native_os = builtin.os.tag;
45
3046arena: std.heap.ArenaAllocator,
3147location: Location,
3248location_tok: std.zig.Ast.TokenIndex,
......@@ -185,7 +201,7 @@ pub const JobQueue = struct {
185201 const hash_slice = hash.toSlice();
186202
187203 try buf.writer().print(
188 \\ pub const {} = struct {{
204 \\ pub const {f} = struct {{
189205 \\
190206 , .{std.zig.fmtId(hash_slice)});
191207
......@@ -211,15 +227,15 @@ pub const JobQueue = struct {
211227 }
212228
213229 try buf.writer().print(
214 \\ pub const build_root = "{q}";
230 \\ pub const build_root = "{f}";
215231 \\
216 , .{fetch.package_root});
232 , .{std.fmt.alt(fetch.package_root, .formatEscapeString)});
217233
218234 if (fetch.has_build_zig) {
219235 try buf.writer().print(
220 \\ pub const build_zig = @import("{}");
236 \\ pub const build_zig = @import("{f}");
221237 \\
222 , .{std.zig.fmtEscapes(hash_slice)});
238 , .{std.zig.fmtString(hash_slice)});
223239 }
224240
225241 if (fetch.manifest) |*manifest| {
......@@ -230,8 +246,8 @@ pub const JobQueue = struct {
230246 for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, dep| {
231247 const h = depDigest(fetch.package_root, jq.global_cache, dep) orelse continue;
232248 try buf.writer().print(
233 " .{{ \"{}\", \"{}\" }},\n",
234 .{ std.zig.fmtEscapes(name), std.zig.fmtEscapes(h.toSlice()) },
249 " .{{ \"{f}\", \"{f}\" }},\n",
250 .{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) },
235251 );
236252 }
237253
......@@ -262,8 +278,8 @@ pub const JobQueue = struct {
262278 for (root_manifest.dependencies.keys(), root_manifest.dependencies.values()) |name, dep| {
263279 const h = depDigest(root_fetch.package_root, jq.global_cache, dep) orelse continue;
264280 try buf.writer().print(
265 " .{{ \"{}\", \"{}\" }},\n",
266 .{ std.zig.fmtEscapes(name), std.zig.fmtEscapes(h.toSlice()) },
281 " .{{ \"{f}\", \"{f}\" }},\n",
282 .{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) },
267283 );
268284 }
269285 try buf.appendSlice("};\n");
......@@ -353,7 +369,7 @@ pub fn run(f: *Fetch) RunError!void {
353369 if (!std.mem.startsWith(u8, pkg_root.sub_path, expected_prefix)) {
354370 return f.fail(
355371 f.location_tok,
356 try eb.printString("dependency path outside project: '{}'", .{pkg_root}),
372 try eb.printString("dependency path outside project: '{f}'", .{pkg_root}),
357373 );
358374 }
359375 }
......@@ -420,14 +436,14 @@ pub fn run(f: *Fetch) RunError!void {
420436 }
421437 if (f.job_queue.read_only) return f.fail(
422438 f.name_tok,
423 try eb.printString("package not found at '{}{s}'", .{
439 try eb.printString("package not found at '{f}{s}'", .{
424440 cache_root, pkg_sub_path,
425441 }),
426442 );
427443 },
428444 else => |e| {
429445 try eb.addRootErrorMessage(.{
430 .msg = try eb.printString("unable to open global package cache directory '{}{s}': {s}", .{
446 .msg = try eb.printString("unable to open global package cache directory '{f}{s}': {s}", .{
431447 cache_root, pkg_sub_path, @errorName(e),
432448 }),
433449 });
......@@ -604,7 +620,7 @@ pub fn computedPackageHash(f: *const Fetch) Package.Hash {
604620 const saturated_size = std.math.cast(u32, f.computed_hash.total_size) orelse std.math.maxInt(u32);
605621 if (f.manifest) |man| {
606622 var version_buffer: [32]u8 = undefined;
607 const version: []const u8 = std.fmt.bufPrint(&version_buffer, "{}", .{man.version}) catch &version_buffer;
623 const version: []const u8 = std.fmt.bufPrint(&version_buffer, "{f}", .{man.version}) catch &version_buffer;
608624 return .init(f.computed_hash.digest, man.name, version, man.id, saturated_size);
609625 }
610626 // In the future build.zig.zon fields will be added to allow overriding these values
......@@ -622,7 +638,7 @@ fn checkBuildFileExistence(f: *Fetch) RunError!void {
622638 error.FileNotFound => {},
623639 else => |e| {
624640 try eb.addRootErrorMessage(.{
625 .msg = try eb.printString("unable to access '{}{s}': {s}", .{
641 .msg = try eb.printString("unable to access '{f}{s}': {s}", .{
626642 f.package_root, Package.build_zig_basename, @errorName(e),
627643 }),
628644 });
......@@ -647,7 +663,7 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void {
647663 else => |e| {
648664 const file_path = try pkg_root.join(arena, Manifest.basename);
649665 try eb.addRootErrorMessage(.{
650 .msg = try eb.printString("unable to load package manifest '{}': {s}", .{
666 .msg = try eb.printString("unable to load package manifest '{f}': {s}", .{
651667 file_path, @errorName(e),
652668 }),
653669 });
......@@ -659,7 +675,7 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void {
659675 ast.* = try std.zig.Ast.parse(arena, manifest_bytes, .zon);
660676
661677 if (ast.errors.len > 0) {
662 const file_path = try std.fmt.allocPrint(arena, "{}" ++ fs.path.sep_str ++ Manifest.basename, .{pkg_root});
678 const file_path = try std.fmt.allocPrint(arena, "{f}" ++ fs.path.sep_str ++ Manifest.basename, .{pkg_root});
663679 try std.zig.putAstErrorsIntoBundle(arena, ast.*, file_path, eb);
664680 return error.FetchFailed;
665681 }
......@@ -672,7 +688,7 @@ fn loadManifest(f: *Fetch, pkg_root: Cache.Path) RunError!void {
672688 const manifest = &f.manifest.?;
673689
674690 if (manifest.errors.len > 0) {
675 const src_path = try eb.printString("{}" ++ fs.path.sep_str ++ "{s}", .{ pkg_root, Manifest.basename });
691 const src_path = try eb.printString("{f}" ++ fs.path.sep_str ++ "{s}", .{ pkg_root, Manifest.basename });
676692 try manifest.copyErrorsIntoBundle(ast.*, src_path, eb);
677693 return error.FetchFailed;
678694 }
......@@ -827,7 +843,7 @@ fn srcLoc(
827843 const ast = f.parent_manifest_ast orelse return .none;
828844 const eb = &f.error_bundle;
829845 const start_loc = ast.tokenLocation(0, tok);
830 const src_path = try eb.printString("{}" ++ fs.path.sep_str ++ Manifest.basename, .{f.parent_package_root});
846 const src_path = try eb.printString("{f}" ++ fs.path.sep_str ++ Manifest.basename, .{f.parent_package_root});
831847 const msg_off = 0;
832848 return eb.addSourceLocation(.{
833849 .src_path = src_path,
......@@ -961,7 +977,7 @@ fn initResource(f: *Fetch, uri: std.Uri, server_header_buffer: []u8) RunError!Re
961977 if (ascii.eqlIgnoreCase(uri.scheme, "file")) {
962978 const path = try uri.path.toRawMaybeAlloc(arena);
963979 return .{ .file = f.parent_package_root.openFile(path, .{}) catch |err| {
964 return f.fail(f.location_tok, try eb.printString("unable to open '{}{s}': {s}", .{
980 return f.fail(f.location_tok, try eb.printString("unable to open '{f}{s}': {s}", .{
965981 f.parent_package_root, path, @errorName(err),
966982 }));
967983 } };
......@@ -1063,13 +1079,16 @@ fn initResource(f: *Fetch, uri: std.Uri, server_header_buffer: []u8) RunError!Re
10631079 });
10641080 const notes_start = try eb.reserveNotes(notes_len);
10651081 eb.extra.items[notes_start] = @intFromEnum(try eb.addErrorMessage(.{
1066 .msg = try eb.printString("try .url = \"{;+/}#{}\",", .{ uri, want_oid }),
1082 .msg = try eb.printString("try .url = \"{f}#{f}\",", .{
1083 uri.fmt(.{ .scheme = true, .authority = true, .path = true }),
1084 want_oid,
1085 }),
10671086 }));
10681087 return error.FetchFailed;
10691088 }
10701089
10711090 var want_oid_buf: [git.Oid.max_formatted_length]u8 = undefined;
1072 _ = std.fmt.bufPrint(&want_oid_buf, "{}", .{want_oid}) catch unreachable;
1091 _ = std.fmt.bufPrint(&want_oid_buf, "{f}", .{want_oid}) catch unreachable;
10731092 var fetch_stream = session.fetch(&.{&want_oid_buf}, server_header_buffer) catch |err| {
10741093 return f.fail(f.location_tok, try eb.printString(
10751094 "unable to create fetch stream: {s}",
......@@ -1305,7 +1324,7 @@ fn unzip(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult {
13051324 .{@errorName(err)},
13061325 ));
13071326 if (len == 0) break;
1308 zip_file.writer().writeAll(buf[0..len]) catch |err| return f.fail(f.location_tok, try eb.printString(
1327 zip_file.deprecatedWriter().writeAll(buf[0..len]) catch |err| return f.fail(f.location_tok, try eb.printString(
13091328 "write temporary zip file failed: {s}",
13101329 .{@errorName(err)},
13111330 ));
......@@ -1358,7 +1377,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
13581377 var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });
13591378 defer pack_file.close();
13601379 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
1361 try fifo.pump(resource.fetch_stream.reader(), pack_file.writer());
1380 try fifo.pump(resource.fetch_stream.reader(), pack_file.deprecatedWriter());
13621381 try pack_file.sync();
13631382
13641383 var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });
......@@ -1366,7 +1385,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
13661385 {
13671386 const index_prog_node = f.prog_node.start("Index pack", 0);
13681387 defer index_prog_node.end();
1369 var index_buffered_writer = std.io.bufferedWriter(index_file.writer());
1388 var index_buffered_writer = std.io.bufferedWriter(index_file.deprecatedWriter());
13701389 try git.indexPack(gpa, object_format, pack_file, index_buffered_writer.writer());
13711390 try index_buffered_writer.flush();
13721391 try index_file.sync();
......@@ -1508,7 +1527,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute
15081527
15091528 while (walker.next() catch |err| {
15101529 try eb.addRootErrorMessage(.{ .msg = try eb.printString(
1511 "unable to walk temporary directory '{}': {s}",
1530 "unable to walk temporary directory '{f}': {s}",
15121531 .{ pkg_path, @errorName(err) },
15131532 ) });
15141533 return error.FetchFailed;
......@@ -1638,14 +1657,14 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute
16381657}
16391658
16401659fn dumpHashInfo(all_files: []const *const HashedFile) !void {
1641 const stdout = std.io.getStdOut();
1642 var bw = std.io.bufferedWriter(stdout.writer());
1660 const stdout: std.fs.File = .stdout();
1661 var bw = std.io.bufferedWriter(stdout.deprecatedWriter());
16431662 const w = bw.writer();
16441663
16451664 for (all_files) |hashed_file| {
1646 try w.print("{s}: {s}: {s}\n", .{
1665 try w.print("{s}: {x}: {s}\n", .{
16471666 @tagName(hashed_file.kind),
1648 std.fmt.fmtSliceHexLower(&hashed_file.hash),
1667 &hashed_file.hash,
16491668 hashed_file.normalized_path,
16501669 });
16511670 }
......@@ -1817,28 +1836,6 @@ pub fn depDigest(pkg_root: Cache.Path, cache_root: Cache.Directory, dep: Manifes
18171836 }
18181837}
18191838
1820const builtin = @import("builtin");
1821const std = @import("std");
1822const fs = std.fs;
1823const assert = std.debug.assert;
1824const ascii = std.ascii;
1825const Allocator = std.mem.Allocator;
1826const Cache = std.Build.Cache;
1827const ThreadPool = std.Thread.Pool;
1828const WaitGroup = std.Thread.WaitGroup;
1829const Fetch = @This();
1830const git = @import("Fetch/git.zig");
1831const Package = @import("../Package.zig");
1832const Manifest = Package.Manifest;
1833const ErrorBundle = std.zig.ErrorBundle;
1834const native_os = builtin.os.tag;
1835
1836test {
1837 _ = Filter;
1838 _ = FileType;
1839 _ = UnpackResult;
1840}
1841
18421839// Detects executable header: ELF or Macho-O magic header or shebang line.
18431840const FileHeader = struct {
18441841 header: [4]u8 = undefined,
......@@ -2056,15 +2053,15 @@ const UnpackResult = struct {
20562053 // output errors to string
20572054 var errors = try fetch.error_bundle.toOwnedBundle("");
20582055 defer errors.deinit(gpa);
2059 var out = std.ArrayList(u8).init(gpa);
2060 defer out.deinit();
2061 try errors.renderToWriter(.{ .ttyconf = .no_color }, out.writer());
2056 var aw: std.io.Writer.Allocating = .init(gpa);
2057 defer aw.deinit();
2058 try errors.renderToWriter(.{ .ttyconf = .no_color }, &aw.writer);
20622059 try std.testing.expectEqualStrings(
20632060 \\error: unable to unpack
20642061 \\ note: unable to create symlink from 'dir2/file2' to 'filename': SymlinkError
20652062 \\ note: file 'dir2/file4' has unsupported type 'x'
20662063 \\
2067 , out.items);
2064 , aw.getWritten());
20682065 }
20692066};
20702067
......@@ -2080,7 +2077,7 @@ test "zip" {
20802077 {
20812078 var zip_file = try tmp.dir.createFile("test.zip", .{});
20822079 defer zip_file.close();
2083 var bw = std.io.bufferedWriter(zip_file.writer());
2080 var bw = std.io.bufferedWriter(zip_file.deprecatedWriter());
20842081 var store: [test_files.len]std.zip.testutil.FileStore = undefined;
20852082 try std.zip.testutil.writeZip(bw.writer(), &test_files, &store, .{});
20862083 try bw.flush();
......@@ -2113,7 +2110,7 @@ test "zip with one root folder" {
21132110 {
21142111 var zip_file = try tmp.dir.createFile("test.zip", .{});
21152112 defer zip_file.close();
2116 var bw = std.io.bufferedWriter(zip_file.writer());
2113 var bw = std.io.bufferedWriter(zip_file.deprecatedWriter());
21172114 var store: [test_files.len]std.zip.testutil.FileStore = undefined;
21182115 try std.zip.testutil.writeZip(bw.writer(), &test_files, &store, .{});
21192116 try bw.flush();
......@@ -2431,9 +2428,15 @@ const TestFetchBuilder = struct {
24312428 if (notes_len > 0) {
24322429 try std.testing.expectEqual(notes_len, em.notes_len);
24332430 }
2434 var al = std.ArrayList(u8).init(std.testing.allocator);
2435 defer al.deinit();
2436 try errors.renderToWriter(.{ .ttyconf = .no_color }, al.writer());
2437 try std.testing.expectEqualStrings(msg, al.items);
2431 var aw: std.io.Writer.Allocating = .init(std.testing.allocator);
2432 defer aw.deinit();
2433 try errors.renderToWriter(.{ .ttyconf = .no_color }, &aw.writer);
2434 try std.testing.expectEqualStrings(msg, aw.getWritten());
24382435 }
24392436};
2437
2438test {
2439 _ = Filter;
2440 _ = FileType;
2441 _ = UnpackResult;
2442}
src/Package/Fetch/git.zig+40-31
......@@ -119,15 +119,8 @@ pub const Oid = union(Format) {
119119 } else error.InvalidOid;
120120 }
121121
122 pub fn format(
123 oid: Oid,
124 comptime fmt: []const u8,
125 options: std.fmt.FormatOptions,
126 writer: anytype,
127 ) @TypeOf(writer).Error!void {
128 _ = fmt;
129 _ = options;
130 try writer.print("{}", .{std.fmt.fmtSliceHexLower(oid.slice())});
122 pub fn format(oid: Oid, writer: *std.io.Writer) std.io.Writer.Error!void {
123 try writer.print("{x}", .{oid.slice()});
131124 }
132125
133126 pub fn slice(oid: *const Oid) []const u8 {
......@@ -353,7 +346,7 @@ const Odb = struct {
353346 fn init(allocator: Allocator, format: Oid.Format, pack_file: std.fs.File, index_file: std.fs.File) !Odb {
354347 try pack_file.seekTo(0);
355348 try index_file.seekTo(0);
356 const index_header = try IndexHeader.read(index_file.reader());
349 const index_header = try IndexHeader.read(index_file.deprecatedReader());
357350 return .{
358351 .format = format,
359352 .pack_file = pack_file,
......@@ -377,7 +370,7 @@ const Odb = struct {
377370 const base_object = while (true) {
378371 if (odb.cache.get(base_offset)) |base_object| break base_object;
379372
380 base_header = try EntryHeader.read(odb.format, odb.pack_file.reader());
373 base_header = try EntryHeader.read(odb.format, odb.pack_file.deprecatedReader());
381374 switch (base_header) {
382375 .ofs_delta => |ofs_delta| {
383376 try delta_offsets.append(odb.allocator, base_offset);
......@@ -390,7 +383,7 @@ const Odb = struct {
390383 base_offset = try odb.pack_file.getPos();
391384 },
392385 else => {
393 const base_data = try readObjectRaw(odb.allocator, odb.pack_file.reader(), base_header.uncompressedLength());
386 const base_data = try readObjectRaw(odb.allocator, odb.pack_file.deprecatedReader(), base_header.uncompressedLength());
394387 errdefer odb.allocator.free(base_data);
395388 const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };
396389 try odb.cache.put(odb.allocator, base_offset, base_object);
......@@ -420,7 +413,7 @@ const Odb = struct {
420413 const found_index = while (start_index < end_index) {
421414 const mid_index = start_index + (end_index - start_index) / 2;
422415 try odb.index_file.seekTo(IndexHeader.size + mid_index * oid_length);
423 const mid_oid = try Oid.readBytes(odb.format, odb.index_file.reader());
416 const mid_oid = try Oid.readBytes(odb.format, odb.index_file.deprecatedReader());
424417 switch (mem.order(u8, mid_oid.slice(), oid.slice())) {
425418 .lt => start_index = mid_index + 1,
426419 .gt => end_index = mid_index,
......@@ -431,12 +424,12 @@ const Odb = struct {
431424 const n_objects = odb.index_header.fan_out_table[255];
432425 const offset_values_start = IndexHeader.size + n_objects * (oid_length + 4);
433426 try odb.index_file.seekTo(offset_values_start + found_index * 4);
434 const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.reader().readInt(u32, .big));
427 const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.deprecatedReader().readInt(u32, .big));
435428 const pack_offset = pack_offset: {
436429 if (l1_offset.big) {
437430 const l2_offset_values_start = offset_values_start + n_objects * 4;
438431 try odb.index_file.seekTo(l2_offset_values_start + l1_offset.value * 4);
439 break :pack_offset try odb.index_file.reader().readInt(u64, .big);
432 break :pack_offset try odb.index_file.deprecatedReader().readInt(u64, .big);
440433 } else {
441434 break :pack_offset l1_offset.value;
442435 }
......@@ -669,13 +662,21 @@ pub const Session = struct {
669662 fn init(allocator: Allocator, uri: std.Uri) !Location {
670663 const scheme = try allocator.dupe(u8, uri.scheme);
671664 errdefer allocator.free(scheme);
672 const user = if (uri.user) |user| try std.fmt.allocPrint(allocator, "{user}", .{user}) else null;
665 const user = if (uri.user) |user| try std.fmt.allocPrint(allocator, "{f}", .{
666 std.fmt.alt(user, .formatUser),
667 }) else null;
673668 errdefer if (user) |s| allocator.free(s);
674 const password = if (uri.password) |password| try std.fmt.allocPrint(allocator, "{password}", .{password}) else null;
669 const password = if (uri.password) |password| try std.fmt.allocPrint(allocator, "{f}", .{
670 std.fmt.alt(password, .formatPassword),
671 }) else null;
675672 errdefer if (password) |s| allocator.free(s);
676 const host = if (uri.host) |host| try std.fmt.allocPrint(allocator, "{host}", .{host}) else null;
673 const host = if (uri.host) |host| try std.fmt.allocPrint(allocator, "{f}", .{
674 std.fmt.alt(host, .formatHost),
675 }) else null;
677676 errdefer if (host) |s| allocator.free(s);
678 const path = try std.fmt.allocPrint(allocator, "{path}", .{uri.path});
677 const path = try std.fmt.allocPrint(allocator, "{f}", .{
678 std.fmt.alt(uri.path, .formatPath),
679 });
679680 errdefer allocator.free(path);
680681 // The query and fragment are not used as part of the base server URI.
681682 return .{
......@@ -706,7 +707,9 @@ pub const Session = struct {
706707 fn getCapabilities(session: *Session, http_headers_buffer: []u8) !CapabilityIterator {
707708 var info_refs_uri = session.location.uri;
708709 {
709 const session_uri_path = try std.fmt.allocPrint(session.allocator, "{path}", .{session.location.uri.path});
710 const session_uri_path = try std.fmt.allocPrint(session.allocator, "{f}", .{
711 std.fmt.alt(session.location.uri.path, .formatPath),
712 });
710713 defer session.allocator.free(session_uri_path);
711714 info_refs_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(session.allocator, &.{ "/", session_uri_path, "info/refs" }) };
712715 }
......@@ -730,7 +733,9 @@ pub const Session = struct {
730733 if (request.response.status != .ok) return error.ProtocolError;
731734 const any_redirects_occurred = request.redirect_behavior.remaining() < max_redirects;
732735 if (any_redirects_occurred) {
733 const request_uri_path = try std.fmt.allocPrint(session.allocator, "{path}", .{request.uri.path});
736 const request_uri_path = try std.fmt.allocPrint(session.allocator, "{f}", .{
737 std.fmt.alt(request.uri.path, .formatPath),
738 });
734739 defer session.allocator.free(request_uri_path);
735740 if (!mem.endsWith(u8, request_uri_path, "/info/refs")) return error.UnparseableRedirect;
736741 var new_uri = request.uri;
......@@ -817,7 +822,9 @@ pub const Session = struct {
817822 pub fn listRefs(session: Session, options: ListRefsOptions) !RefIterator {
818823 var upload_pack_uri = session.location.uri;
819824 {
820 const session_uri_path = try std.fmt.allocPrint(session.allocator, "{path}", .{session.location.uri.path});
825 const session_uri_path = try std.fmt.allocPrint(session.allocator, "{f}", .{
826 std.fmt.alt(session.location.uri.path, .formatPath),
827 });
821828 defer session.allocator.free(session_uri_path);
822829 upload_pack_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(session.allocator, &.{ "/", session_uri_path, "git-upload-pack" }) };
823830 }
......@@ -932,7 +939,9 @@ pub const Session = struct {
932939 ) !FetchStream {
933940 var upload_pack_uri = session.location.uri;
934941 {
935 const session_uri_path = try std.fmt.allocPrint(session.allocator, "{path}", .{session.location.uri.path});
942 const session_uri_path = try std.fmt.allocPrint(session.allocator, "{f}", .{
943 std.fmt.alt(session.location.uri.path, .formatPath),
944 });
936945 defer session.allocator.free(session_uri_path);
937946 upload_pack_uri.path = .{ .percent_encoded = try std.fs.path.resolvePosix(session.allocator, &.{ "/", session_uri_path, "git-upload-pack" }) };
938947 }
......@@ -1026,7 +1035,7 @@ pub const Session = struct {
10261035 ProtocolError,
10271036 UnexpectedPacket,
10281037 };
1029 pub const Reader = std.io.Reader(*FetchStream, ReadError, read);
1038 pub const Reader = std.io.GenericReader(*FetchStream, ReadError, read);
10301039
10311040 const StreamCode = enum(u8) {
10321041 pack_data = 1,
......@@ -1320,7 +1329,7 @@ fn indexPackFirstPass(
13201329 index_entries: *std.AutoHashMapUnmanaged(Oid, IndexEntry),
13211330 pending_deltas: *std.ArrayListUnmanaged(IndexEntry),
13221331) !Oid {
1323 var pack_buffered_reader = std.io.bufferedReader(pack.reader());
1332 var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader());
13241333 var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader());
13251334 var pack_hashed_reader = std.compress.hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format));
13261335 const pack_reader = pack_hashed_reader.reader();
......@@ -1400,7 +1409,7 @@ fn indexPackHashDelta(
14001409 if (cache.get(base_offset)) |base_object| break base_object;
14011410
14021411 try pack.seekTo(base_offset);
1403 base_header = try EntryHeader.read(format, pack.reader());
1412 base_header = try EntryHeader.read(format, pack.deprecatedReader());
14041413 switch (base_header) {
14051414 .ofs_delta => |ofs_delta| {
14061415 try delta_offsets.append(allocator, base_offset);
......@@ -1411,7 +1420,7 @@ fn indexPackHashDelta(
14111420 base_offset = (index_entries.get(ref_delta.base_object) orelse return null).offset;
14121421 },
14131422 else => {
1414 const base_data = try readObjectRaw(allocator, pack.reader(), base_header.uncompressedLength());
1423 const base_data = try readObjectRaw(allocator, pack.deprecatedReader(), base_header.uncompressedLength());
14151424 errdefer allocator.free(base_data);
14161425 const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };
14171426 try cache.put(allocator, base_offset, base_object);
......@@ -1448,8 +1457,8 @@ fn resolveDeltaChain(
14481457
14491458 const delta_offset = delta_offsets[i];
14501459 try pack.seekTo(delta_offset);
1451 const delta_header = try EntryHeader.read(format, pack.reader());
1452 const delta_data = try readObjectRaw(allocator, pack.reader(), delta_header.uncompressedLength());
1460 const delta_header = try EntryHeader.read(format, pack.deprecatedReader());
1461 const delta_data = try readObjectRaw(allocator, pack.deprecatedReader(), delta_header.uncompressedLength());
14531462 defer allocator.free(delta_data);
14541463 var delta_stream = std.io.fixedBufferStream(delta_data);
14551464 const delta_reader = delta_stream.reader();
......@@ -1561,7 +1570,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
15611570
15621571 var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });
15631572 defer index_file.close();
1564 try indexPack(testing.allocator, format, pack_file, index_file.writer());
1573 try indexPack(testing.allocator, format, pack_file, index_file.deprecatedWriter());
15651574
15661575 // Arbitrary size limit on files read while checking the repository contents
15671576 // (all files in the test repo are known to be smaller than this)
......@@ -1678,7 +1687,7 @@ pub fn main() !void {
16781687 std.debug.print("Starting index...\n", .{});
16791688 var index_file = try git_dir.createFile("idx", .{ .read = true });
16801689 defer index_file.close();
1681 var index_buffered_writer = std.io.bufferedWriter(index_file.writer());
1690 var index_buffered_writer = std.io.bufferedWriter(index_file.deprecatedWriter());
16821691 try indexPack(allocator, format, pack_file, index_buffered_writer.writer());
16831692 try index_buffered_writer.flush();
16841693 try index_file.sync();
src/Package/Manifest.zig+2-2
......@@ -401,7 +401,7 @@ const Parse = struct {
401401 return fail(p, main_token, "name must be a valid bare zig identifier (hint: switch from string to enum literal)", .{});
402402
403403 if (name.len > max_name_len)
404 return fail(p, main_token, "name '{}' exceeds max length of {d}", .{
404 return fail(p, main_token, "name '{f}' exceeds max length of {d}", .{
405405 std.zig.fmtId(name), max_name_len,
406406 });
407407
......@@ -416,7 +416,7 @@ const Parse = struct {
416416 return fail(p, main_token, "name must be a valid bare zig identifier", .{});
417417
418418 if (ident_name.len > max_name_len)
419 return fail(p, main_token, "name '{}' exceeds max length of {d}", .{
419 return fail(p, main_token, "name '{f}' exceeds max length of {d}", .{
420420 std.zig.fmtId(ident_name), max_name_len,
421421 });
422422
src/Sema.zig+481-480
......@@ -5,6 +5,39 @@
55//! Does type checking, comptime control flow, and safety-check generation.
66//! This is the the heart of the Zig compiler.
77
8const std = @import("std");
9const math = std.math;
10const mem = std.mem;
11const Allocator = mem.Allocator;
12const assert = std.debug.assert;
13const log = std.log.scoped(.sema);
14
15const Sema = @This();
16const Value = @import("Value.zig");
17const MutableValue = @import("mutable_value.zig").MutableValue;
18const Type = @import("Type.zig");
19const Air = @import("Air.zig");
20const Zir = std.zig.Zir;
21const Zcu = @import("Zcu.zig");
22const trace = @import("tracy.zig").trace;
23const Namespace = Zcu.Namespace;
24const CompileError = Zcu.CompileError;
25const SemaError = Zcu.SemaError;
26const LazySrcLoc = Zcu.LazySrcLoc;
27const RangeSet = @import("RangeSet.zig");
28const target_util = @import("target.zig");
29const Package = @import("Package.zig");
30const crash_report = @import("crash_report.zig");
31const build_options = @import("build_options");
32const Compilation = @import("Compilation.zig");
33const InternPool = @import("InternPool.zig");
34const Alignment = InternPool.Alignment;
35const AnalUnit = InternPool.AnalUnit;
36const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
37const Cache = std.Build.Cache;
38const LowerZon = @import("Sema/LowerZon.zig");
39const arith = @import("Sema/arith.zig");
40
841pt: Zcu.PerThread,
942/// Alias to `zcu.gpa`.
1043gpa: Allocator,
......@@ -157,39 +190,6 @@ pub fn getComptimeAlloc(sema: *Sema, idx: ComptimeAllocIndex) *ComptimeAlloc {
157190 return &sema.comptime_allocs.items[@intFromEnum(idx)];
158191}
159192
160const std = @import("std");
161const math = std.math;
162const mem = std.mem;
163const Allocator = mem.Allocator;
164const assert = std.debug.assert;
165const log = std.log.scoped(.sema);
166
167const Sema = @This();
168const Value = @import("Value.zig");
169const MutableValue = @import("mutable_value.zig").MutableValue;
170const Type = @import("Type.zig");
171const Air = @import("Air.zig");
172const Zir = std.zig.Zir;
173const Zcu = @import("Zcu.zig");
174const trace = @import("tracy.zig").trace;
175const Namespace = Zcu.Namespace;
176const CompileError = Zcu.CompileError;
177const SemaError = Zcu.SemaError;
178const LazySrcLoc = Zcu.LazySrcLoc;
179const RangeSet = @import("RangeSet.zig");
180const target_util = @import("target.zig");
181const Package = @import("Package.zig");
182const crash_report = @import("crash_report.zig");
183const build_options = @import("build_options");
184const Compilation = @import("Compilation.zig");
185const InternPool = @import("InternPool.zig");
186const Alignment = InternPool.Alignment;
187const AnalUnit = InternPool.AnalUnit;
188const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
189const Cache = std.Build.Cache;
190const LowerZon = @import("Sema/LowerZon.zig");
191const arith = @import("Sema/arith.zig");
192
193193pub const default_branch_quota = 1000;
194194
195195pub const InferredErrorSet = struct {
......@@ -888,7 +888,7 @@ const ComptimeReason = union(enum) {
888888 /// Evaluating at comptime because of a comptime-only type. This field is separate so that
889889 /// the type in question can be included in the error message. AstGen could never emit this
890890 /// reason, because it knows nothing of types.
891 /// The format string looks like "foo '{}' bar", where "{}" is the comptime-only type.
891 /// The format string looks like "foo '{f}' bar", where "{f}" is the comptime-only type.
892892 /// We will then explain why this type is comptime-only.
893893 comptime_only: struct {
894894 ty: Type,
......@@ -930,17 +930,17 @@ const ComptimeReason = union(enum) {
930930 .struct_init => .{ "initializer of comptime-only struct", "must be comptime-known" },
931931 .tuple_init => .{ "initializer of comptime-only tuple", "must be comptime-known" },
932932 };
933 try sema.errNote(src, err_msg, "{s} '{}' {s}", .{ pre, co.ty.fmt(sema.pt), post });
933 try sema.errNote(src, err_msg, "{s} '{f}' {s}", .{ pre, co.ty.fmt(sema.pt), post });
934934 try sema.explainWhyTypeIsComptime(err_msg, src, co.ty);
935935 },
936936 .comptime_only_param_ty => |co| {
937 try sema.errNote(src, err_msg, "argument to parameter with comptime-only type '{}' must be comptime-known", .{co.ty.fmt(sema.pt)});
937 try sema.errNote(src, err_msg, "argument to parameter with comptime-only type '{f}' must be comptime-known", .{co.ty.fmt(sema.pt)});
938938 try sema.errNote(co.param_ty_src, err_msg, "parameter type declared here", .{});
939939 try sema.explainWhyTypeIsComptime(err_msg, src, co.ty);
940940 },
941941 .comptime_only_ret_ty => |co| {
942942 const function_with: []const u8 = if (co.is_generic_inst) "generic function instantiated with" else "function with";
943 try sema.errNote(src, err_msg, "call to {s} comptime-only return type '{}' is evaluated at comptime", .{ function_with, co.ty.fmt(sema.pt) });
943 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) });
944944 try sema.errNote(co.ret_ty_src, err_msg, "return type declared here", .{});
945945 try sema.explainWhyTypeIsComptime(err_msg, src, co.ty);
946946 },
......@@ -1144,7 +1144,7 @@ fn analyzeBodyInner(
11441144
11451145 // The hashmap lookup in here is a little expensive, and LLVM fails to optimize it away.
11461146 if (build_options.enable_logging) {
1147 std.log.scoped(.sema_zir).debug("sema ZIR {} %{d}", .{ path: {
1147 std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path: {
11481148 const file_index = block.src_base_inst.resolveFile(&zcu.intern_pool);
11491149 const file = zcu.fileByIndex(file_index);
11501150 break :path file.path.fmt(zcu.comp);
......@@ -1905,7 +1905,7 @@ fn analyzeBodyInner(
19051905 const err_union = try sema.resolveInst(extra.data.operand);
19061906 const err_union_ty = sema.typeOf(err_union);
19071907 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
1908 return sema.fail(block, operand_src, "expected error union type, found '{}'", .{
1908 return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{
19091909 err_union_ty.fmt(pt),
19101910 });
19111911 }
......@@ -2339,7 +2339,7 @@ pub fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) Compile
23392339
23402340fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: Type, rhs_ty: Type) CompileError {
23412341 const pt = sema.pt;
2342 return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{
2342 return sema.fail(block, src, "remainder division with '{f}' and '{f}': signed integers and floats must use @rem or @mod", .{
23432343 lhs_ty.fmt(pt), rhs_ty.fmt(pt),
23442344 });
23452345}
......@@ -2347,7 +2347,7 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T
23472347fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non_optional_ty: Type) CompileError {
23482348 const pt = sema.pt;
23492349 const msg = msg: {
2350 const msg = try sema.errMsg(src, "expected optional type, found '{}'", .{
2350 const msg = try sema.errMsg(src, "expected optional type, found '{f}'", .{
23512351 non_optional_ty.fmt(pt),
23522352 });
23532353 errdefer msg.destroy(sema.gpa);
......@@ -2363,12 +2363,12 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non
23632363fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
23642364 const pt = sema.pt;
23652365 const msg = msg: {
2366 const msg = try sema.errMsg(src, "type '{}' does not support array initialization syntax", .{
2366 const msg = try sema.errMsg(src, "type '{f}' does not support array initialization syntax", .{
23672367 ty.fmt(pt),
23682368 });
23692369 errdefer msg.destroy(sema.gpa);
23702370 if (ty.isSlice(pt.zcu)) {
2371 try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(pt.zcu).fmt(pt)});
2371 try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.elemType2(pt.zcu).fmt(pt)});
23722372 }
23732373 break :msg msg;
23742374 };
......@@ -2377,7 +2377,7 @@ fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty
23772377
23782378fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
23792379 const pt = sema.pt;
2380 return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{
2380 return sema.fail(block, src, "type '{f}' does not support struct initialization syntax", .{
23812381 ty.fmt(pt),
23822382 });
23832383}
......@@ -2390,7 +2390,7 @@ fn failWithErrorSetCodeMissing(
23902390 src_err_set_ty: Type,
23912391) CompileError {
23922392 const pt = sema.pt;
2393 return sema.fail(block, src, "expected type '{}', found type '{}'", .{
2393 return sema.fail(block, src, "expected type '{f}', found type '{f}'", .{
23942394 dest_err_set_ty.fmt(pt), src_err_set_ty.fmt(pt),
23952395 });
23962396}
......@@ -2398,7 +2398,7 @@ fn failWithErrorSetCodeMissing(
23982398pub fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: ?usize) CompileError {
23992399 const pt = sema.pt;
24002400 return sema.failWithOwnedErrorMsg(block, msg: {
2401 const msg = try sema.errMsg(src, "overflow of integer type '{}' with value '{}'", .{
2401 const msg = try sema.errMsg(src, "overflow of integer type '{f}' with value '{f}'", .{
24022402 int_ty.fmt(pt), val.fmtValueSema(pt, sema),
24032403 });
24042404 errdefer msg.destroy(sema.gpa);
......@@ -2448,7 +2448,7 @@ fn failWithInvalidFieldAccess(
24482448 const child_ty = inner_ty.optionalChild(zcu);
24492449 if (!typeSupportsFieldAccess(zcu, child_ty, field_name)) break :opt;
24502450 const msg = msg: {
2451 const msg = try sema.errMsg(src, "optional type '{}' does not support field access", .{object_ty.fmt(pt)});
2451 const msg = try sema.errMsg(src, "optional type '{f}' does not support field access", .{object_ty.fmt(pt)});
24522452 errdefer msg.destroy(sema.gpa);
24532453 try sema.errNote(src, msg, "consider using '.?', 'orelse', or 'if'", .{});
24542454 break :msg msg;
......@@ -2458,14 +2458,14 @@ fn failWithInvalidFieldAccess(
24582458 const child_ty = inner_ty.errorUnionPayload(zcu);
24592459 if (!typeSupportsFieldAccess(zcu, child_ty, field_name)) break :err;
24602460 const msg = msg: {
2461 const msg = try sema.errMsg(src, "error union type '{}' does not support field access", .{object_ty.fmt(pt)});
2461 const msg = try sema.errMsg(src, "error union type '{f}' does not support field access", .{object_ty.fmt(pt)});
24622462 errdefer msg.destroy(sema.gpa);
24632463 try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{});
24642464 break :msg msg;
24652465 };
24662466 return sema.failWithOwnedErrorMsg(block, msg);
24672467 }
2468 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(pt)});
2468 return sema.fail(block, src, "type '{f}' does not support field access", .{object_ty.fmt(pt)});
24692469}
24702470
24712471fn typeSupportsFieldAccess(zcu: *const Zcu, ty: Type, field_name: InternPool.NullTerminatedString) bool {
......@@ -2494,7 +2494,7 @@ fn failWithComptimeErrorRetTrace(
24942494 const pt = sema.pt;
24952495 const zcu = pt.zcu;
24962496 const msg = msg: {
2497 const msg = try sema.errMsg(src, "caught unexpected error '{}'", .{name.fmt(&zcu.intern_pool)});
2497 const msg = try sema.errMsg(src, "caught unexpected error '{f}'", .{name.fmt(&zcu.intern_pool)});
24982498 errdefer msg.destroy(sema.gpa);
24992499
25002500 for (sema.comptime_err_ret_trace.items) |src_loc| {
......@@ -2763,7 +2763,7 @@ fn zirTupleDecl(
27632763 const coerced_field_init = try sema.coerce(block, field_type, uncoerced_field_init, init_src);
27642764 const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ .simple = .tuple_field_default_value });
27652765 if (field_init_val.canMutateComptimeVarState(zcu)) {
2766 const field_name = try zcu.intern_pool.getOrPutStringFmt(gpa, pt.tid, "{}", .{field_index}, .no_embedded_nulls);
2766 const field_name = try zcu.intern_pool.getOrPutStringFmt(gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
27672767 return sema.failWithContainsReferenceToComptimeVar(block, init_src, field_name, "field default value", field_init_val);
27682768 }
27692769 break :init field_init_val.toIntern();
......@@ -3005,7 +3005,7 @@ pub fn createTypeName(
30053005 inst: ?Zir.Inst.Index,
30063006 /// This is used purely to give the type a unique name in the `anon` case.
30073007 type_index: InternPool.Index,
3008) !struct {
3008) CompileError!struct {
30093009 name: InternPool.NullTerminatedString,
30103010 nav: InternPool.Nav.Index.Optional,
30113011} {
......@@ -3024,11 +3024,10 @@ pub fn createTypeName(
30243024 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
30253025 const zir_tags = sema.code.instructions.items(.tag);
30263026
3027 var buf: std.ArrayListUnmanaged(u8) = .empty;
3028 defer buf.deinit(gpa);
3029
3030 const writer = buf.writer(gpa);
3031 try writer.print("{}(", .{block.type_name_ctx.fmt(ip)});
3027 var aw: std.io.Writer.Allocating = .init(gpa);
3028 defer aw.deinit();
3029 const w = &aw.writer;
3030 w.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory;
30323031
30333032 var arg_i: usize = 0;
30343033 for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) {
......@@ -3041,18 +3040,18 @@ pub fn createTypeName(
30413040 // result in a compile error.
30423041 const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat
30433042
3044 if (arg_i != 0) try writer.writeByte(',');
3043 if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory;
30453044
30463045 // Limiting the depth here helps avoid type names getting too long, which
30473046 // in turn helps to avoid unreasonably long symbol names for namespaced
30483047 // symbols. Such names should ideally be human-readable, and additionally,
30493048 // some tooling may not support very long symbol names.
3050 try writer.print("{}", .{Value.fmtValueSemaFull(.{
3049 w.print("{f}", .{Value.fmtValueSemaFull(.{
30513050 .val = arg_val,
30523051 .pt = pt,
30533052 .opt_sema = sema,
30543053 .depth = 1,
3055 })});
3054 })}) catch return error.OutOfMemory;
30563055
30573056 arg_i += 1;
30583057 continue;
......@@ -3060,9 +3059,9 @@ pub fn createTypeName(
30603059 else => continue,
30613060 };
30623061
3063 try writer.writeByte(')');
3062 w.writeByte(')') catch return error.OutOfMemory;
30643063 return .{
3065 .name = try ip.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls),
3064 .name = try ip.getOrPutString(gpa, pt.tid, aw.getWritten(), .no_embedded_nulls),
30663065 .nav = .none,
30673066 };
30683067 },
......@@ -3074,7 +3073,7 @@ pub fn createTypeName(
30743073 for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) {
30753074 .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {
30763075 return .{
3077 .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.{s}", .{
3076 .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}.{s}", .{
30783077 block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code),
30793078 }, .no_embedded_nulls),
30803079 .nav = .none,
......@@ -3097,7 +3096,7 @@ pub fn createTypeName(
30973096 // that builtin from the language, we can consider this.
30983097
30993098 return .{
3100 .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}__{s}_{d}", .{
3099 .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}__{s}_{d}", .{
31013100 block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index),
31023101 }, .no_embedded_nulls),
31033102 .nav = .none,
......@@ -3581,7 +3580,7 @@ fn ensureResultUsed(
35813580 },
35823581 else => {
35833582 const msg = msg: {
3584 const msg = try sema.errMsg(src, "value of type '{}' ignored", .{ty.fmt(pt)});
3583 const msg = try sema.errMsg(src, "value of type '{f}' ignored", .{ty.fmt(pt)});
35853584 errdefer msg.destroy(sema.gpa);
35863585 try sema.errNote(src, msg, "all non-void values must be used", .{});
35873586 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
38513850 // The value was initialized through RLS, so we didn't detect the runtime condition earlier.
38523851 // TODO: source location of runtime control flow
38533852 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
3854 return sema.fail(block, init_src, "value with comptime-only type '{}' depends on runtime control flow", .{elem_ty.fmt(pt)});
3853 return sema.fail(block, init_src, "value with comptime-only type '{f}' depends on runtime control flow", .{elem_ty.fmt(pt)});
38553854 }
38563855
38573856 // This is a runtime value.
......@@ -4348,7 +4347,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
43484347 // The alloc wasn't comptime-known per the above logic, so the
43494348 // type cannot be comptime-only.
43504349 // TODO: source location of runtime control flow
4351 return sema.fail(block, src, "value with comptime-only type '{}' depends on runtime control flow", .{final_elem_ty.fmt(pt)});
4350 return sema.fail(block, src, "value with comptime-only type '{f}' depends on runtime control flow", .{final_elem_ty.fmt(pt)});
43524351 }
43534352 if (sema.func_is_naked and try final_elem_ty.hasRuntimeBitsSema(pt)) {
43544353 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.
44454444 if (!object_ty.isIndexable(zcu)) {
44464445 // Instead of using checkIndexable we customize this error.
44474446 const msg = msg: {
4448 const msg = try sema.errMsg(arg_src, "type '{}' is not indexable and not a range", .{object_ty.fmt(pt)});
4447 const msg = try sema.errMsg(arg_src, "type '{f}' is not indexable and not a range", .{object_ty.fmt(pt)});
44494448 errdefer msg.destroy(sema.gpa);
44504449 try sema.errNote(arg_src, msg, "for loop operand must be a range, array, slice, tuple, or vector", .{});
44514450
......@@ -4480,10 +4479,10 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
44804479 .for_node_offset = inst_data.src_node,
44814480 .input_index = len_idx,
44824481 } });
4483 try sema.errNote(a_src, msg, "length {} here", .{
4482 try sema.errNote(a_src, msg, "length {f} here", .{
44844483 v.fmtValueSema(pt, sema),
44854484 });
4486 try sema.errNote(arg_src, msg, "length {} here", .{
4485 try sema.errNote(arg_src, msg, "length {f} here", .{
44874486 arg_val.fmtValueSema(pt, sema),
44884487 });
44894488 break :msg msg;
......@@ -4515,7 +4514,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
45154514 .for_node_offset = inst_data.src_node,
45164515 .input_index = i,
45174516 } });
4518 try sema.errNote(arg_src, msg, "type '{}' has no upper bound", .{
4517 try sema.errNote(arg_src, msg, "type '{f}' has no upper bound", .{
45194518 object_ty.fmt(pt),
45204519 });
45214520 }
......@@ -4591,7 +4590,7 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
45914590 switch (val_ty.zigTypeTag(zcu)) {
45924591 .array, .vector => {},
45934592 else => if (!val_ty.isTuple(zcu)) {
4594 return sema.fail(block, src, "expected array of '{}', found '{}'", .{ elem_ty.fmt(pt), val_ty.fmt(pt) });
4593 return sema.fail(block, src, "expected array of '{f}', found '{f}'", .{ elem_ty.fmt(pt), val_ty.fmt(pt) });
45954594 },
45964595 }
45974596 const want_ty = try pt.arrayType(.{
......@@ -4665,7 +4664,7 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
46654664 const ty_operand = try sema.resolveTypeOrPoison(block, src, un_tok.operand) orelse return;
46664665 if (ty_operand.optEuBaseType(zcu).zigTypeTag(zcu) != .pointer) {
46674666 return sema.failWithOwnedErrorMsg(block, msg: {
4668 const msg = try sema.errMsg(src, "expected type '{}', found pointer", .{ty_operand.fmt(pt)});
4667 const msg = try sema.errMsg(src, "expected type '{f}', found pointer", .{ty_operand.fmt(pt)});
46694668 errdefer msg.destroy(sema.gpa);
46704669 try sema.errNote(src, msg, "address-of operator always returns a pointer", .{});
46714670 break :msg msg;
......@@ -5074,7 +5073,7 @@ fn validateStructInit(
50745073 }
50755074 continue;
50765075 };
5077 const template = "missing struct field: {}";
5076 const template = "missing struct field: {f}";
50785077 const args = .{field_name.fmt(ip)};
50795078 if (root_msg) |msg| {
50805079 try sema.errNote(init_src, msg, template, args);
......@@ -5204,7 +5203,7 @@ fn validateStructInit(
52045203 }
52055204 continue;
52065205 };
5207 const template = "missing struct field: {}";
5206 const template = "missing struct field: {f}";
52085207 const args = .{field_name.fmt(ip)};
52095208 if (root_msg) |msg| {
52105209 try sema.errNote(init_src, msg, template, args);
......@@ -5508,11 +5507,11 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
55085507 const operand_ty = sema.typeOf(operand);
55095508
55105509 if (operand_ty.zigTypeTag(zcu) != .pointer) {
5511 return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(pt)});
5510 return sema.fail(block, src, "cannot dereference non-pointer type '{f}'", .{operand_ty.fmt(pt)});
55125511 } else switch (operand_ty.ptrSize(zcu)) {
55135512 .one, .c => {},
5514 .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(pt)}),
5515 .slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(pt)}),
5513 .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{f}'", .{operand_ty.fmt(pt)}),
5514 .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}),
55165515 }
55175516
55185517 if ((try sema.typeHasOnePossibleValue(operand_ty.childType(zcu))) != null) {
......@@ -5529,7 +5528,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
55295528 const msg = msg: {
55305529 const msg = try sema.errMsg(
55315530 src,
5532 "values of type '{}' must be comptime-known, but operand value is runtime-known",
5531 "values of type '{f}' must be comptime-known, but operand value is runtime-known",
55335532 .{elem_ty.fmt(pt)},
55345533 );
55355534 errdefer msg.destroy(sema.gpa);
......@@ -5561,7 +5560,7 @@ fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
55615560
55625561 if (!typeIsDestructurable(operand_ty, zcu)) {
55635562 return sema.failWithOwnedErrorMsg(block, msg: {
5564 const msg = try sema.errMsg(src, "type '{}' cannot be destructured", .{operand_ty.fmt(pt)});
5563 const msg = try sema.errMsg(src, "type '{f}' cannot be destructured", .{operand_ty.fmt(pt)});
55655564 errdefer msg.destroy(sema.gpa);
55665565 try sema.errNote(destructure_src, msg, "result destructured here", .{});
55675566 if (operand_ty.zigTypeTag(pt.zcu) == .error_union) {
......@@ -5575,9 +5574,8 @@ fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
55755574
55765575 if (operand_ty.arrayLen(zcu) != extra.expect_len) {
55775576 return sema.failWithOwnedErrorMsg(block, msg: {
5578 const msg = try sema.errMsg(src, "expected {} elements for destructure, found {}", .{
5579 extra.expect_len,
5580 operand_ty.arrayLen(zcu),
5577 const msg = try sema.errMsg(src, "expected {d} elements for destructure, found {d}", .{
5578 extra.expect_len, operand_ty.arrayLen(zcu),
55815579 });
55825580 errdefer msg.destroy(sema.gpa);
55835581 try sema.errNote(destructure_src, msg, "result destructured here", .{});
......@@ -5604,12 +5602,12 @@ fn failWithBadMemberAccess(
56045602 else => unreachable,
56055603 };
56065604 if (agg_ty.typeDeclInst(zcu)) |inst| if ((inst.resolve(ip) orelse return error.AnalysisFail) == .main_struct_inst) {
5607 return sema.fail(block, field_src, "root source file struct '{}' has no member named '{}'", .{
5605 return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{
56085606 agg_ty.fmt(pt), field_name.fmt(ip),
56095607 });
56105608 };
56115609
5612 return sema.fail(block, field_src, "{s} '{}' has no member named '{}'", .{
5610 return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{
56135611 kw_name, agg_ty.fmt(pt), field_name.fmt(ip),
56145612 });
56155613}
......@@ -5629,7 +5627,7 @@ fn failWithBadStructFieldAccess(
56295627 const msg = msg: {
56305628 const msg = try sema.errMsg(
56315629 field_src,
5632 "no field named '{}' in struct '{}'",
5630 "no field named '{f}' in struct '{f}'",
56335631 .{ field_name.fmt(ip), struct_type.name.fmt(ip) },
56345632 );
56355633 errdefer msg.destroy(sema.gpa);
......@@ -5655,7 +5653,7 @@ fn failWithBadUnionFieldAccess(
56555653 const msg = msg: {
56565654 const msg = try sema.errMsg(
56575655 field_src,
5658 "no field named '{}' in union '{}'",
5656 "no field named '{f}' in union '{f}'",
56595657 .{ field_name.fmt(ip), union_obj.name.fmt(ip) },
56605658 );
56615659 errdefer msg.destroy(gpa);
......@@ -5907,30 +5905,29 @@ fn zirCompileLog(
59075905 const zcu = pt.zcu;
59085906 const gpa = zcu.gpa;
59095907
5910 var buf: std.ArrayListUnmanaged(u8) = .empty;
5911 defer buf.deinit(gpa);
5912
5913 const writer = buf.writer(gpa);
5908 var aw: std.io.Writer.Allocating = .init(gpa);
5909 defer aw.deinit();
5910 const writer = &aw.writer;
59145911
59155912 const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
59165913 const src_node = extra.data.src_node;
59175914 const args = sema.code.refSlice(extra.end, extended.small);
59185915
59195916 for (args, 0..) |arg_ref, i| {
5920 if (i != 0) try writer.print(", ", .{});
5917 if (i != 0) writer.writeAll(", ") catch return error.OutOfMemory;
59215918
59225919 const arg = try sema.resolveInst(arg_ref);
59235920 const arg_ty = sema.typeOf(arg);
59245921 if (try sema.resolveValueResolveLazy(arg)) |val| {
5925 try writer.print("@as({}, {})", .{
5922 writer.print("@as({f}, {f})", .{
59265923 arg_ty.fmt(pt), val.fmtValueSema(pt, sema),
5927 });
5924 }) catch return error.OutOfMemory;
59285925 } else {
5929 try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(pt)});
5926 writer.print("@as({f}, [runtime value])", .{arg_ty.fmt(pt)}) catch return error.OutOfMemory;
59305927 }
59315928 }
59325929
5933 const line_data = try zcu.intern_pool.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls);
5930 const line_data = try zcu.intern_pool.getOrPutString(gpa, pt.tid, aw.getWritten(), .no_embedded_nulls);
59345931
59355932 const line_idx: Zcu.CompileLogLine.Index = if (zcu.free_compile_log_lines.pop()) |idx| idx: {
59365933 zcu.compile_log_lines.items[@intFromEnum(idx)] = .{
......@@ -6472,7 +6469,7 @@ fn resolveAnalyzedBlock(
64726469 const type_src = src; // TODO: better source location
64736470 if (try resolved_ty.comptimeOnlySema(pt)) {
64746471 const msg = msg: {
6475 const msg = try sema.errMsg(type_src, "value with comptime-only type '{}' depends on runtime control flow", .{resolved_ty.fmt(pt)});
6472 const msg = try sema.errMsg(type_src, "value with comptime-only type '{f}' depends on runtime control flow", .{resolved_ty.fmt(pt)});
64766473 errdefer msg.destroy(sema.gpa);
64776474
64786475 const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?;
......@@ -6588,7 +6585,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
65886585
65896586 {
65906587 if (ptr_ty.zigTypeTag(zcu) != .pointer) {
6591 return sema.fail(block, ptr_src, "expected pointer type, found '{}'", .{ptr_ty.fmt(pt)});
6588 return sema.fail(block, ptr_src, "expected pointer type, found '{f}'", .{ptr_ty.fmt(pt)});
65926589 }
65936590 const ptr_ty_info = ptr_ty.ptrInfo(zcu);
65946591 if (ptr_ty_info.flags.size == .slice) {
......@@ -6611,7 +6608,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
66116608 const export_ty = Value.fromInterned(uav.val).typeOf(zcu);
66126609 if (!try sema.validateExternType(export_ty, .other)) {
66136610 return sema.failWithOwnedErrorMsg(block, msg: {
6614 const msg = try sema.errMsg(src, "unable to export type '{}'", .{export_ty.fmt(pt)});
6611 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
66156612 errdefer msg.destroy(sema.gpa);
66166613 try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
66176614 try sema.addDeclaredHereNote(msg, export_ty);
......@@ -6663,7 +6660,7 @@ pub fn analyzeExport(
66636660
66646661 if (!try sema.validateExternType(export_ty, .other)) {
66656662 return sema.failWithOwnedErrorMsg(block, msg: {
6666 const msg = try sema.errMsg(src, "unable to export type '{}'", .{export_ty.fmt(pt)});
6663 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
66676664 errdefer msg.destroy(gpa);
66686665
66696666 try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
......@@ -7287,7 +7284,7 @@ fn checkCallArgumentCount(
72877284 opt_child.childType(zcu).zigTypeTag(zcu) == .@"fn"))
72887285 {
72897286 const msg = msg: {
7290 const msg = try sema.errMsg(func_src, "cannot call optional type '{}'", .{
7287 const msg = try sema.errMsg(func_src, "cannot call optional type '{f}'", .{
72917288 callee_ty.fmt(pt),
72927289 });
72937290 errdefer msg.destroy(sema.gpa);
......@@ -7299,7 +7296,7 @@ fn checkCallArgumentCount(
72997296 },
73007297 else => {},
73017298 }
7302 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(pt)});
7299 return sema.fail(block, func_src, "type '{f}' not a function", .{callee_ty.fmt(pt)});
73037300 };
73047301
73057302 const func_ty_info = zcu.typeToFunc(func_ty).?;
......@@ -7362,7 +7359,7 @@ fn callBuiltin(
73627359 },
73637360 else => {},
73647361 }
7365 std.debug.panic("type '{}' is not a function calling builtin fn", .{callee_ty.fmt(pt)});
7362 std.debug.panic("type '{f}' is not a function calling builtin fn", .{callee_ty.fmt(pt)});
73667363 };
73677364
73687365 const func_ty_info = zcu.typeToFunc(func_ty).?;
......@@ -7746,7 +7743,7 @@ fn analyzeCall(
77467743
77477744 if (!param_ty.isValidParamType(zcu)) {
77487745 const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
7749 return sema.fail(block, param_src, "parameter of {s}type '{}' not allowed", .{
7746 return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{
77507747 opaque_str, param_ty.fmt(pt),
77517748 });
77527749 }
......@@ -7843,7 +7840,7 @@ fn analyzeCall(
78437840
78447841 if (!full_ty.isValidReturnType(zcu)) {
78457842 const opaque_str = if (full_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
7846 return sema.fail(block, func_ret_ty_src, "{s}return type '{}' not allowed", .{
7843 return sema.fail(block, func_ret_ty_src, "{s}return type '{f}' not allowed", .{
78477844 opaque_str, full_ty.fmt(pt),
78487845 });
78497846 }
......@@ -8301,7 +8298,7 @@ fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Typ
83018298 }
83028299 const owner_func_ty: Type = .fromInterned(zcu.funcInfo(sema.owner.unwrap().func).ty);
83038300 if (owner_func_ty.toIntern() != func_ty.toIntern()) {
8304 return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{
8301 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}'", .{
83058302 func_ty.fmt(pt), owner_func_ty.fmt(pt),
83068303 });
83078304 }
......@@ -8325,9 +8322,9 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
83258322 const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node });
83268323 const child_type = try sema.resolveType(block, operand_src, inst_data.operand);
83278324 if (child_type.zigTypeTag(zcu) == .@"opaque") {
8328 return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(pt)});
8325 return sema.fail(block, operand_src, "opaque type '{f}' cannot be optional", .{child_type.fmt(pt)});
83298326 } else if (child_type.zigTypeTag(zcu) == .null) {
8330 return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(pt)});
8327 return sema.fail(block, operand_src, "type '{f}' cannot be optional", .{child_type.fmt(pt)});
83318328 }
83328329 const opt_type = try pt.optionalType(child_type.toIntern());
83338330
......@@ -8388,7 +8385,7 @@ fn zirVecArrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
83888385 const vec_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, un_node.operand) orelse return .generic_poison_type;
83898386 switch (vec_ty.zigTypeTag(zcu)) {
83908387 .array, .vector => {},
8391 else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{}'", .{vec_ty.fmt(pt)}),
8388 else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{f}'", .{vec_ty.fmt(pt)}),
83928389 }
83938390 return Air.internedToRef(vec_ty.childType(zcu).toIntern());
83948391}
......@@ -8456,7 +8453,7 @@ fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src:
84568453 const pt = sema.pt;
84578454 const zcu = pt.zcu;
84588455 if (elem_type.zigTypeTag(zcu) == .@"opaque") {
8459 return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(pt)});
8456 return sema.fail(block, elem_src, "array of opaque type '{f}' not allowed", .{elem_type.fmt(pt)});
84608457 } else if (elem_type.zigTypeTag(zcu) == .noreturn) {
84618458 return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{});
84628459 }
......@@ -8492,7 +8489,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
84928489 const payload = try sema.resolveType(block, rhs_src, extra.rhs);
84938490
84948491 if (error_set.zigTypeTag(zcu) != .error_set) {
8495 return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{
8492 return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{
84968493 error_set.fmt(pt),
84978494 });
84988495 }
......@@ -8505,11 +8502,11 @@ fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, p
85058502 const pt = sema.pt;
85068503 const zcu = pt.zcu;
85078504 if (payload_ty.zigTypeTag(zcu) == .@"opaque") {
8508 return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{
8505 return sema.fail(block, payload_src, "error union with payload of opaque type '{f}' not allowed", .{
85098506 payload_ty.fmt(pt),
85108507 });
85118508 } else if (payload_ty.zigTypeTag(zcu) == .error_set) {
8512 return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{
8509 return sema.fail(block, payload_src, "error union with payload of error set type '{f}' not allowed", .{
85138510 payload_ty.fmt(pt),
85148511 });
85158512 }
......@@ -8647,9 +8644,9 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
86478644 const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs);
86488645 const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs);
86498646 if (lhs_ty.zigTypeTag(zcu) != .error_set)
8650 return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(pt)});
8647 return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)});
86518648 if (rhs_ty.zigTypeTag(zcu) != .error_set)
8652 return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(pt)});
8649 return sema.fail(block, rhs_src, "expected error set type, found '{f}'", .{rhs_ty.fmt(pt)});
86538650
86548651 // Anything merged with anyerror is anyerror.
86558652 if (lhs_ty.toIntern() == .anyerror_type or rhs_ty.toIntern() == .anyerror_type) {
......@@ -8759,7 +8756,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
87598756 return sema.fail(
87608757 block,
87618758 operand_src,
8762 "untagged union '{}' cannot be converted to integer",
8759 "untagged union '{f}' cannot be converted to integer",
87638760 .{operand_ty.fmt(pt)},
87648761 );
87658762 };
......@@ -8767,7 +8764,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
87678764 break :blk try sema.unionToTag(block, tag_ty, operand, operand_src);
87688765 },
87698766 else => {
8770 return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{
8767 return sema.fail(block, operand_src, "expected enum or tagged union, found '{f}'", .{
87718768 operand_ty.fmt(pt),
87728769 });
87738770 },
......@@ -8778,7 +8775,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
87788775 // TODO: use correct solution
87798776 // https://github.com/ziglang/zig/issues/15909
87808777 if (enum_tag_ty.enumFieldCount(zcu) == 0 and !enum_tag_ty.isNonexhaustiveEnum(zcu)) {
8781 return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{}'", .{
8778 return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{f}'", .{
87828779 enum_tag_ty.fmt(pt),
87838780 });
87848781 }
......@@ -8812,7 +8809,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
88128809 const operand_ty = sema.typeOf(operand);
88138810
88148811 if (dest_ty.zigTypeTag(zcu) != .@"enum") {
8815 return sema.fail(block, src, "expected enum, found '{}'", .{dest_ty.fmt(pt)});
8812 return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)});
88168813 }
88178814 _ = try sema.checkIntType(block, operand_src, operand_ty);
88188815
......@@ -8822,7 +8819,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
88228819 if (try sema.intFitsInType(int_val, int_tag_ty, null)) {
88238820 return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern());
88248821 }
8825 return sema.fail(block, src, "int value '{}' out of range of non-exhaustive enum '{}'", .{
8822 return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{
88268823 int_val.fmtValueSema(pt, sema), dest_ty.fmt(pt),
88278824 });
88288825 }
......@@ -8830,7 +8827,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
88308827 return sema.failWithUseOfUndef(block, operand_src);
88318828 }
88328829 if (!(try sema.enumHasInt(dest_ty, int_val))) {
8833 return sema.fail(block, src, "enum '{}' has no tag with value '{}'", .{
8830 return sema.fail(block, src, "enum '{f}' has no tag with value '{f}'", .{
88348831 dest_ty.fmt(pt), int_val.fmtValueSema(pt, sema),
88358832 });
88368833 }
......@@ -9024,7 +9021,7 @@ fn zirErrUnionPayload(
90249021 const operand_src = src;
90259022 const err_union_ty = sema.typeOf(operand);
90269023 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
9027 return sema.fail(block, operand_src, "expected error union type, found '{}'", .{
9024 return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{
90289025 err_union_ty.fmt(pt),
90299026 });
90309027 }
......@@ -9092,7 +9089,7 @@ fn analyzeErrUnionPayloadPtr(
90929089 assert(operand_ty.zigTypeTag(zcu) == .pointer);
90939090
90949091 if (operand_ty.childType(zcu).zigTypeTag(zcu) != .error_union) {
9095 return sema.fail(block, src, "expected error union type, found '{}'", .{
9092 return sema.fail(block, src, "expected error union type, found '{f}'", .{
90969093 operand_ty.childType(zcu).fmt(pt),
90979094 });
90989095 }
......@@ -9169,7 +9166,7 @@ fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air
91699166 const zcu = pt.zcu;
91709167 const operand_ty = sema.typeOf(operand);
91719168 if (operand_ty.zigTypeTag(zcu) != .error_union) {
9172 return sema.fail(block, src, "expected error union type, found '{}'", .{
9169 return sema.fail(block, src, "expected error union type, found '{f}'", .{
91739170 operand_ty.fmt(pt),
91749171 });
91759172 }
......@@ -9205,7 +9202,7 @@ fn analyzeErrUnionCodePtr(sema: *Sema, block: *Block, src: LazySrcLoc, operand:
92059202 assert(operand_ty.zigTypeTag(zcu) == .pointer);
92069203
92079204 if (operand_ty.childType(zcu).zigTypeTag(zcu) != .error_union) {
9208 return sema.fail(block, src, "expected error union type, found '{}'", .{
9205 return sema.fail(block, src, "expected error union type, found '{f}'", .{
92099206 operand_ty.childType(zcu).fmt(pt),
92109207 });
92119208 }
......@@ -9450,19 +9447,17 @@ fn callConvSupportsVarArgs(cc: std.builtin.CallingConvention.Tag) bool {
94509447fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: std.builtin.CallingConvention.Tag) CompileError!void {
94519448 const CallingConventionsSupportingVarArgsList = struct {
94529449 arch: std.Target.Cpu.Arch,
9453 pub fn format(ctx: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
9454 _ = fmt;
9455 _ = options;
9450 pub fn format(ctx: @This(), w: *std.io.Writer) std.io.Writer.Error!void {
94569451 var first = true;
94579452 for (calling_conventions_supporting_var_args) |cc_inner| {
94589453 for (std.Target.Cpu.Arch.fromCallingConvention(cc_inner)) |supported_arch| {
94599454 if (supported_arch == ctx.arch) break;
94609455 } else continue; // callconv not supported by this arch
94619456 if (!first) {
9462 try writer.writeAll(", ");
9457 try w.writeAll(", ");
94639458 }
94649459 first = false;
9465 try writer.print("'{s}'", .{@tagName(cc_inner)});
9460 try w.print("'{s}'", .{@tagName(cc_inner)});
94669461 }
94679462 }
94689463 };
......@@ -9472,7 +9467,7 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc:
94729467 const msg = try sema.errMsg(src, "variadic function does not support '{s}' calling convention", .{@tagName(cc)});
94739468 errdefer msg.destroy(sema.gpa);
94749469 const target = sema.pt.zcu.getTarget();
9475 try sema.errNote(src, msg, "supported calling conventions: {}", .{CallingConventionsSupportingVarArgsList{ .arch = target.cpu.arch }});
9470 try sema.errNote(src, msg, "supported calling conventions: {f}", .{CallingConventionsSupportingVarArgsList{ .arch = target.cpu.arch }});
94769471 break :msg msg;
94779472 });
94789473 }
......@@ -9520,7 +9515,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type)
95209515 }
95219516
95229517 return sema.failWithOwnedErrorMsg(block, msg: {
9523 const msg = try sema.errMsg(src, "value with non-mergable pointer type '{}' depends on runtime control flow", .{peer_ty.fmt(pt)});
9518 const msg = try sema.errMsg(src, "value with non-mergable pointer type '{f}' depends on runtime control flow", .{peer_ty.fmt(pt)});
95249519 errdefer msg.destroy(sema.gpa);
95259520
95269521 const runtime_src = block.runtime_cond orelse block.runtime_loop.?;
......@@ -9598,13 +9593,13 @@ fn funcCommon(
95989593 }
95999594 if (!param_ty.isValidParamType(zcu)) {
96009595 const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
9601 return sema.fail(block, param_src, "parameter of {s}type '{}' not allowed", .{
9596 return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{
96029597 opaque_str, param_ty.fmt(pt),
96039598 });
96049599 }
96059600 if (!param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc) and !try sema.validateExternType(param_ty, .param_ty)) {
96069601 const msg = msg: {
9607 const msg = try sema.errMsg(param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
9602 const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
96089603 param_ty.fmt(pt), @tagName(cc),
96099604 });
96109605 errdefer msg.destroy(sema.gpa);
......@@ -9618,7 +9613,7 @@ fn funcCommon(
96189613 }
96199614 if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) {
96209615 const msg = msg: {
9621 const msg = try sema.errMsg(param_src, "parameter of type '{}' must be declared comptime", .{
9616 const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{
96229617 param_ty.fmt(pt),
96239618 });
96249619 errdefer msg.destroy(sema.gpa);
......@@ -9798,7 +9793,7 @@ fn finishFunc(
97989793
97999794 if (!return_type.isValidReturnType(zcu)) {
98009795 const opaque_str = if (return_type.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
9801 return sema.fail(block, ret_ty_src, "{s}return type '{}' not allowed", .{
9796 return sema.fail(block, ret_ty_src, "{s}return type '{f}' not allowed", .{
98029797 opaque_str, return_type.fmt(pt),
98039798 });
98049799 }
......@@ -9806,7 +9801,7 @@ fn finishFunc(
98069801 !try sema.validateExternType(return_type, .ret_ty))
98079802 {
98089803 const msg = msg: {
9809 const msg = try sema.errMsg(ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{
9804 const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{s}'", .{
98109805 return_type.fmt(pt), @tagName(cc_resolved),
98119806 });
98129807 errdefer msg.destroy(gpa);
......@@ -9828,7 +9823,7 @@ fn finishFunc(
98289823
98299824 const msg = try sema.errMsg(
98309825 ret_ty_src,
9831 "function with comptime-only return type '{}' requires all parameters to be comptime",
9826 "function with comptime-only return type '{f}' requires all parameters to be comptime",
98329827 .{return_type.fmt(pt)},
98339828 );
98349829 errdefer msg.destroy(sema.gpa);
......@@ -9897,17 +9892,15 @@ fn finishFunc(
98979892 .bad_arch => |allowed_archs| {
98989893 const ArchListFormatter = struct {
98999894 archs: []const std.Target.Cpu.Arch,
9900 pub fn format(formatter: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
9901 _ = fmt;
9902 _ = options;
9895 pub fn format(formatter: @This(), w: *std.io.Writer) std.io.Writer.Error!void {
99039896 for (formatter.archs, 0..) |arch, i| {
99049897 if (i != 0)
9905 try writer.writeAll(", ");
9906 try writer.print("'{s}'", .{@tagName(arch)});
9898 try w.writeAll(", ");
9899 try w.print("'{s}'", .{@tagName(arch)});
99079900 }
99089901 }
99099902 };
9910 return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {}", .{
9903 return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {f}", .{
99119904 @tagName(cc_resolved),
99129905 ArchListFormatter{ .archs = allowed_archs },
99139906 });
......@@ -10008,7 +10001,7 @@ fn analyzeAs(
1000810001 const operand = try sema.resolveInst(zir_operand);
1000910002 const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse return operand;
1001010003 switch (dest_ty.zigTypeTag(zcu)) {
10011 .@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{}'", .{dest_ty.fmt(pt)}),
10004 .@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{f}'", .{dest_ty.fmt(pt)}),
1001210005 .noreturn => return sema.fail(block, src, "cannot cast to noreturn", .{}),
1001310006 else => {},
1001410007 }
......@@ -10036,12 +10029,12 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1003610029 const ptr_ty = operand_ty.scalarType(zcu);
1003710030 const is_vector = operand_ty.zigTypeTag(zcu) == .vector;
1003810031 if (!ptr_ty.isPtrAtRuntime(zcu)) {
10039 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(pt)});
10032 return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)});
1004010033 }
1004110034 const pointee_ty = ptr_ty.childType(zcu);
1004210035 if (try ptr_ty.comptimeOnlySema(pt)) {
1004310036 const msg = msg: {
10044 const msg = try sema.errMsg(ptr_src, "comptime-only type '{}' has no pointer address", .{pointee_ty.fmt(pt)});
10037 const msg = try sema.errMsg(ptr_src, "comptime-only type '{f}' has no pointer address", .{pointee_ty.fmt(pt)});
1004510038 errdefer msg.destroy(sema.gpa);
1004610039 try sema.explainWhyTypeIsComptime(msg, ptr_src, pointee_ty);
1004710040 break :msg msg;
......@@ -10289,14 +10282,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1028910282 .type,
1029010283 .undefined,
1029110284 .void,
10292 => return sema.fail(block, src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)}),
10285 => return sema.fail(block, src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}),
1029310286
1029410287 .@"enum" => {
1029510288 const msg = msg: {
10296 const msg = try sema.errMsg(src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)});
10289 const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)});
1029710290 errdefer msg.destroy(sema.gpa);
1029810291 switch (operand_ty.zigTypeTag(zcu)) {
10299 .int, .comptime_int => try sema.errNote(src, msg, "use @enumFromInt to cast from '{}'", .{operand_ty.fmt(pt)}),
10292 .int, .comptime_int => try sema.errNote(src, msg, "use @enumFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}),
1030010293 else => {},
1030110294 }
1030210295
......@@ -10307,11 +10300,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1030710300
1030810301 .pointer => {
1030910302 const msg = msg: {
10310 const msg = try sema.errMsg(src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)});
10303 const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)});
1031110304 errdefer msg.destroy(sema.gpa);
1031210305 switch (operand_ty.zigTypeTag(zcu)) {
10313 .int, .comptime_int => try sema.errNote(src, msg, "use @ptrFromInt to cast from '{}'", .{operand_ty.fmt(pt)}),
10314 .pointer => try sema.errNote(src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(pt)}),
10306 .int, .comptime_int => try sema.errNote(src, msg, "use @ptrFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}),
10307 .pointer => try sema.errNote(src, msg, "use @ptrCast to cast from '{f}'", .{operand_ty.fmt(pt)}),
1031510308 else => {},
1031610309 }
1031710310
......@@ -10325,7 +10318,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1032510318 .@"union" => "union",
1032610319 else => unreachable,
1032710320 };
10328 return sema.fail(block, src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{
10321 return sema.fail(block, src, "cannot @bitCast to '{f}'; {s} does not have a guaranteed in-memory layout", .{
1032910322 dest_ty.fmt(pt), container,
1033010323 });
1033110324 },
......@@ -10353,14 +10346,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1035310346 .type,
1035410347 .undefined,
1035510348 .void,
10356 => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)}),
10349 => return sema.fail(block, operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}),
1035710350
1035810351 .@"enum" => {
1035910352 const msg = msg: {
10360 const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)});
10353 const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)});
1036110354 errdefer msg.destroy(sema.gpa);
1036210355 switch (dest_ty.zigTypeTag(zcu)) {
10363 .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromEnum to cast to '{}'", .{dest_ty.fmt(pt)}),
10356 .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromEnum to cast to '{f}'", .{dest_ty.fmt(pt)}),
1036410357 else => {},
1036510358 }
1036610359
......@@ -10370,11 +10363,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1037010363 },
1037110364 .pointer => {
1037210365 const msg = msg: {
10373 const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)});
10366 const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)});
1037410367 errdefer msg.destroy(sema.gpa);
1037510368 switch (dest_ty.zigTypeTag(zcu)) {
10376 .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromPtr to cast to '{}'", .{dest_ty.fmt(pt)}),
10377 .pointer => try sema.errNote(operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(pt)}),
10369 .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromPtr to cast to '{f}'", .{dest_ty.fmt(pt)}),
10370 .pointer => try sema.errNote(operand_src, msg, "use @ptrCast to cast to '{f}'", .{dest_ty.fmt(pt)}),
1037810371 else => {},
1037910372 }
1038010373
......@@ -10388,7 +10381,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1038810381 .@"union" => "union",
1038910382 else => unreachable,
1039010383 };
10391 return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{
10384 return sema.fail(block, operand_src, "cannot @bitCast from '{f}'; {s} does not have a guaranteed in-memory layout", .{
1039210385 operand_ty.fmt(pt), container,
1039310386 });
1039410387 },
......@@ -10431,7 +10424,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1043110424 else => return sema.fail(
1043210425 block,
1043310426 src,
10434 "expected float or vector type, found '{}'",
10427 "expected float or vector type, found '{f}'",
1043510428 .{dest_ty.fmt(pt)},
1043610429 ),
1043710430 };
......@@ -10441,7 +10434,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1044110434 else => return sema.fail(
1044210435 block,
1044310436 operand_src,
10444 "expected float or vector type, found '{}'",
10437 "expected float or vector type, found '{f}'",
1044510438 .{operand_ty.fmt(pt)},
1044610439 ),
1044710440 }
......@@ -10525,7 +10518,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1052510518 if (indexable_ty.zigTypeTag(zcu) != .pointer) {
1052610519 const capture_src = block.src(.{ .for_capture_from_input = inst_data.src_node });
1052710520 const msg = msg: {
10528 const msg = try sema.errMsg(capture_src, "pointer capture of non pointer type '{}'", .{
10521 const msg = try sema.errMsg(capture_src, "pointer capture of non pointer type '{f}'", .{
1052910522 indexable_ty.fmt(pt),
1053010523 });
1053110524 errdefer msg.destroy(sema.gpa);
......@@ -10667,7 +10660,7 @@ fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1066710660 const lhs_ptr_ty = sema.typeOf(try sema.resolveInst(inst_data.operand));
1066810661 const lhs_ty = switch (lhs_ptr_ty.zigTypeTag(zcu)) {
1066910662 .pointer => lhs_ptr_ty.childType(zcu),
10670 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{lhs_ptr_ty.fmt(pt)}),
10663 else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{lhs_ptr_ty.fmt(pt)}),
1067110664 };
1067210665
1067310666 const sentinel_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) {
......@@ -10682,7 +10675,7 @@ fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1068210675 };
1068310676 },
1068410677 },
10685 else => return sema.fail(block, src, "slice of non-array type '{}'", .{lhs_ty.fmt(pt)}),
10678 else => return sema.fail(block, src, "slice of non-array type '{f}'", .{lhs_ty.fmt(pt)}),
1068610679 };
1068710680
1068810681 return Air.internedToRef(sentinel_ty.toIntern());
......@@ -10877,7 +10870,7 @@ const SwitchProngAnalysis = struct {
1087710870 .base_node_inst = capture_src.base_node_inst,
1087810871 .offset = .{ .switch_tag_capture = capture_src.offset.switch_capture },
1087910872 };
10880 return sema.fail(block, tag_capture_src, "cannot capture tag of non-union type '{}'", .{
10873 return sema.fail(block, tag_capture_src, "cannot capture tag of non-union type '{f}'", .{
1088110874 operand_ty.fmt(pt),
1088210875 });
1088310876 }
......@@ -11309,7 +11302,7 @@ fn switchCond(
1130911302 .@"enum",
1131011303 => {
1131111304 if (operand_ty.isSlice(zcu)) {
11312 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(pt)});
11305 return sema.fail(block, src, "switch on type '{f}'", .{operand_ty.fmt(pt)});
1131311306 }
1131411307 if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| {
1131511308 return Air.internedToRef(opv.toIntern());
......@@ -11344,7 +11337,7 @@ fn switchCond(
1134411337 .vector,
1134511338 .frame,
1134611339 .@"anyframe",
11347 => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(pt)}),
11340 => return sema.fail(block, src, "switch on type '{f}'", .{operand_ty.fmt(pt)}),
1134811341 }
1134911342}
1135011343
......@@ -11445,7 +11438,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
1144511438 operand_ty;
1144611439
1144711440 if (operand_err_set.zigTypeTag(zcu) != .error_union) {
11448 return sema.fail(block, switch_src, "expected error union type, found '{}'", .{
11441 return sema.fail(block, switch_src, "expected error union type, found '{f}'", .{
1144911442 operand_ty.fmt(pt),
1145011443 });
1145111444 }
......@@ -11699,7 +11692,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1169911692 // Even if the operand is comptime-known, this `switch` is runtime.
1170011693 if (try operand_ty.comptimeOnlySema(pt)) {
1170111694 return sema.failWithOwnedErrorMsg(block, msg: {
11702 const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{}'", .{operand_ty.fmt(pt)});
11695 const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)});
1170311696 errdefer msg.destroy(gpa);
1170411697 try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{});
1170511698 break :msg msg;
......@@ -11923,14 +11916,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1192311916 cond_ty,
1192411917 i,
1192511918 msg,
11926 "unhandled enumeration value: '{}'",
11919 "unhandled enumeration value: '{f}'",
1192711920 .{field_name.fmt(&zcu.intern_pool)},
1192811921 );
1192911922 }
1193011923 try sema.errNote(
1193111924 cond_ty.srcLoc(zcu),
1193211925 msg,
11933 "enum '{}' declared here",
11926 "enum '{f}' declared here",
1193411927 .{cond_ty.fmt(pt)},
1193511928 );
1193611929 break :msg msg;
......@@ -12142,7 +12135,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1214212135 return sema.fail(
1214312136 block,
1214412137 src,
12145 "else prong required when switching on type '{}'",
12138 "else prong required when switching on type '{f}'",
1214612139 .{cond_ty.fmt(pt)},
1214712140 );
1214812141 }
......@@ -12218,7 +12211,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1221812211 .@"anyframe",
1221912212 .comptime_float,
1222012213 .float,
12221 => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{
12214 => return sema.fail(block, operand_src, "invalid switch operand type '{f}'", .{
1222212215 raw_operand_ty.fmt(pt),
1222312216 }),
1222412217 }
......@@ -12747,7 +12740,7 @@ fn analyzeSwitchRuntimeBlock(
1274712740 if (special.is_inline) switch (operand_ty.zigTypeTag(zcu)) {
1274812741 .@"enum" => {
1274912742 if (operand_ty.isNonexhaustiveEnum(zcu) and !union_originally) {
12750 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
12743 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{
1275112744 operand_ty.fmt(pt),
1275212745 });
1275312746 }
......@@ -12803,7 +12796,7 @@ fn analyzeSwitchRuntimeBlock(
1280312796 },
1280412797 .error_set => {
1280512798 if (operand_ty.isAnyError(zcu)) {
12806 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
12799 return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{
1280712800 operand_ty.fmt(pt),
1280812801 });
1280912802 }
......@@ -12964,7 +12957,7 @@ fn analyzeSwitchRuntimeBlock(
1296412957 cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items));
1296512958 }
1296612959 },
12967 else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
12960 else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{
1296812961 operand_ty.fmt(pt),
1296912962 }),
1297012963 };
......@@ -13478,7 +13471,7 @@ fn validateErrSetSwitch(
1347813471 try sema.errNote(
1347913472 src,
1348013473 msg,
13481 "unhandled error value: 'error.{}'",
13474 "unhandled error value: 'error.{f}'",
1348213475 .{error_name.fmt(ip)},
1348313476 );
1348413477 }
......@@ -13704,7 +13697,7 @@ fn validateSwitchNoRange(
1370413697 const msg = msg: {
1370513698 const msg = try sema.errMsg(
1370613699 operand_src,
13707 "ranges not allowed when switching on type '{}'",
13700 "ranges not allowed when switching on type '{f}'",
1370813701 .{operand_ty.fmt(sema.pt)},
1370913702 );
1371013703 errdefer msg.destroy(sema.gpa);
......@@ -13862,7 +13855,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1386213855 .array_type => break :hf field_name.eqlSlice("len", ip),
1386313856 else => {},
1386413857 }
13865 return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
13858 return sema.fail(block, ty_src, "type '{f}' does not support '@hasField'", .{
1386613859 ty.fmt(pt),
1386713860 });
1386813861 };
......@@ -14050,7 +14043,7 @@ fn zirShl(
1405014043 while (i < rhs_ty.vectorLen(zcu)) : (i += 1) {
1405114044 const rhs_elem = try rhs_val.elemValue(pt, i);
1405214045 if (rhs_elem.compareHetero(.gte, bit_value, zcu)) {
14053 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
14046 return sema.fail(block, rhs_src, "shift amount '{f}' at index '{d}' is too large for operand type '{f}'", .{
1405414047 rhs_elem.fmtValueSema(pt, sema),
1405514048 i,
1405614049 scalar_ty.fmt(pt),
......@@ -14058,7 +14051,7 @@ fn zirShl(
1405814051 }
1405914052 }
1406014053 } else if (rhs_val.compareHetero(.gte, bit_value, zcu)) {
14061 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
14054 return sema.fail(block, rhs_src, "shift amount '{f}' is too large for operand type '{f}'", .{
1406214055 rhs_val.fmtValueSema(pt, sema),
1406314056 scalar_ty.fmt(pt),
1406414057 });
......@@ -14069,19 +14062,19 @@ fn zirShl(
1406914062 while (i < rhs_ty.vectorLen(zcu)) : (i += 1) {
1407014063 const rhs_elem = try rhs_val.elemValue(pt, i);
1407114064 if (rhs_elem.compareHetero(.lt, try pt.intValue(scalar_rhs_ty, 0), zcu)) {
14072 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
14065 return sema.fail(block, rhs_src, "shift by negative amount '{f}' at index '{d}'", .{
1407314066 rhs_elem.fmtValueSema(pt, sema),
1407414067 i,
1407514068 });
1407614069 }
1407714070 }
1407814071 } else if (rhs_val.compareHetero(.lt, try pt.intValue(rhs_ty, 0), zcu)) {
14079 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
14072 return sema.fail(block, rhs_src, "shift by negative amount '{f}'", .{
1408014073 rhs_val.fmtValueSema(pt, sema),
1408114074 });
1408214075 }
1408314076 } else if (scalar_rhs_ty.isSignedInt(zcu)) {
14084 return sema.fail(block, rhs_src, "shift by signed type '{}'", .{rhs_ty.fmt(pt)});
14077 return sema.fail(block, rhs_src, "shift by signed type '{f}'", .{rhs_ty.fmt(pt)});
1408514078 }
1408614079
1408714080 const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
......@@ -14231,7 +14224,7 @@ fn zirShr(
1423114224 while (i < rhs_ty.vectorLen(zcu)) : (i += 1) {
1423214225 const rhs_elem = try rhs_val.elemValue(pt, i);
1423314226 if (rhs_elem.compareHetero(.gte, bit_value, zcu)) {
14234 return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
14227 return sema.fail(block, rhs_src, "shift amount '{f}' at index '{d}' is too large for operand type '{f}'", .{
1423514228 rhs_elem.fmtValueSema(pt, sema),
1423614229 i,
1423714230 scalar_ty.fmt(pt),
......@@ -14239,7 +14232,7 @@ fn zirShr(
1423914232 }
1424014233 }
1424114234 } else if (rhs_val.compareHetero(.gte, bit_value, zcu)) {
14242 return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
14235 return sema.fail(block, rhs_src, "shift amount '{f}' is too large for operand type '{f}'", .{
1424314236 rhs_val.fmtValueSema(pt, sema),
1424414237 scalar_ty.fmt(pt),
1424514238 });
......@@ -14250,14 +14243,14 @@ fn zirShr(
1425014243 while (i < rhs_ty.vectorLen(zcu)) : (i += 1) {
1425114244 const rhs_elem = try rhs_val.elemValue(pt, i);
1425214245 if (rhs_elem.compareHetero(.lt, try pt.intValue(rhs_ty.childType(zcu), 0), zcu)) {
14253 return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
14246 return sema.fail(block, rhs_src, "shift by negative amount '{f}' at index '{d}'", .{
1425414247 rhs_elem.fmtValueSema(pt, sema),
1425514248 i,
1425614249 });
1425714250 }
1425814251 }
1425914252 } else if (rhs_val.compareHetero(.lt, try pt.intValue(rhs_ty, 0), zcu)) {
14260 return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
14253 return sema.fail(block, rhs_src, "shift by negative amount '{f}'", .{
1426114254 rhs_val.fmtValueSema(pt, sema),
1426214255 });
1426314256 }
......@@ -14386,7 +14379,7 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1438614379 const scalar_tag = scalar_ty.zigTypeTag(zcu);
1438714380
1438814381 if (scalar_tag != .int and scalar_tag != .bool)
14389 return sema.fail(block, operand_src, "bitwise not operation on type '{}'", .{operand_ty.fmt(pt)});
14382 return sema.fail(block, operand_src, "bitwise not operation on type '{f}'", .{operand_ty.fmt(pt)});
1439014383
1439114384 return analyzeBitNot(sema, block, operand, src);
1439214385}
......@@ -14543,11 +14536,11 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1454314536
1454414537 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: {
1454514538 if (lhs_is_tuple) break :lhs_info undefined;
14546 return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(pt)});
14539 return sema.fail(block, lhs_src, "expected indexable; found '{f}'", .{lhs_ty.fmt(pt)});
1454714540 };
1454814541 const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse {
1454914542 assert(!rhs_is_tuple);
14550 return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(pt)});
14543 return sema.fail(block, rhs_src, "expected indexable; found '{f}'", .{rhs_ty.fmt(pt)});
1455114544 };
1455214545
1455314546 const resolved_elem_ty = t: {
......@@ -15000,7 +14993,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1500014993 // Analyze the lhs first, to catch the case that someone tried to do exponentiation
1500114994 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse {
1500214995 const msg = msg: {
15003 const msg = try sema.errMsg(lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(pt)});
14996 const msg = try sema.errMsg(lhs_src, "expected indexable; found '{f}'", .{lhs_ty.fmt(pt)});
1500414997 errdefer msg.destroy(sema.gpa);
1500514998 switch (lhs_ty.zigTypeTag(zcu)) {
1500614999 .int, .float, .comptime_float, .comptime_int, .vector => {
......@@ -15132,7 +15125,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1513215125 .int, .comptime_int, .float, .comptime_float => false,
1513315126 else => true,
1513415127 }) {
15135 return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(pt)});
15128 return sema.fail(block, src, "negation of type '{f}'", .{rhs_ty.fmt(pt)});
1513615129 }
1513715130
1513815131 if (rhs_scalar_ty.isAnyFloat()) {
......@@ -15163,7 +15156,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1516315156
1516415157 switch (rhs_scalar_ty.zigTypeTag(zcu)) {
1516515158 .int, .comptime_int, .float, .comptime_float => {},
15166 else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(pt)}),
15159 else => return sema.fail(block, src, "negation of type '{f}'", .{rhs_ty.fmt(pt)}),
1516715160 }
1516815161
1516915162 const lhs = Air.internedToRef((try sema.splat(rhs_ty, try pt.intValue(rhs_scalar_ty, 0))).toIntern());
......@@ -15237,7 +15230,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1523715230 return sema.fail(
1523815231 block,
1523915232 src,
15240 "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'",
15233 "ambiguous coercion of division operands '{f}' and '{f}'; non-zero remainder '{f}'",
1524115234 .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), rem.fmtValueSema(pt, sema) },
1524215235 );
1524315236 }
......@@ -15289,7 +15282,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1528915282 return sema.fail(
1529015283 block,
1529115284 src,
15292 "division with '{}' and '{}': signed integers must use @divTrunc, @divFloor, or @divExact",
15285 "division with '{f}' and '{f}': signed integers must use @divTrunc, @divFloor, or @divExact",
1529315286 .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt) },
1529415287 );
1529515288 }
......@@ -15951,7 +15944,7 @@ fn zirOverflowArithmetic(
1595115944 const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src);
1595215945
1595315946 if (dest_ty.scalarType(zcu).zigTypeTag(zcu) != .int) {
15954 return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(pt)});
15947 return sema.fail(block, src, "expected vector of integers or integer tag type, found '{f}'", .{dest_ty.fmt(pt)});
1595515948 }
1595615949
1595715950 const maybe_lhs_val = try sema.resolveValue(lhs);
......@@ -16157,14 +16150,14 @@ fn analyzeArithmetic(
1615716150 return sema.failWithInvalidPtrArithmetic(block, src, "pointer-pointer", "subtraction");
1615816151 }
1615916152 if (!lhs_ty.elemType2(zcu).eql(rhs_ty.elemType2(zcu), zcu)) {
16160 return sema.fail(block, src, "incompatible pointer arithmetic operands '{}' and '{}'", .{
16153 return sema.fail(block, src, "incompatible pointer arithmetic operands '{f}' and '{f}'", .{
1616116154 lhs_ty.fmt(pt), rhs_ty.fmt(pt),
1616216155 });
1616316156 }
1616416157
1616516158 const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu);
1616616159 if (elem_size == 0) {
16167 return sema.fail(block, src, "pointer arithmetic requires element type '{}' to have runtime bits", .{
16160 return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{
1616816161 lhs_ty.elemType2(zcu).fmt(pt),
1616916162 });
1617016163 }
......@@ -16215,7 +16208,7 @@ fn analyzeArithmetic(
1621516208 };
1621616209
1621716210 if (!try lhs_ty.elemType2(zcu).hasRuntimeBitsSema(pt)) {
16218 return sema.fail(block, src, "pointer arithmetic requires element type '{}' to have runtime bits", .{
16211 return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{
1621916212 lhs_ty.elemType2(zcu).fmt(pt),
1622016213 });
1622116214 }
......@@ -16619,7 +16612,7 @@ fn zirCmpEq(
1661916612
1662016613 if (lhs_ty_tag == .null or rhs_ty_tag == .null) {
1662116614 const non_null_type = if (lhs_ty_tag == .null) rhs_ty else lhs_ty;
16622 return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(pt)});
16615 return sema.fail(block, src, "comparison of '{f}' with null", .{non_null_type.fmt(pt)});
1662316616 }
1662416617
1662516618 if (lhs_ty_tag == .@"union" and (rhs_ty_tag == .enum_literal or rhs_ty_tag == .@"enum")) {
......@@ -16676,7 +16669,7 @@ fn analyzeCmpUnionTag(
1667616669 const msg = msg: {
1667716670 const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
1667816671 errdefer msg.destroy(sema.gpa);
16679 try sema.errNote(union_ty.srcLoc(zcu), msg, "union '{}' is not a tagged union", .{union_ty.fmt(pt)});
16672 try sema.errNote(union_ty.srcLoc(zcu), msg, "union '{f}' is not a tagged union", .{union_ty.fmt(pt)});
1668016673 break :msg msg;
1668116674 };
1668216675 return sema.failWithOwnedErrorMsg(block, msg);
......@@ -16762,7 +16755,7 @@ fn analyzeCmp(
1676216755 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
1676316756 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
1676416757 if (!resolved_type.isSelfComparable(zcu, is_equality_cmp)) {
16765 return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{
16758 return sema.fail(block, src, "operator {s} not allowed for type '{f}'", .{
1676616759 compareOperatorName(op), resolved_type.fmt(pt),
1676716760 });
1676816761 }
......@@ -16871,7 +16864,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1687116864 .undefined,
1687216865 .null,
1687316866 .@"opaque",
16874 => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(pt)}),
16867 => return sema.fail(block, operand_src, "no size available for type '{f}'", .{ty.fmt(pt)}),
1687516868
1687616869 .type,
1687716870 .enum_literal,
......@@ -16912,7 +16905,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1691216905 .undefined,
1691316906 .null,
1691416907 .@"opaque",
16915 => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(pt)}),
16908 => return sema.fail(block, operand_src, "no size available for type '{f}'", .{operand_ty.fmt(pt)}),
1691616909
1691716910 .type,
1691816911 .enum_literal,
......@@ -17002,7 +16995,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1700216995 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
1700316996 const tree = file.getTree(zcu) catch |err| {
1700416997 // In this case we emit a warning + a less precise source location.
17005 log.warn("unable to load {}: {s}", .{
16998 log.warn("unable to load {f}: {s}", .{
1700616999 file.path.fmt(zcu.comp), @errorName(err),
1700717000 });
1700817001 break :name null;
......@@ -17030,7 +17023,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1703017023 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
1703117024 const tree = file.getTree(zcu) catch |err| {
1703217025 // In this case we emit a warning + a less precise source location.
17033 log.warn("unable to load {}: {s}", .{
17026 log.warn("unable to load {f}: {s}", .{
1703417027 file.path.fmt(zcu.comp), @errorName(err),
1703517028 });
1703617029 break :name null;
......@@ -18212,7 +18205,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
1821218205 return sema.fail(
1821318206 block,
1821418207 src,
18215 "bit shifting operation expected integer type, found '{}'",
18208 "bit shifting operation expected integer type, found '{f}'",
1821618209 .{operand.fmt(pt)},
1821718210 );
1821818211}
......@@ -18271,7 +18264,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1827118264 const uncasted_ty = sema.typeOf(uncasted_operand);
1827218265 if (uncasted_ty.isVector(zcu)) {
1827318266 if (uncasted_ty.scalarType(zcu).zigTypeTag(zcu) != .bool) {
18274 return sema.fail(block, operand_src, "boolean not operation on type '{}'", .{
18267 return sema.fail(block, operand_src, "boolean not operation on type '{f}'", .{
1827518268 uncasted_ty.fmt(pt),
1827618269 });
1827718270 }
......@@ -18451,7 +18444,7 @@ fn checkSentinelType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !voi
1845118444 const pt = sema.pt;
1845218445 const zcu = pt.zcu;
1845318446 if (!ty.isSelfComparable(zcu, true)) {
18454 return sema.fail(block, src, "non-scalar sentinel type '{}'", .{ty.fmt(pt)});
18447 return sema.fail(block, src, "non-scalar sentinel type '{f}'", .{ty.fmt(pt)});
1845518448 }
1845618449}
1845718450
......@@ -18501,7 +18494,7 @@ fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
1850118494 const zcu = pt.zcu;
1850218495 switch (ty.zigTypeTag(zcu)) {
1850318496 .error_set, .error_union, .undefined => return,
18504 else => return sema.fail(block, src, "expected error union type, found '{}'", .{
18497 else => return sema.fail(block, src, "expected error union type, found '{f}'", .{
1850518498 ty.fmt(pt),
1850618499 }),
1850718500 }
......@@ -18645,7 +18638,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
1864518638 const pt = sema.pt;
1864618639 const zcu = pt.zcu;
1864718640 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
18648 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
18641 return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{
1864918642 err_union_ty.fmt(pt),
1865018643 });
1865118644 }
......@@ -18705,7 +18698,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
1870518698 const pt = sema.pt;
1870618699 const zcu = pt.zcu;
1870718700 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
18708 return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
18701 return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{
1870918702 err_union_ty.fmt(pt),
1871018703 });
1871118704 }
......@@ -18903,7 +18896,7 @@ fn zirRetImplicit(
1890318896 const base_tag = sema.fn_ret_ty.baseZigTypeTag(zcu);
1890418897 if (base_tag == .noreturn) {
1890518898 const msg = msg: {
18906 const msg = try sema.errMsg(ret_ty_src, "function declared '{}' implicitly returns", .{
18899 const msg = try sema.errMsg(ret_ty_src, "function declared '{f}' implicitly returns", .{
1890718900 sema.fn_ret_ty.fmt(pt),
1890818901 });
1890918902 errdefer msg.destroy(sema.gpa);
......@@ -18913,7 +18906,7 @@ fn zirRetImplicit(
1891318906 return sema.failWithOwnedErrorMsg(block, msg);
1891418907 } else if (base_tag != .void) {
1891518908 const msg = msg: {
18916 const msg = try sema.errMsg(ret_ty_src, "function with non-void return type '{}' implicitly returns", .{
18909 const msg = try sema.errMsg(ret_ty_src, "function with non-void return type '{f}' implicitly returns", .{
1891718910 sema.fn_ret_ty.fmt(pt),
1891818911 });
1891918912 errdefer msg.destroy(sema.gpa);
......@@ -19302,13 +19295,13 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1930219295
1930319296 if (host_size != 0) {
1930419297 if (bit_offset >= host_size * 8) {
19305 return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} starts {} bits after the end of a {} byte host integer", .{
19298 return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} starts {d} bits after the end of a {d} byte host integer", .{
1930619299 elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size,
1930719300 });
1930819301 }
1930919302 const elem_bit_size = try elem_ty.bitSizeSema(pt);
1931019303 if (elem_bit_size > host_size * 8 - bit_offset) {
19311 return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} ends {} bits after the end of a {} byte host integer", .{
19304 return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{
1931219305 elem_ty.fmt(pt), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size,
1931319306 });
1931419307 }
......@@ -19323,7 +19316,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1932319316 } else if (inst_data.size == .c) {
1932419317 if (!try sema.validateExternType(elem_ty, .other)) {
1932519318 const msg = msg: {
19326 const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(pt)});
19319 const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
1932719320 errdefer msg.destroy(sema.gpa);
1932819321
1932919322 try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
......@@ -19340,7 +19333,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1934019333
1934119334 if (host_size != 0 and !try sema.validatePackedType(elem_ty)) {
1934219335 return sema.failWithOwnedErrorMsg(block, msg: {
19343 const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{}'", .{elem_ty.fmt(pt)});
19336 const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)});
1934419337 errdefer msg.destroy(sema.gpa);
1934519338 try sema.explainWhyTypeIsNotPacked(msg, elem_ty_src, elem_ty);
1934619339 break :msg msg;
......@@ -19509,7 +19502,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1950919502 const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
1951019503 const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
1951119504 if (union_ty.zigTypeTag(pt.zcu) != .@"union") {
19512 return sema.fail(block, ty_src, "expected union type, found '{}'", .{union_ty.fmt(pt)});
19505 return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)});
1951319506 }
1951419507 const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_name });
1951519508 const init = try sema.resolveInst(extra.init);
......@@ -19672,7 +19665,7 @@ fn zirStructInit(
1967219665 const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{});
1967319666 errdefer msg.destroy(sema.gpa);
1967419667
19675 try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{}' declared here", .{
19668 try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{f}' declared here", .{
1967619669 field_name.fmt(ip),
1967719670 });
1967819671 try sema.addDeclaredHereNote(msg, resolved_ty);
......@@ -19791,7 +19784,7 @@ fn finishStructInit(
1979119784 const field_init = struct_type.fieldInit(ip, i);
1979219785 if (field_init == .none) {
1979319786 const field_name = struct_type.field_names.get(ip)[i];
19794 const template = "missing struct field: {}";
19787 const template = "missing struct field: {f}";
1979519788 const args = .{field_name.fmt(ip)};
1979619789 if (root_msg) |msg| {
1979719790 try sema.errNote(init_src, msg, template, args);
......@@ -20406,7 +20399,7 @@ fn fieldType(
2040620399 },
2040720400 else => {},
2040820401 }
20409 return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{
20402 return sema.fail(block, ty_src, "expected struct or union; found '{f}'", .{
2041020403 cur_ty.fmt(pt),
2041120404 });
2041220405 }
......@@ -20453,7 +20446,7 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2045320446 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
2045420447 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
2045520448 if (ty.isNoReturn(zcu)) {
20456 return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.pt)});
20449 return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});
2045720450 }
2045820451 const val = try ty.lazyAbiAlignment(sema.pt);
2045920452 return Air.internedToRef(val.toIntern());
......@@ -20469,7 +20462,7 @@ fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
2046920462 const is_vector = operand_ty.zigTypeTag(zcu) == .vector;
2047020463 const operand_scalar_ty = operand_ty.scalarType(zcu);
2047120464 if (operand_scalar_ty.toIntern() != .bool_type) {
20472 return sema.fail(block, src, "expected 'bool', found '{}'", .{operand_scalar_ty.zigTypeTag(zcu)});
20465 return sema.fail(block, src, "expected 'bool', found '{t}'", .{operand_scalar_ty.zigTypeTag(zcu)});
2047320466 }
2047420467 const len = if (is_vector) operand_ty.vectorLen(zcu) else undefined;
2047520468 const dest_ty: Type = if (is_vector) try pt.vectorType(.{ .child = .u1_type, .len = len }) else .u1;
......@@ -20531,7 +20524,7 @@ fn zirAbs(
2053120524 else => return sema.fail(
2053220525 block,
2053320526 operand_src,
20534 "expected integer, float, or vector of either integers or floats, found '{}'",
20527 "expected integer, float, or vector of either integers or floats, found '{f}'",
2053520528 .{operand_ty.fmt(pt)},
2053620529 ),
2053720530 };
......@@ -20600,7 +20593,7 @@ fn zirUnaryMath(
2060020593 else => return sema.fail(
2060120594 block,
2060220595 operand_src,
20603 "expected vector of floats or float type, found '{}'",
20596 "expected vector of floats or float type, found '{f}'",
2060420597 .{operand_ty.fmt(pt)},
2060520598 ),
2060620599 }
......@@ -20629,8 +20622,8 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2062920622 },
2063020623 .@"enum" => operand_ty,
2063120624 .@"union" => operand_ty.unionTagType(zcu) orelse
20632 return sema.fail(block, src, "union '{}' is untagged", .{operand_ty.fmt(pt)}),
20633 else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{
20625 return sema.fail(block, src, "union '{f}' is untagged", .{operand_ty.fmt(pt)}),
20626 else => return sema.fail(block, operand_src, "expected enum or union; found '{f}'", .{
2063420627 operand_ty.fmt(pt),
2063520628 }),
2063620629 };
......@@ -20638,7 +20631,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2063820631 // TODO I don't think this is the correct way to handle this but
2063920632 // it prevents a crash.
2064020633 // https://github.com/ziglang/zig/issues/15909
20641 return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{
20634 return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{f}'", .{
2064220635 enum_ty.fmt(pt),
2064320636 });
2064420637 }
......@@ -20646,7 +20639,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2064620639 if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {
2064720640 const field_index = enum_ty.enumTagFieldIndex(val, zcu) orelse {
2064820641 const msg = msg: {
20649 const msg = try sema.errMsg(src, "no field with value '{}' in enum '{}'", .{
20642 const msg = try sema.errMsg(src, "no field with value '{f}' in enum '{f}'", .{
2065020643 val.fmtValueSema(pt, sema), enum_ty.fmt(pt),
2065120644 });
2065220645 errdefer msg.destroy(sema.gpa);
......@@ -20752,7 +20745,7 @@ fn zirReify(
2075220745 64 => .f64,
2075320746 80 => .f80,
2075420747 128 => .f128,
20755 else => return sema.fail(block, src, "{}-bit float unsupported", .{float.bits}),
20748 else => return sema.fail(block, src, "{d}-bit float unsupported", .{float.bits}),
2075620749 };
2075720750 return Air.internedToRef(ty.toIntern());
2075820751 },
......@@ -20833,7 +20826,7 @@ fn zirReify(
2083320826 } else if (ptr_size == .c) {
2083420827 if (!try sema.validateExternType(elem_ty, .other)) {
2083520828 const msg = msg: {
20836 const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(pt)});
20829 const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
2083720830 errdefer msg.destroy(gpa);
2083820831
2083920832 try sema.explainWhyTypeIsNotExtern(msg, src, elem_ty, .other);
......@@ -20946,7 +20939,7 @@ fn zirReify(
2094620939 _ = try pt.getErrorValue(name);
2094720940 const gop = names.getOrPutAssumeCapacity(name);
2094820941 if (gop.found_existing) {
20949 return sema.fail(block, src, "duplicate error '{}'", .{
20942 return sema.fail(block, src, "duplicate error '{f}'", .{
2095020943 name.fmt(ip),
2095120944 });
2095220945 }
......@@ -21294,7 +21287,7 @@ fn reifyEnum(
2129421287
2129521288 if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {
2129621289 // TODO: better source location
21297 return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
21290 return sema.fail(block, src, "field '{f}' with enumeration value '{f}' is too large for backing int type '{f}'", .{
2129821291 field_name.fmt(ip),
2129921292 field_value_val.fmtValueSema(pt, sema),
2130021293 tag_ty.fmt(pt),
......@@ -21305,14 +21298,14 @@ fn reifyEnum(
2130521298 if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| {
2130621299 return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
2130721300 .name => msg: {
21308 const msg = try sema.errMsg(src, "duplicate enum field '{}'", .{field_name.fmt(ip)});
21301 const msg = try sema.errMsg(src, "duplicate enum field '{f}'", .{field_name.fmt(ip)});
2130921302 errdefer msg.destroy(gpa);
2131021303 _ = conflict.prev_field_idx; // TODO: this note is incorrect
2131121304 try sema.errNote(src, msg, "other field here", .{});
2131221305 break :msg msg;
2131321306 },
2131421307 .value => msg: {
21315 const msg = try sema.errMsg(src, "enum tag value {} already taken", .{field_value_val.fmtValueSema(pt, sema)});
21308 const msg = try sema.errMsg(src, "enum tag value {f} already taken", .{field_value_val.fmtValueSema(pt, sema)});
2131621309 errdefer msg.destroy(gpa);
2131721310 _ = conflict.prev_field_idx; // TODO: this note is incorrect
2131821311 try sema.errNote(src, msg, "other enum tag value here", .{});
......@@ -21460,13 +21453,13 @@ fn reifyUnion(
2146021453
2146121454 const enum_index = enum_tag_ty.enumFieldIndex(field_name, zcu) orelse {
2146221455 // TODO: better source location
21463 return sema.fail(block, src, "no field named '{}' in enum '{}'", .{
21456 return sema.fail(block, src, "no field named '{f}' in enum '{f}'", .{
2146421457 field_name.fmt(ip), enum_tag_ty.fmt(pt),
2146521458 });
2146621459 };
2146721460 if (seen_tags.isSet(enum_index)) {
2146821461 // TODO: better source location
21469 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
21462 return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});
2147021463 }
2147121464 seen_tags.set(enum_index);
2147221465
......@@ -21487,7 +21480,7 @@ fn reifyUnion(
2148721480 var it = seen_tags.iterator(.{ .kind = .unset });
2148821481 while (it.next()) |enum_index| {
2148921482 const field_name = enum_tag_ty.enumFieldName(enum_index, zcu);
21490 try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{}' missing, declared here", .{
21483 try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{f}' missing, declared here", .{
2149121484 field_name.fmt(ip),
2149221485 });
2149321486 }
......@@ -21512,7 +21505,7 @@ fn reifyUnion(
2151221505 const gop = field_names.getOrPutAssumeCapacity(field_name);
2151321506 if (gop.found_existing) {
2151421507 // TODO: better source location
21515 return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
21508 return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});
2151621509 }
2151721510
2151821511 field_ty.* = field_type_val.toIntern();
......@@ -21544,7 +21537,7 @@ fn reifyUnion(
2154421537 }
2154521538 if (layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) {
2154621539 return sema.failWithOwnedErrorMsg(block, msg: {
21547 const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)});
21540 const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
2154821541 errdefer msg.destroy(gpa);
2154921542
2155021543 try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .union_field);
......@@ -21554,7 +21547,7 @@ fn reifyUnion(
2155421547 });
2155521548 } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) {
2155621549 return sema.failWithOwnedErrorMsg(block, msg: {
21557 const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)});
21550 const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
2155821551 errdefer msg.destroy(gpa);
2155921552
2156021553 try sema.explainWhyTypeIsNotPacked(msg, src, field_ty);
......@@ -21636,14 +21629,14 @@ fn reifyTuple(
2163621629 const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(
2163721630 block,
2163821631 src,
21639 "tuple cannot have non-numeric field '{}'",
21632 "tuple cannot have non-numeric field '{f}'",
2164021633 .{field_name.fmt(ip)},
2164121634 );
2164221635 if (field_name_index != field_idx) {
2164321636 return sema.fail(
2164421637 block,
2164521638 src,
21646 "tuple field name '{}' does not match field index {}",
21639 "tuple field name '{d}' does not match field index {d}",
2164721640 .{ field_name_index, field_idx },
2164821641 );
2164921642 }
......@@ -21814,7 +21807,7 @@ fn reifyStruct(
2181421807 const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
2181521808 if (struct_type.addFieldName(ip, field_name)) |prev_index| {
2181621809 _ = prev_index; // TODO: better source location
21817 return sema.fail(block, src, "duplicate struct field name {}", .{field_name.fmt(ip)});
21810 return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
2181821811 }
2181921812
2182021813 if (any_aligned_fields) {
......@@ -21883,7 +21876,7 @@ fn reifyStruct(
2188321876 }
2188421877 if (layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) {
2188521878 return sema.failWithOwnedErrorMsg(block, msg: {
21886 const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)});
21879 const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
2188721880 errdefer msg.destroy(gpa);
2188821881
2188921882 try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .struct_field);
......@@ -21893,7 +21886,7 @@ fn reifyStruct(
2189321886 });
2189421887 } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) {
2189521888 return sema.failWithOwnedErrorMsg(block, msg: {
21896 const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)});
21889 const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
2189721890 errdefer msg.destroy(gpa);
2189821891
2189921892 try sema.explainWhyTypeIsNotPacked(msg, src, field_ty);
......@@ -21970,7 +21963,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
2197021963
2197121964 if (!try sema.validateExternType(arg_ty, .param_ty)) {
2197221965 const msg = msg: {
21973 const msg = try sema.errMsg(ty_src, "cannot get '{}' from variadic argument", .{arg_ty.fmt(sema.pt)});
21966 const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)});
2197421967 errdefer msg.destroy(sema.gpa);
2197521968
2197621969 try sema.explainWhyTypeIsNotExtern(msg, ty_src, arg_ty, .param_ty);
......@@ -22029,7 +22022,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2202922022 const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);
2203022023 const ty = try sema.resolveType(block, ty_src, inst_data.operand);
2203122024
22032 const type_name = try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{}", .{ty.fmt(pt)}, .no_embedded_nulls);
22025 const type_name = try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{f}", .{ty.fmt(pt)}, .no_embedded_nulls);
2203322026 return sema.addNullTerminatedStrLit(type_name);
2203422027}
2203522028
......@@ -22157,7 +22150,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2215722150
2215822151 if (ptr_ty.isSlice(zcu)) {
2215922152 const msg = msg: {
22160 const msg = try sema.errMsg(src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(pt)});
22153 const msg = try sema.errMsg(src, "integer cannot be converted to slice type '{f}'", .{ptr_ty.fmt(pt)});
2216122154 errdefer msg.destroy(sema.gpa);
2216222155 try sema.errNote(src, msg, "slice length cannot be inferred from address", .{});
2216322156 break :msg msg;
......@@ -22184,7 +22177,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2218422177 }
2218522178 if (try ptr_ty.comptimeOnlySema(pt)) {
2218622179 return sema.failWithOwnedErrorMsg(block, msg: {
22187 const msg = try sema.errMsg(src, "pointer to comptime-only type '{}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(pt)});
22180 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)});
2218822181 errdefer msg.destroy(sema.gpa);
2218922182
2219022183 try sema.explainWhyTypeIsComptime(msg, src, ptr_ty);
......@@ -22241,7 +22234,7 @@ fn ptrFromIntVal(
2224122234 }
2224222235 const addr = try operand_val.toUnsignedIntSema(pt);
2224322236 if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0)
22244 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(pt)});
22237 return sema.fail(block, operand_src, "pointer type '{f}' does not allow address zero", .{ptr_ty.fmt(pt)});
2224522238 if (addr != 0 and ptr_align != .none) {
2224622239 const masked_addr = if (ptr_ty.childType(zcu).fnPtrMaskOrNull(zcu)) |mask|
2224722240 addr & mask
......@@ -22249,7 +22242,7 @@ fn ptrFromIntVal(
2224922242 addr;
2225022243
2225122244 if (!ptr_align.check(masked_addr)) {
22252 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(pt)});
22245 return sema.fail(block, operand_src, "pointer type '{f}' requires aligned address", .{ptr_ty.fmt(pt)});
2225322246 }
2225422247 }
2225522248
......@@ -22294,8 +22287,8 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
2229422287 errdefer msg.destroy(sema.gpa);
2229522288 const dest_payload_ty = dest_ty.errorUnionPayload(zcu);
2229622289 const operand_payload_ty = operand_ty.errorUnionPayload(zcu);
22297 try sema.errNote(src, msg, "destination payload is '{}'", .{dest_payload_ty.fmt(pt)});
22298 try sema.errNote(src, msg, "operand payload is '{}'", .{operand_payload_ty.fmt(pt)});
22290 try sema.errNote(src, msg, "destination payload is '{f}'", .{dest_payload_ty.fmt(pt)});
22291 try sema.errNote(src, msg, "operand payload is '{f}'", .{operand_payload_ty.fmt(pt)});
2229922292 try addDeclaredHereNote(sema, msg, dest_ty);
2230022293 try addDeclaredHereNote(sema, msg, operand_ty);
2230122294 break :msg msg;
......@@ -22340,7 +22333,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
2234022333 break :disjoint true;
2234122334 };
2234222335 if (disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) {
22343 return sema.fail(block, src, "error sets '{}' and '{}' have no common errors", .{
22336 return sema.fail(block, src, "error sets '{f}' and '{f}' have no common errors", .{
2234422337 operand_err_ty.fmt(pt), dest_err_ty.fmt(pt),
2234522338 });
2234622339 }
......@@ -22360,7 +22353,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
2236022353 };
2236122354
2236222355 if (!dest_err_ty.isAnyError(zcu) and !Type.errorSetHasFieldIp(ip, dest_err_ty.toIntern(), err_name)) {
22363 return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{
22356 return sema.fail(block, src, "'error.{f}' not a member of error set '{f}'", .{
2236422357 err_name.fmt(ip), dest_err_ty.fmt(pt),
2236522358 });
2236622359 }
......@@ -22520,13 +22513,15 @@ fn ptrCastFull(
2252022513 const src_elem_size = src_elem_ty.abiSize(zcu);
2252122514 const dest_elem_size = dest_elem_ty.abiSize(zcu);
2252222515 if (dest_elem_size == 0) {
22523 return sema.fail(block, src, "cannot infer length of slice of zero-bit '{}' from '{}'", .{ dest_elem_ty.fmt(pt), operand_ty.fmt(pt) });
22516 return sema.fail(block, src, "cannot infer length of slice of zero-bit '{f}' from '{f}'", .{
22517 dest_elem_ty.fmt(pt), operand_ty.fmt(pt),
22518 });
2252422519 }
2252522520 if (opt_src_len) |src_len| {
2252622521 const bytes = src_len * src_elem_size;
2252722522 const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) {
2252822523 .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}),
22529 .one => return sema.fail(block, src, "type '{}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}),
22524 .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}),
2253022525 else => unreachable,
2253122526 };
2253222527 break :len .{ .constant = dest_len };
......@@ -22544,7 +22539,9 @@ fn ptrCastFull(
2254422539 // The source value has `src_len * src_base_per_elem` values of type `src_base_ty`.
2254522540 // The result value will have `dest_len * dest_base_per_elem` values of type `dest_base_ty`.
2254622541 if (dest_base_ty.toIntern() != src_base_ty.toIntern()) {
22547 return sema.fail(block, src, "cannot infer length of comptime-only '{}' from incompatible '{}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) });
22542 return sema.fail(block, src, "cannot infer length of comptime-only '{f}' from incompatible '{f}'", .{
22543 dest_ty.fmt(pt), operand_ty.fmt(pt),
22544 });
2254822545 }
2254922546 // `src_base_ty` is comptime-only, so `src_elem_ty` is comptime-only, so `operand_ty` is
2255022547 // comptime-only, so `operand` is comptime-known, so `opt_src_len` is non-`null`.
......@@ -22552,7 +22549,7 @@ fn ptrCastFull(
2255222549 const base_len = src_len * src_base_per_elem;
2255322550 const dest_len = std.math.divExact(u64, base_len, dest_base_per_elem) catch switch (src_info.flags.size) {
2255422551 .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}),
22555 .one => return sema.fail(block, src, "type '{}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}),
22552 .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}),
2255622553 else => unreachable,
2255722554 };
2255822555 break :len .{ .constant = dest_len };
......@@ -22613,7 +22610,7 @@ fn ptrCastFull(
2261322610 );
2261422611 if (imc_res == .ok) break :check_child;
2261522612 return sema.failWithOwnedErrorMsg(block, msg: {
22616 const msg = try sema.errMsg(src, "pointer element type '{}' cannot coerce into element type '{}'", .{
22613 const msg = try sema.errMsg(src, "pointer element type '{f}' cannot coerce into element type '{f}'", .{
2261722614 src_child.fmt(pt), dest_child.fmt(pt),
2261822615 });
2261922616 errdefer msg.destroy(sema.gpa);
......@@ -22640,11 +22637,11 @@ fn ptrCastFull(
2264022637 }
2264122638 return sema.failWithOwnedErrorMsg(block, msg: {
2264222639 const msg = if (src_info.sentinel == .none) blk: {
22643 break :blk try sema.errMsg(src, "destination pointer requires '{}' sentinel", .{
22640 break :blk try sema.errMsg(src, "destination pointer requires '{f}' sentinel", .{
2264422641 Value.fromInterned(dest_info.sentinel).fmtValueSema(pt, sema),
2264522642 });
2264622643 } else blk: {
22647 break :blk try sema.errMsg(src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{
22644 break :blk try sema.errMsg(src, "pointer sentinel '{f}' cannot coerce into pointer sentinel '{f}'", .{
2264822645 Value.fromInterned(src_info.sentinel).fmtValueSema(pt, sema),
2264922646 Value.fromInterned(dest_info.sentinel).fmtValueSema(pt, sema),
2265022647 });
......@@ -22657,7 +22654,7 @@ fn ptrCastFull(
2265722654
2265822655 if (src_info.packed_offset.host_size != dest_info.packed_offset.host_size) {
2265922656 return sema.failWithOwnedErrorMsg(block, msg: {
22660 const msg = try sema.errMsg(src, "pointer host size '{}' cannot coerce into pointer host size '{}'", .{
22657 const msg = try sema.errMsg(src, "pointer host size '{d}' cannot coerce into pointer host size '{d}'", .{
2266122658 src_info.packed_offset.host_size,
2266222659 dest_info.packed_offset.host_size,
2266322660 });
......@@ -22669,7 +22666,7 @@ fn ptrCastFull(
2266922666
2267022667 if (src_info.packed_offset.bit_offset != dest_info.packed_offset.bit_offset) {
2267122668 return sema.failWithOwnedErrorMsg(block, msg: {
22672 const msg = try sema.errMsg(src, "pointer bit offset '{}' cannot coerce into pointer bit offset '{}'", .{
22669 const msg = try sema.errMsg(src, "pointer bit offset '{d}' cannot coerce into pointer bit offset '{d}'", .{
2267322670 src_info.packed_offset.bit_offset,
2267422671 dest_info.packed_offset.bit_offset,
2267522672 });
......@@ -22686,7 +22683,7 @@ fn ptrCastFull(
2268622683 if (dest_allows_zero) break :check_allowzero;
2268722684
2268822685 return sema.failWithOwnedErrorMsg(block, msg: {
22689 const msg = try sema.errMsg(src, "'{}' could have null values which are illegal in type '{}'", .{
22686 const msg = try sema.errMsg(src, "'{f}' could have null values which are illegal in type '{f}'", .{
2269022687 operand_ty.fmt(pt),
2269122688 dest_ty.fmt(pt),
2269222689 });
......@@ -22714,10 +22711,10 @@ fn ptrCastFull(
2271422711 return sema.failWithOwnedErrorMsg(block, msg: {
2271522712 const msg = try sema.errMsg(src, "{s} increases pointer alignment", .{operation});
2271622713 errdefer msg.destroy(sema.gpa);
22717 try sema.errNote(operand_src, msg, "'{}' has alignment '{d}'", .{
22714 try sema.errNote(operand_src, msg, "'{f}' has alignment '{d}'", .{
2271822715 operand_ty.fmt(pt), src_align.toByteUnits() orelse 0,
2271922716 });
22720 try sema.errNote(src, msg, "'{}' has alignment '{d}'", .{
22717 try sema.errNote(src, msg, "'{f}' has alignment '{d}'", .{
2272122718 dest_ty.fmt(pt), dest_align.toByteUnits() orelse 0,
2272222719 });
2272322720 try sema.errNote(src, msg, "use @alignCast to assert pointer alignment", .{});
......@@ -22731,10 +22728,10 @@ fn ptrCastFull(
2273122728 return sema.failWithOwnedErrorMsg(block, msg: {
2273222729 const msg = try sema.errMsg(src, "{s} changes pointer address space", .{operation});
2273322730 errdefer msg.destroy(sema.gpa);
22734 try sema.errNote(operand_src, msg, "'{}' has address space '{s}'", .{
22731 try sema.errNote(operand_src, msg, "'{f}' has address space '{s}'", .{
2273522732 operand_ty.fmt(pt), @tagName(src_info.flags.address_space),
2273622733 });
22737 try sema.errNote(src, msg, "'{}' has address space '{s}'", .{
22734 try sema.errNote(src, msg, "'{f}' has address space '{s}'", .{
2273822735 dest_ty.fmt(pt), @tagName(dest_info.flags.address_space),
2273922736 });
2274022737 try sema.errNote(src, msg, "use @addrSpaceCast to cast pointer address space", .{});
......@@ -22801,7 +22798,7 @@ fn ptrCastFull(
2280122798
2280222799 if (operand_val.isNull(zcu)) {
2280322800 if (!dest_ty.ptrAllowsZero(zcu)) {
22804 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(pt)});
22801 return sema.fail(block, operand_src, "null pointer casted to type '{f}'", .{dest_ty.fmt(pt)});
2280522802 }
2280622803 if (dest_ty.zigTypeTag(zcu) == .optional) {
2280722804 return Air.internedToRef((try pt.nullValue(dest_ty)).toIntern());
......@@ -23092,7 +23089,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2309223089 const operand_is_vector = operand_ty.zigTypeTag(zcu) == .vector;
2309323090 const dest_is_vector = dest_ty.zigTypeTag(zcu) == .vector;
2309423091 if (operand_is_vector != dest_is_vector) {
23095 return sema.fail(block, operand_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) });
23092 return sema.fail(block, operand_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) });
2309623093 }
2309723094
2309823095 if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_int) {
......@@ -23112,7 +23109,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2311223109 }
2311323110
2311423111 if (operand_info.signedness != dest_info.signedness) {
23115 return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{
23112 return sema.fail(block, operand_src, "expected {s} integer type, found '{f}'", .{
2311623113 @tagName(dest_info.signedness), operand_ty.fmt(pt),
2311723114 });
2311823115 }
......@@ -23121,7 +23118,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2312123118 const msg = msg: {
2312223119 const msg = try sema.errMsg(
2312323120 src,
23124 "destination type '{}' has more bits than source type '{}'",
23121 "destination type '{f}' has more bits than source type '{f}'",
2312523122 .{ dest_ty.fmt(pt), operand_ty.fmt(pt) },
2312623123 );
2312723124 errdefer msg.destroy(sema.gpa);
......@@ -23239,7 +23236,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2323923236 return sema.fail(
2324023237 block,
2324123238 operand_src,
23242 "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits",
23239 "@byteSwap requires the number of bits to be evenly divisible by 8, but {f} has {d} bits",
2324323240 .{ scalar_ty.fmt(pt), bits },
2324423241 );
2324523242 }
......@@ -23359,7 +23356,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
2335923356 try ty.resolveLayout(pt);
2336023357 switch (ty.zigTypeTag(zcu)) {
2336123358 .@"struct" => {},
23362 else => return sema.fail(block, ty_src, "expected struct type, found '{}'", .{ty.fmt(pt)}),
23359 else => return sema.fail(block, ty_src, "expected struct type, found '{f}'", .{ty.fmt(pt)}),
2336323360 }
2336423361
2336523362 const field_index = if (ty.isTuple(zcu)) blk: {
......@@ -23394,7 +23391,7 @@ fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Com
2339423391 const zcu = pt.zcu;
2339523392 switch (ty.zigTypeTag(zcu)) {
2339623393 .@"struct", .@"enum", .@"union", .@"opaque" => return,
23397 else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(pt)}),
23394 else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{f}'", .{ty.fmt(pt)}),
2339823395 }
2339923396}
2340023397
......@@ -23405,7 +23402,7 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr
2340523402 switch (ty.zigTypeTag(zcu)) {
2340623403 .comptime_int => return true,
2340723404 .int => return false,
23408 else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(pt)}),
23405 else => return sema.fail(block, src, "expected integer type, found '{f}'", .{ty.fmt(pt)}),
2340923406 }
2341023407}
2341123408
......@@ -23459,7 +23456,7 @@ fn checkPtrOperand(
2345923456 const msg = msg: {
2346023457 const msg = try sema.errMsg(
2346123458 ty_src,
23462 "expected pointer, found '{}'",
23459 "expected pointer, found '{f}'",
2346323460 .{ty.fmt(pt)},
2346423461 );
2346523462 errdefer msg.destroy(sema.gpa);
......@@ -23473,7 +23470,7 @@ fn checkPtrOperand(
2347323470 .optional => if (ty.childType(zcu).zigTypeTag(zcu) == .pointer) return,
2347423471 else => {},
2347523472 }
23476 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)});
23473 return sema.fail(block, ty_src, "expected pointer type, found '{f}'", .{ty.fmt(pt)});
2347723474}
2347823475
2347923476fn checkPtrType(
......@@ -23491,7 +23488,7 @@ fn checkPtrType(
2349123488 const msg = msg: {
2349223489 const msg = try sema.errMsg(
2349323490 ty_src,
23494 "expected pointer type, found '{}'",
23491 "expected pointer type, found '{f}'",
2349523492 .{ty.fmt(pt)},
2349623493 );
2349723494 errdefer msg.destroy(sema.gpa);
......@@ -23505,7 +23502,7 @@ fn checkPtrType(
2350523502 .optional => if (ty.childType(zcu).zigTypeTag(zcu) == .pointer) return,
2350623503 else => {},
2350723504 }
23508 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)});
23505 return sema.fail(block, ty_src, "expected pointer type, found '{f}'", .{ty.fmt(pt)});
2350923506}
2351023507
2351123508fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
......@@ -23516,7 +23513,7 @@ fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
2351623513 const as = ty.ptrAddressSpace(zcu);
2351723514 if (target_util.arePointersLogical(target, as)) {
2351823515 return sema.failWithOwnedErrorMsg(block, msg: {
23519 const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{}'", .{ty.fmt(pt)});
23516 const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{f}'", .{ty.fmt(pt)});
2352023517 errdefer msg.destroy(sema.gpa);
2352123518 try sema.errNote(
2352223519 src,
......@@ -23547,7 +23544,7 @@ fn checkVectorElemType(
2354723544 .optional, .pointer => if (ty.isPtrAtRuntime(zcu)) return,
2354823545 else => {},
2354923546 }
23550 return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(pt)});
23547 return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{f}'", .{ty.fmt(pt)});
2355123548}
2355223549
2355323550fn checkFloatType(
......@@ -23560,7 +23557,7 @@ fn checkFloatType(
2356023557 const zcu = pt.zcu;
2356123558 switch (ty.zigTypeTag(zcu)) {
2356223559 .comptime_int, .comptime_float, .float => {},
23563 else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(pt)}),
23560 else => return sema.fail(block, ty_src, "expected float type, found '{f}'", .{ty.fmt(pt)}),
2356423561 }
2356523562}
2356623563
......@@ -23576,9 +23573,9 @@ fn checkNumericType(
2357623573 .comptime_float, .float, .comptime_int, .int => {},
2357723574 .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
2357823575 .comptime_float, .float, .comptime_int, .int => {},
23579 else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}),
23576 else => |t| return sema.fail(block, ty_src, "expected number, found '{t}'", .{t}),
2358023577 },
23581 else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(pt)}),
23578 else => return sema.fail(block, ty_src, "expected number, found '{f}'", .{ty.fmt(pt)}),
2358223579 }
2358323580}
2358423581
......@@ -23612,7 +23609,7 @@ fn checkAtomicPtrOperand(
2361223609 error.BadType => return sema.fail(
2361323610 block,
2361423611 elem_ty_src,
23615 "expected bool, integer, float, enum, packed struct, or pointer type; found '{}'",
23612 "expected bool, integer, float, enum, packed struct, or pointer type; found '{f}'",
2361623613 .{elem_ty.fmt(pt)},
2361723614 ),
2361823615 };
......@@ -23673,12 +23670,12 @@ fn checkIntOrVector(
2367323670 const elem_ty = operand_ty.childType(zcu);
2367423671 switch (elem_ty.zigTypeTag(zcu)) {
2367523672 .int => return elem_ty,
23676 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{
23673 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{f}'", .{
2367723674 elem_ty.fmt(pt),
2367823675 }),
2367923676 }
2368023677 },
23681 else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{
23678 else => return sema.fail(block, operand_src, "expected integer or vector, found '{f}'", .{
2368223679 operand_ty.fmt(pt),
2368323680 }),
2368423681 }
......@@ -23698,12 +23695,12 @@ fn checkIntOrVectorAllowComptime(
2369823695 const elem_ty = operand_ty.childType(zcu);
2369923696 switch (elem_ty.zigTypeTag(zcu)) {
2370023697 .int, .comptime_int => return elem_ty,
23701 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{
23698 else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{f}'", .{
2370223699 elem_ty.fmt(pt),
2370323700 }),
2370423701 }
2370523702 },
23706 else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{
23703 else => return sema.fail(block, operand_src, "expected integer or vector, found '{f}'", .{
2370723704 operand_ty.fmt(pt),
2370823705 }),
2370923706 }
......@@ -23794,7 +23791,7 @@ fn checkVectorizableBinaryOperands(
2379423791 }
2379523792 } else {
2379623793 const msg = msg: {
23797 const msg = try sema.errMsg(src, "mixed scalar and vector operands: '{}' and '{}'", .{
23794 const msg = try sema.errMsg(src, "mixed scalar and vector operands: '{f}' and '{f}'", .{
2379823795 lhs_ty.fmt(pt), rhs_ty.fmt(pt),
2379923796 });
2380023797 errdefer msg.destroy(sema.gpa);
......@@ -23928,7 +23925,7 @@ fn zirCmpxchg(
2392823925 return sema.fail(
2392923926 block,
2393023927 elem_ty_src,
23931 "expected bool, integer, enum, packed struct, or pointer type; found '{}'",
23928 "expected bool, integer, enum, packed struct, or pointer type; found '{f}'",
2393223929 .{elem_ty.fmt(pt)},
2393323930 );
2393423931 }
......@@ -24012,7 +24009,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
2401224009
2401324010 switch (dest_ty.zigTypeTag(zcu)) {
2401424011 .array, .vector => {},
24015 else => return sema.fail(block, src, "expected array or vector type, found '{}'", .{dest_ty.fmt(pt)}),
24012 else => return sema.fail(block, src, "expected array or vector type, found '{f}'", .{dest_ty.fmt(pt)}),
2401624013 }
2401724014
2401824015 const operand = try sema.resolveInst(extra.rhs);
......@@ -24088,7 +24085,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
2408824085 const zcu = pt.zcu;
2408924086
2409024087 if (operand_ty.zigTypeTag(zcu) != .vector) {
24091 return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(pt)});
24088 return sema.fail(block, operand_src, "expected vector, found '{f}'", .{operand_ty.fmt(pt)});
2409224089 }
2409324090
2409424091 const scalar_ty = operand_ty.childType(zcu);
......@@ -24097,13 +24094,13 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
2409724094 switch (operation) {
2409824095 .And, .Or, .Xor => switch (scalar_ty.zigTypeTag(zcu)) {
2409924096 .int, .bool => {},
24100 else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{
24097 else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{f}'", .{
2410124098 @tagName(operation), operand_ty.fmt(pt),
2410224099 }),
2410324100 },
2410424101 .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag(zcu)) {
2410524102 .int, .float => {},
24106 else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{
24103 else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{f}'", .{
2410724104 @tagName(operation), operand_ty.fmt(pt),
2410824105 }),
2410924106 },
......@@ -24157,7 +24154,7 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2415724154
2415824155 const mask_len = switch (sema.typeOf(mask).zigTypeTag(zcu)) {
2415924156 .array, .vector => sema.typeOf(mask).arrayLen(zcu),
24160 else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(pt)}),
24157 else => return sema.fail(block, mask_src, "expected vector or array, found '{f}'", .{sema.typeOf(mask).fmt(pt)}),
2416124158 };
2416224159 mask_ty = try pt.vectorType(.{
2416324160 .len = @intCast(mask_len),
......@@ -24184,11 +24181,14 @@ fn analyzeShuffle(
2418424181 const b_src = block.builtinCallArgSrc(src_node, 2);
2418524182 const mask_src = block.builtinCallArgSrc(src_node, 3);
2418624183
24187 // 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.
24184 // If the type of `a` is `@Type(.undefined)`, i.e. the argument is untyped,
24185 // this is 0, because it is an error to index into this vector.
2418824186 const a_len: u32 = switch (sema.typeOf(a_uncoerced).zigTypeTag(zcu)) {
2418924187 .array, .vector => @intCast(sema.typeOf(a_uncoerced).arrayLen(zcu)),
2419024188 .undefined => 0,
24191 else => return sema.fail(block, a_src, "expected vector of '{}', found '{}'", .{ elem_ty.fmt(pt), sema.typeOf(a_uncoerced).fmt(pt) }),
24189 else => return sema.fail(block, a_src, "expected vector of '{f}', found '{f}'", .{
24190 elem_ty.fmt(pt), sema.typeOf(a_uncoerced).fmt(pt),
24191 }),
2419224192 };
2419324193 const a_ty = try pt.vectorType(.{ .len = a_len, .child = elem_ty.toIntern() });
2419424194 const a_coerced = try sema.coerce(block, a_ty, a_uncoerced, a_src);
......@@ -24197,7 +24197,9 @@ fn analyzeShuffle(
2419724197 const b_len: u32 = switch (sema.typeOf(b_uncoerced).zigTypeTag(zcu)) {
2419824198 .array, .vector => @intCast(sema.typeOf(b_uncoerced).arrayLen(zcu)),
2419924199 .undefined => 0,
24200 else => return sema.fail(block, b_src, "expected vector of '{}', found '{}'", .{ elem_ty.fmt(pt), sema.typeOf(b_uncoerced).fmt(pt) }),
24200 else => return sema.fail(block, b_src, "expected vector of '{f}', found '{f}'", .{
24201 elem_ty.fmt(pt), sema.typeOf(b_uncoerced).fmt(pt),
24202 }),
2420124203 };
2420224204 const b_ty = try pt.vectorType(.{ .len = b_len, .child = elem_ty.toIntern() });
2420324205 const b_coerced = try sema.coerce(block, b_ty, b_uncoerced, b_src);
......@@ -24235,7 +24237,7 @@ fn analyzeShuffle(
2423524237 if (idx >= a_len) return sema.failWithOwnedErrorMsg(block, msg: {
2423624238 const msg = try sema.errMsg(mask_src, "mask element at index '{d}' selects out-of-bounds index", .{mask_idx});
2423724239 errdefer msg.destroy(sema.gpa);
24238 try sema.errNote(a_src, msg, "index '{d}' exceeds bounds of '{}' given here", .{ idx, a_ty.fmt(pt) });
24240 try sema.errNote(a_src, msg, "index '{d}' exceeds bounds of '{f}' given here", .{ idx, a_ty.fmt(pt) });
2423924241 if (idx < b_len) {
2424024242 try sema.errNote(b_src, msg, "use '~@as(u32, {d})' to index into second vector given here", .{idx});
2424124243 }
......@@ -24248,7 +24250,7 @@ fn analyzeShuffle(
2424824250 if (idx >= b_len) return sema.failWithOwnedErrorMsg(block, msg: {
2424924251 const msg = try sema.errMsg(mask_src, "mask element at index '{d}' selects out-of-bounds index", .{mask_idx});
2425024252 errdefer msg.destroy(sema.gpa);
24251 try sema.errNote(b_src, msg, "index '{d}' exceeds bounds of '{}' given here", .{ idx, b_ty.fmt(pt) });
24253 try sema.errNote(b_src, msg, "index '{d}' exceeds bounds of '{f}' given here", .{ idx, b_ty.fmt(pt) });
2425224254 break :msg msg;
2425324255 });
2425424256 }
......@@ -24351,7 +24353,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
2435124353
2435224354 const vec_len_u64 = switch (pred_ty.zigTypeTag(zcu)) {
2435324355 .vector, .array => pred_ty.arrayLen(zcu),
24354 else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(pt)}),
24356 else => return sema.fail(block, pred_src, "expected vector or array, found '{f}'", .{pred_ty.fmt(pt)}),
2435524357 };
2435624358 const vec_len: u32 = @intCast(try sema.usizeCast(block, pred_src, vec_len_u64));
2435724359
......@@ -24611,7 +24613,7 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
2461124613
2461224614 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
2461324615 .comptime_float, .float => {},
24614 else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(pt)}),
24616 else => return sema.fail(block, src, "expected vector of floats or float type, found '{f}'", .{ty.fmt(pt)}),
2461524617 }
2461624618
2461724619 const runtime_src = if (maybe_mulend1) |mulend1_val| rs: {
......@@ -24712,7 +24714,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
2471224714
2471324715 const args_ty = sema.typeOf(args);
2471424716 if (!args_ty.isTuple(zcu)) {
24715 return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(pt)});
24717 return sema.fail(block, args_src, "expected a tuple, found '{f}'", .{args_ty.fmt(pt)});
2471624718 }
2471724719
2471824720 const resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount(zcu));
......@@ -24757,12 +24759,12 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2475724759 try sema.checkPtrType(block, inst_src, parent_ptr_ty, true);
2475824760 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
2475924761 if (parent_ptr_info.flags.size != .one) {
24760 return sema.fail(block, inst_src, "expected single pointer type, found '{}'", .{parent_ptr_ty.fmt(pt)});
24762 return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)});
2476124763 }
2476224764 const parent_ty: Type = .fromInterned(parent_ptr_info.child);
2476324765 switch (parent_ty.zigTypeTag(zcu)) {
2476424766 .@"struct", .@"union" => {},
24765 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{}'", .{parent_ptr_ty.fmt(pt)}),
24767 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}),
2476624768 }
2476724769 try parent_ty.resolveLayout(pt);
2476824770
......@@ -24912,7 +24914,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2491224914 }
2491324915
2491424916 if (field.index != field_index) {
24915 return sema.fail(block, inst_src, "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'", .{
24917 return sema.fail(block, inst_src, "field '{f}' has index '{d}' but pointer value is index '{d}' of struct '{f}'", .{
2491624918 field_name.fmt(ip), field_index, field.index, parent_ty.fmt(pt),
2491724919 });
2491824920 }
......@@ -25033,7 +25035,7 @@ fn analyzeMinMax(
2503325035 try sema.checkNumericType(block, operand_src, operand_ty);
2503425036 if (operand_ty.zigTypeTag(zcu) != .vector) {
2503525037 return sema.failWithOwnedErrorMsg(block, msg: {
25036 const msg = try sema.errMsg(operand_src, "expected vector, found '{}'", .{operand_ty.fmt(pt)});
25038 const msg = try sema.errMsg(operand_src, "expected vector, found '{f}'", .{operand_ty.fmt(pt)});
2503725039 errdefer msg.destroy(zcu.gpa);
2503825040 try sema.errNote(operand_srcs[0], msg, "vector operand here", .{});
2503925041 break :msg msg;
......@@ -25041,7 +25043,7 @@ fn analyzeMinMax(
2504125043 }
2504225044 if (operand_ty.vectorLen(zcu) != vec_len) {
2504325045 return sema.failWithOwnedErrorMsg(block, msg: {
25044 const msg = try sema.errMsg(operand_src, "expected vector of length '{d}', found '{}'", .{ vec_len, operand_ty.fmt(pt) });
25046 const msg = try sema.errMsg(operand_src, "expected vector of length '{d}', found '{f}'", .{ vec_len, operand_ty.fmt(pt) });
2504525047 errdefer msg.destroy(zcu.gpa);
2504625048 try sema.errNote(operand_srcs[0], msg, "vector of length '{d}' here", .{vec_len});
2504725049 break :msg msg;
......@@ -25054,7 +25056,7 @@ fn analyzeMinMax(
2505425056 const operand_ty = sema.typeOf(operand);
2505525057 if (operand_ty.zigTypeTag(zcu) == .vector) {
2505625058 return sema.failWithOwnedErrorMsg(block, msg: {
25057 const msg = try sema.errMsg(operand_srcs[0], "expected vector, found '{}'", .{first_operand_ty.fmt(pt)});
25059 const msg = try sema.errMsg(operand_srcs[0], "expected vector, found '{f}'", .{first_operand_ty.fmt(pt)});
2505825060 errdefer msg.destroy(zcu.gpa);
2505925061 try sema.errNote(operand_src, msg, "vector operand here", .{});
2506025062 break :msg msg;
......@@ -25371,10 +25373,10 @@ fn zirMemcpy(
2537125373 const msg = msg: {
2537225374 const msg = try sema.errMsg(src, "unknown copy length", .{});
2537325375 errdefer msg.destroy(sema.gpa);
25374 try sema.errNote(dest_src, msg, "destination type '{}' provides no length", .{
25376 try sema.errNote(dest_src, msg, "destination type '{f}' provides no length", .{
2537525377 dest_ty.fmt(pt),
2537625378 });
25377 try sema.errNote(src_src, msg, "source type '{}' provides no length", .{
25379 try sema.errNote(src_src, msg, "source type '{f}' provides no length", .{
2537825380 src_ty.fmt(pt),
2537925381 });
2538025382 break :msg msg;
......@@ -25398,7 +25400,7 @@ fn zirMemcpy(
2539825400 if (imc != .ok) return sema.failWithOwnedErrorMsg(block, msg: {
2539925401 const msg = try sema.errMsg(
2540025402 src,
25401 "pointer element type '{}' cannot coerce into element type '{}'",
25403 "pointer element type '{f}' cannot coerce into element type '{f}'",
2540225404 .{ src_elem_ty.fmt(pt), dest_elem_ty.fmt(pt) },
2540325405 );
2540425406 errdefer msg.destroy(sema.gpa);
......@@ -25417,10 +25419,10 @@ fn zirMemcpy(
2541725419 const msg = msg: {
2541825420 const msg = try sema.errMsg(src, "non-matching copy lengths", .{});
2541925421 errdefer msg.destroy(sema.gpa);
25420 try sema.errNote(dest_src, msg, "length {} here", .{
25422 try sema.errNote(dest_src, msg, "length {f} here", .{
2542125423 dest_len_val.fmtValueSema(pt, sema),
2542225424 });
25423 try sema.errNote(src_src, msg, "length {} here", .{
25425 try sema.errNote(src_src, msg, "length {f} here", .{
2542425426 src_len_val.fmtValueSema(pt, sema),
2542525427 });
2542625428 break :msg msg;
......@@ -25635,7 +25637,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2563525637 return sema.failWithOwnedErrorMsg(block, msg: {
2563625638 const msg = try sema.errMsg(src, "unknown @memset length", .{});
2563725639 errdefer msg.destroy(sema.gpa);
25638 try sema.errNote(dest_src, msg, "destination type '{}' provides no length", .{
25640 try sema.errNote(dest_src, msg, "destination type '{f}' provides no length", .{
2563925641 dest_ptr_ty.fmt(pt),
2564025642 });
2564125643 break :msg msg;
......@@ -25815,7 +25817,7 @@ fn zirCUndef(
2581525817 const src = block.builtinCallArgSrc(extra.node, 0);
2581625818
2581725819 const name = try sema.resolveConstString(block, src, extra.operand, .{ .simple = .operand_cUndef_macro_name });
25818 try block.c_import_buf.?.writer().print("#undef {s}\n", .{name});
25820 try block.c_import_buf.?.print("#undef {s}\n", .{name});
2581925821 return .void_value;
2582025822}
2582125823
......@@ -25828,7 +25830,7 @@ fn zirCInclude(
2582825830 const src = block.builtinCallArgSrc(extra.node, 0);
2582925831
2583025832 const name = try sema.resolveConstString(block, src, extra.operand, .{ .simple = .operand_cInclude_file_name });
25831 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});
25833 try block.c_import_buf.?.print("#include <{s}>\n", .{name});
2583225834 return .void_value;
2583325835}
2583425836
......@@ -25847,9 +25849,9 @@ fn zirCDefine(
2584725849 const rhs = try sema.resolveInst(extra.rhs);
2584825850 if (sema.typeOf(rhs).zigTypeTag(zcu) != .void) {
2584925851 const value = try sema.resolveConstString(block, val_src, extra.rhs, .{ .simple = .operand_cDefine_macro_value });
25850 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
25852 try block.c_import_buf.?.print("#define {s} {s}\n", .{ name, value });
2585125853 } else {
25852 try block.c_import_buf.?.writer().print("#define {s}\n", .{name});
25854 try block.c_import_buf.?.print("#define {s}\n", .{name});
2585325855 }
2585425856 return .void_value;
2585525857}
......@@ -26067,7 +26069,7 @@ fn zirBuiltinExtern(
2606726069 }
2606826070 if (!try sema.validateExternType(ty, .other)) {
2606926071 const msg = msg: {
26070 const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(pt)});
26072 const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)});
2607126073 errdefer msg.destroy(sema.gpa);
2607226074 try sema.explainWhyTypeIsNotExtern(msg, ty_src, ty, .other);
2607326075 break :msg msg;
......@@ -26307,7 +26309,7 @@ pub fn validateVarType(
2630726309 if (is_extern) {
2630826310 if (!try sema.validateExternType(var_ty, .other)) {
2630926311 const msg = msg: {
26310 const msg = try sema.errMsg(src, "extern variable cannot have type '{}'", .{var_ty.fmt(pt)});
26312 const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)});
2631126313 errdefer msg.destroy(sema.gpa);
2631226314 try sema.explainWhyTypeIsNotExtern(msg, src, var_ty, .other);
2631326315 break :msg msg;
......@@ -26319,7 +26321,7 @@ pub fn validateVarType(
2631926321 return sema.fail(
2632026322 block,
2632126323 src,
26322 "non-extern variable with opaque type '{}'",
26324 "non-extern variable with opaque type '{f}'",
2632326325 .{var_ty.fmt(pt)},
2632426326 );
2632526327 }
......@@ -26328,7 +26330,7 @@ pub fn validateVarType(
2632826330 if (!try var_ty.comptimeOnlySema(pt)) return;
2632926331
2633026332 const msg = msg: {
26331 const msg = try sema.errMsg(src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(pt)});
26333 const msg = try sema.errMsg(src, "variable of type '{f}' must be const or comptime", .{var_ty.fmt(pt)});
2633226334 errdefer msg.destroy(sema.gpa);
2633326335
2633426336 try sema.explainWhyTypeIsComptime(msg, src, var_ty);
......@@ -26378,7 +26380,7 @@ fn explainWhyTypeIsComptimeInner(
2637826380 => return,
2637926381
2638026382 .@"fn" => {
26381 try sema.errNote(src_loc, msg, "use '*const {}' for a function pointer type", .{ty.fmt(pt)});
26383 try sema.errNote(src_loc, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)});
2638226384 },
2638326385
2638426386 .type => {
......@@ -26394,7 +26396,7 @@ fn explainWhyTypeIsComptimeInner(
2639426396 => return,
2639526397
2639626398 .@"opaque" => {
26397 try sema.errNote(src_loc, msg, "opaque type '{}' has undefined size", .{ty.fmt(pt)});
26399 try sema.errNote(src_loc, msg, "opaque type '{f}' has undefined size", .{ty.fmt(pt)});
2639826400 },
2639926401
2640026402 .array, .vector => {
......@@ -26581,7 +26583,7 @@ fn explainWhyTypeIsNotExtern(
2658126583 if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") {
2658226584 try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{});
2658326585 } else if (try ty.comptimeOnlySema(pt)) {
26584 try sema.errNote(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(pt)});
26586 try sema.errNote(src_loc, msg, "pointer to comptime-only type '{f}'", .{pointee_ty.fmt(pt)});
2658526587 try sema.explainWhyTypeIsComptime(msg, src_loc, ty);
2658626588 }
2658726589 try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other);
......@@ -26609,7 +26611,7 @@ fn explainWhyTypeIsNotExtern(
2660926611 },
2661026612 .@"enum" => {
2661126613 const tag_ty = ty.intTagType(zcu);
26612 try sema.errNote(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(pt)});
26614 try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)});
2661326615 try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
2661426616 },
2661526617 .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),
......@@ -27045,7 +27047,7 @@ fn fieldVal(
2704527047 return sema.fail(
2704627048 block,
2704727049 field_name_src,
27048 "no member named '{}' in '{}'",
27050 "no member named '{f}' in '{f}'",
2704927051 .{ field_name.fmt(ip), object_ty.fmt(pt) },
2705027052 );
2705127053 }
......@@ -27069,7 +27071,7 @@ fn fieldVal(
2706927071 return sema.fail(
2707027072 block,
2707127073 field_name_src,
27072 "no member named '{}' in '{}'",
27074 "no member named '{f}' in '{f}'",
2707327075 .{ field_name.fmt(ip), object_ty.fmt(pt) },
2707427076 );
2707527077 }
......@@ -27089,7 +27091,7 @@ fn fieldVal(
2708927091 switch (ip.indexToKey(child_type.toIntern())) {
2709027092 .error_set_type => |error_set_type| blk: {
2709127093 if (error_set_type.nameIndex(ip, field_name) != null) break :blk;
27092 return sema.fail(block, src, "no error named '{}' in '{}'", .{
27094 return sema.fail(block, src, "no error named '{f}' in '{f}'", .{
2709327095 field_name.fmt(ip), child_type.fmt(pt),
2709427096 });
2709527097 },
......@@ -27144,7 +27146,7 @@ fn fieldVal(
2714427146 return sema.failWithBadMemberAccess(block, child_type, src, field_name);
2714527147 },
2714627148 else => return sema.failWithOwnedErrorMsg(block, msg: {
27147 const msg = try sema.errMsg(src, "type '{}' has no members", .{child_type.fmt(pt)});
27149 const msg = try sema.errMsg(src, "type '{f}' has no members", .{child_type.fmt(pt)});
2714827150 errdefer msg.destroy(sema.gpa);
2714927151 if (child_type.isSlice(zcu)) try sema.errNote(src, msg, "slice values have 'len' and 'ptr' members", .{});
2715027152 if (child_type.zigTypeTag(zcu) == .array) try sema.errNote(src, msg, "array values have 'len' member", .{});
......@@ -27190,7 +27192,7 @@ fn fieldPtr(
2719027192 const object_ptr_ty = sema.typeOf(object_ptr);
2719127193 const object_ty = switch (object_ptr_ty.zigTypeTag(zcu)) {
2719227194 .pointer => object_ptr_ty.childType(zcu),
27193 else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(pt)}),
27195 else => return sema.fail(block, object_ptr_src, "expected pointer, found '{f}'", .{object_ptr_ty.fmt(pt)}),
2719427196 };
2719527197
2719627198 // Zig allows dereferencing a single pointer during field lookup. Note that
......@@ -27243,7 +27245,7 @@ fn fieldPtr(
2724327245 return sema.fail(
2724427246 block,
2724527247 field_name_src,
27246 "no member named '{}' in '{}'",
27248 "no member named '{f}' in '{f}'",
2724727249 .{ field_name.fmt(ip), object_ty.fmt(pt) },
2724827250 );
2724927251 }
......@@ -27298,7 +27300,7 @@ fn fieldPtr(
2729827300 return sema.fail(
2729927301 block,
2730027302 field_name_src,
27301 "no member named '{}' in '{}'",
27303 "no member named '{f}' in '{f}'",
2730227304 .{ field_name.fmt(ip), object_ty.fmt(pt) },
2730327305 );
2730427306 }
......@@ -27321,7 +27323,7 @@ fn fieldPtr(
2732127323 if (error_set_type.nameIndex(ip, field_name) != null) {
2732227324 break :blk;
2732327325 }
27324 return sema.fail(block, src, "no error named '{}' in '{}'", .{
27326 return sema.fail(block, src, "no error named '{f}' in '{f}'", .{
2732527327 field_name.fmt(ip), child_type.fmt(pt),
2732627328 });
2732727329 },
......@@ -27375,7 +27377,7 @@ fn fieldPtr(
2737527377 }
2737627378 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
2737727379 },
27378 else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(pt)}),
27380 else => return sema.fail(block, src, "type '{f}' has no members", .{child_type.fmt(pt)}),
2737927381 }
2738027382 },
2738127383 .@"struct" => {
......@@ -27430,7 +27432,7 @@ fn fieldCallBind(
2743027432 const inner_ty = if (raw_ptr_ty.zigTypeTag(zcu) == .pointer and (raw_ptr_ty.ptrSize(zcu) == .one or raw_ptr_ty.ptrSize(zcu) == .c))
2743127433 raw_ptr_ty.childType(zcu)
2743227434 else
27433 return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(pt)});
27435 return sema.fail(block, raw_ptr_src, "expected single pointer, found '{f}'", .{raw_ptr_ty.fmt(pt)});
2743427436
2743527437 // Optionally dereference a second pointer to get the concrete type.
2743627438 const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one;
......@@ -27549,7 +27551,7 @@ fn fieldCallBind(
2754927551 };
2755027552
2755127553 const msg = msg: {
27552 const msg = try sema.errMsg(src, "no field or member function named '{}' in '{}'", .{
27554 const msg = try sema.errMsg(src, "no field or member function named '{f}' in '{f}'", .{
2755327555 field_name.fmt(ip),
2755427556 concrete_ty.fmt(pt),
2755527557 });
......@@ -27559,7 +27561,7 @@ fn fieldCallBind(
2755927561 try sema.errNote(
2756027562 zcu.navSrcLoc(nav_index),
2756127563 msg,
27562 "'{}' is not a member function",
27564 "'{f}' is not a member function",
2756327565 .{field_name.fmt(ip)},
2756427566 );
2756527567 }
......@@ -27627,7 +27629,7 @@ fn namespaceLookup(
2762727629 if (try sema.lookupInNamespace(block, namespace, decl_name)) |lookup| {
2762827630 if (!lookup.accessible) {
2762927631 return sema.failWithOwnedErrorMsg(block, msg: {
27630 const msg = try sema.errMsg(src, "'{}' is not marked 'pub'", .{
27632 const msg = try sema.errMsg(src, "'{f}' is not marked 'pub'", .{
2763127633 decl_name.fmt(&zcu.intern_pool),
2763227634 });
2763327635 errdefer msg.destroy(gpa);
......@@ -27865,12 +27867,12 @@ fn tupleFieldIndex(
2786527867 assert(!field_name.eqlSlice("len", ip));
2786627868 if (field_name.toUnsigned(ip)) |field_index| {
2786727869 if (field_index < tuple_ty.structFieldCount(pt.zcu)) return field_index;
27868 return sema.fail(block, field_name_src, "index '{}' out of bounds of tuple '{}'", .{
27870 return sema.fail(block, field_name_src, "index '{f}' out of bounds of tuple '{f}'", .{
2786927871 field_name.fmt(ip), tuple_ty.fmt(pt),
2787027872 });
2787127873 }
2787227874
27873 return sema.fail(block, field_name_src, "no field named '{}' in tuple '{}'", .{
27875 return sema.fail(block, field_name_src, "no field named '{f}' in tuple '{f}'", .{
2787427876 field_name.fmt(ip), tuple_ty.fmt(pt),
2787527877 });
2787627878}
......@@ -27957,7 +27959,7 @@ fn unionFieldPtr(
2795727959 const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{});
2795827960 errdefer msg.destroy(sema.gpa);
2795927961
27960 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
27962 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
2796127963 field_name.fmt(ip),
2796227964 });
2796327965 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -27991,7 +27993,7 @@ fn unionFieldPtr(
2799127993 const msg = msg: {
2799227994 const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
2799327995 const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu);
27994 const msg = try sema.errMsg(src, "access of union field '{}' while field '{}' is active", .{
27996 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
2799527997 field_name.fmt(ip),
2799627998 active_field_name.fmt(ip),
2799727999 });
......@@ -28059,7 +28061,7 @@ fn unionFieldVal(
2805928061 const msg = msg: {
2806028062 const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
2806128063 const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu);
28062 const msg = try sema.errMsg(src, "access of union field '{}' while field '{}' is active", .{
28064 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
2806328065 field_name.fmt(ip), active_field_name.fmt(ip),
2806428066 });
2806528067 errdefer msg.destroy(sema.gpa);
......@@ -28117,7 +28119,7 @@ fn elemPtr(
2811728119
2811828120 const indexable_ty = switch (indexable_ptr_ty.zigTypeTag(zcu)) {
2811928121 .pointer => indexable_ptr_ty.childType(zcu),
28120 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(pt)}),
28122 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}),
2812128123 };
2812228124 try sema.checkIndexable(block, src, indexable_ty);
2812328125
......@@ -28288,7 +28290,7 @@ fn validateRuntimeElemAccess(
2828828290 const msg = msg: {
2828928291 const msg = try sema.errMsg(
2829028292 elem_index_src,
28291 "values of type '{}' must be comptime-known, but index value is runtime-known",
28293 "values of type '{f}' must be comptime-known, but index value is runtime-known",
2829228294 .{parent_ty.fmt(sema.pt)},
2829328295 );
2829428296 errdefer msg.destroy(sema.gpa);
......@@ -28304,7 +28306,7 @@ fn validateRuntimeElemAccess(
2830428306 const target = zcu.getTarget();
2830528307 const as = parent_ty.ptrAddressSpace(zcu);
2830628308 if (target_util.arePointersLogical(target, as)) {
28307 return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{}'", .{parent_ty.fmt(pt)});
28309 return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{f}'", .{parent_ty.fmt(pt)});
2830828310 }
2830928311 }
2831028312}
......@@ -29000,7 +29002,7 @@ fn coerceExtra(
2900029002 return sema.fail(
2900129003 block,
2900229004 inst_src,
29003 "array literal requires address-of operator (&) to coerce to slice type '{}'",
29005 "array literal requires address-of operator (&) to coerce to slice type '{f}'",
2900429006 .{dest_ty.fmt(pt)},
2900529007 );
2900629008 }
......@@ -29027,7 +29029,7 @@ fn coerceExtra(
2902729029 // pointer to tuple to slice
2902829030 if (!dest_info.flags.is_const) {
2902929031 const err_msg = err_msg: {
29030 const err_msg = try sema.errMsg(inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(pt)});
29032 const err_msg = try sema.errMsg(inst_src, "cannot cast pointer to tuple to '{f}'", .{dest_ty.fmt(pt)});
2903129033 errdefer err_msg.destroy(sema.gpa);
2903229034 try sema.errNote(dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});
2903329035 break :err_msg err_msg;
......@@ -29082,7 +29084,7 @@ fn coerceExtra(
2908229084 // comptime-known integer to other number
2908329085 if (!(try sema.intFitsInType(val, dest_ty, null))) {
2908429086 if (!opts.report_err) return error.NotCoercible;
29085 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });
29087 return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });
2908629088 }
2908729089 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
2908829090 .undef => try pt.undefRef(dest_ty),
......@@ -29124,7 +29126,7 @@ fn coerceExtra(
2912429126 return sema.fail(
2912529127 block,
2912629128 inst_src,
29127 "type '{}' cannot represent float value '{}'",
29129 "type '{f}' cannot represent float value '{f}'",
2912829130 .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) },
2912929131 );
2913029132 }
......@@ -29157,7 +29159,7 @@ fn coerceExtra(
2915729159 // return sema.fail(
2915829160 // block,
2915929161 // inst_src,
29160 // "type '{}' cannot represent integer value '{}'",
29162 // "type '{f}' cannot represent integer value '{f}'",
2916129163 // .{ dest_ty.fmt(pt), val },
2916229164 // );
2916329165 //}
......@@ -29171,7 +29173,7 @@ fn coerceExtra(
2917129173 const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
2917229174 const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal;
2917329175 const field_index = dest_ty.enumFieldIndex(string, zcu) orelse {
29174 return sema.fail(block, inst_src, "no field named '{}' in enum '{}'", .{
29176 return sema.fail(block, inst_src, "no field named '{f}' in enum '{f}'", .{
2917529177 string.fmt(&zcu.intern_pool), dest_ty.fmt(pt),
2917629178 });
2917729179 };
......@@ -29320,11 +29322,11 @@ fn coerceExtra(
2932029322 }
2932129323
2932229324 const msg = msg: {
29323 const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt) });
29325 const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt) });
2932429326 errdefer msg.destroy(sema.gpa);
2932529327
2932629328 if (!can_coerce_to) {
29327 try sema.errNote(inst_src, msg, "cannot coerce to '{}'", .{dest_ty.fmt(pt)});
29329 try sema.errNote(inst_src, msg, "cannot coerce to '{f}'", .{dest_ty.fmt(pt)});
2932829330 }
2932929331
2933029332 // E!T to T
......@@ -29364,7 +29366,7 @@ fn coerceExtra(
2936429366 try sema.errNote(param_src, msg, "parameter type declared here", .{});
2936529367 }
2936629368
29367 // TODO maybe add "cannot store an error in type '{}'" note
29369 // TODO maybe add "cannot store an error in type '{f}'" note
2936829370
2936929371 break :msg msg;
2937029372 };
......@@ -29513,13 +29515,13 @@ const InMemoryCoercionResult = union(enum) {
2951329515 break;
2951429516 },
2951529517 .comptime_int_not_coercible => |int| {
29516 try sema.errNote(src, msg, "type '{}' cannot represent value '{}'", .{
29518 try sema.errNote(src, msg, "type '{f}' cannot represent value '{f}'", .{
2951729519 int.wanted.fmt(pt), int.actual.fmtValueSema(pt, sema),
2951829520 });
2951929521 break;
2952029522 },
2952129523 .error_union_payload => |pair| {
29522 try sema.errNote(src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{
29524 try sema.errNote(src, msg, "error union payload '{f}' cannot cast into error union payload '{f}'", .{
2952329525 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2952429526 });
2952529527 cur = pair.child;
......@@ -29532,18 +29534,18 @@ const InMemoryCoercionResult = union(enum) {
2953229534 },
2953329535 .array_sentinel => |sentinel| {
2953429536 if (sentinel.actual.toIntern() != .unreachable_value) {
29535 try sema.errNote(src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{
29537 try sema.errNote(src, msg, "array sentinel '{f}' cannot cast into array sentinel '{f}'", .{
2953629538 sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema),
2953729539 });
2953829540 } else {
29539 try sema.errNote(src, msg, "destination array requires '{}' sentinel", .{
29541 try sema.errNote(src, msg, "destination array requires '{f}' sentinel", .{
2954029542 sentinel.wanted.fmtValueSema(pt, sema),
2954129543 });
2954229544 }
2954329545 break;
2954429546 },
2954529547 .array_elem => |pair| {
29546 try sema.errNote(src, msg, "array element type '{}' cannot cast into array element type '{}'", .{
29548 try sema.errNote(src, msg, "array element type '{f}' cannot cast into array element type '{f}'", .{
2954729549 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2954829550 });
2954929551 cur = pair.child;
......@@ -29555,19 +29557,19 @@ const InMemoryCoercionResult = union(enum) {
2955529557 break;
2955629558 },
2955729559 .vector_elem => |pair| {
29558 try sema.errNote(src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{
29560 try sema.errNote(src, msg, "vector element type '{f}' cannot cast into vector element type '{f}'", .{
2955929561 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2956029562 });
2956129563 cur = pair.child;
2956229564 },
2956329565 .optional_shape => |pair| {
29564 try sema.errNote(src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
29566 try sema.errNote(src, msg, "optional type child '{f}' cannot cast into optional type child '{f}'", .{
2956529567 pair.actual.optionalChild(pt.zcu).fmt(pt), pair.wanted.optionalChild(pt.zcu).fmt(pt),
2956629568 });
2956729569 break;
2956829570 },
2956929571 .optional_child => |pair| {
29570 try sema.errNote(src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
29572 try sema.errNote(src, msg, "optional type child '{f}' cannot cast into optional type child '{f}'", .{
2957129573 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2957229574 });
2957329575 cur = pair.child;
......@@ -29578,7 +29580,7 @@ const InMemoryCoercionResult = union(enum) {
2957829580 },
2957929581 .missing_error => |missing_errors| {
2958029582 for (missing_errors) |err| {
29581 try sema.errNote(src, msg, "'error.{}' not a member of destination error set", .{err.fmt(&pt.zcu.intern_pool)});
29583 try sema.errNote(src, msg, "'error.{f}' not a member of destination error set", .{err.fmt(&pt.zcu.intern_pool)});
2958229584 }
2958329585 break;
2958429586 },
......@@ -29631,7 +29633,7 @@ const InMemoryCoercionResult = union(enum) {
2963129633 break;
2963229634 },
2963329635 .fn_param => |param| {
29634 try sema.errNote(src, msg, "parameter {d} '{}' cannot cast into '{}'", .{
29636 try sema.errNote(src, msg, "parameter {d} '{f}' cannot cast into '{f}'", .{
2963529637 param.index, param.actual.fmt(pt), param.wanted.fmt(pt),
2963629638 });
2963729639 cur = param.child;
......@@ -29641,13 +29643,13 @@ const InMemoryCoercionResult = union(enum) {
2964129643 break;
2964229644 },
2964329645 .fn_return_type => |pair| {
29644 try sema.errNote(src, msg, "return type '{}' cannot cast into return type '{}'", .{
29646 try sema.errNote(src, msg, "return type '{f}' cannot cast into return type '{f}'", .{
2964529647 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2964629648 });
2964729649 cur = pair.child;
2964829650 },
2964929651 .ptr_child => |pair| {
29650 try sema.errNote(src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{
29652 try sema.errNote(src, msg, "pointer type child '{f}' cannot cast into pointer type child '{f}'", .{
2965129653 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2965229654 });
2965329655 cur = pair.child;
......@@ -29658,11 +29660,11 @@ const InMemoryCoercionResult = union(enum) {
2965829660 },
2965929661 .ptr_sentinel => |sentinel| {
2966029662 if (sentinel.actual.toIntern() != .unreachable_value) {
29661 try sema.errNote(src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{
29663 try sema.errNote(src, msg, "pointer sentinel '{f}' cannot cast into pointer sentinel '{f}'", .{
2966229664 sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema),
2966329665 });
2966429666 } else {
29665 try sema.errNote(src, msg, "destination pointer requires '{}' sentinel", .{
29667 try sema.errNote(src, msg, "destination pointer requires '{f}' sentinel", .{
2966629668 sentinel.wanted.fmtValueSema(pt, sema),
2966729669 });
2966829670 }
......@@ -29676,11 +29678,11 @@ const InMemoryCoercionResult = union(enum) {
2967629678 const wanted_allow_zero = pair.wanted.ptrAllowsZero(pt.zcu);
2967729679 const actual_allow_zero = pair.actual.ptrAllowsZero(pt.zcu);
2967829680 if (actual_allow_zero and !wanted_allow_zero) {
29679 try sema.errNote(src, msg, "'{}' could have null values which are illegal in type '{}'", .{
29681 try sema.errNote(src, msg, "'{f}' could have null values which are illegal in type '{f}'", .{
2968029682 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2968129683 });
2968229684 } else {
29683 try sema.errNote(src, msg, "mutable '{}' would allow illegal null values stored to type '{}'", .{
29685 try sema.errNote(src, msg, "mutable '{f}' would allow illegal null values stored to type '{f}'", .{
2968429686 pair.wanted.fmt(pt), pair.actual.fmt(pt),
2968529687 });
2968629688 }
......@@ -29692,7 +29694,7 @@ const InMemoryCoercionResult = union(enum) {
2969229694 if (actual_const and !wanted_const) {
2969329695 try sema.errNote(src, msg, "cast discards const qualifier", .{});
2969429696 } else {
29695 try sema.errNote(src, msg, "mutable '{}' would allow illegal const pointers stored to type '{}'", .{
29697 try sema.errNote(src, msg, "mutable '{f}' would allow illegal const pointers stored to type '{f}'", .{
2969629698 pair.wanted.fmt(pt), pair.actual.fmt(pt),
2969729699 });
2969829700 }
......@@ -29704,7 +29706,7 @@ const InMemoryCoercionResult = union(enum) {
2970429706 if (actual_volatile and !wanted_volatile) {
2970529707 try sema.errNote(src, msg, "cast discards volatile qualifier", .{});
2970629708 } else {
29707 try sema.errNote(src, msg, "mutable '{}' would allow illegal volatile pointers stored to type '{}'", .{
29709 try sema.errNote(src, msg, "mutable '{f}' would allow illegal volatile pointers stored to type '{f}'", .{
2970829710 pair.wanted.fmt(pt), pair.actual.fmt(pt),
2970929711 });
2971029712 }
......@@ -29712,12 +29714,12 @@ const InMemoryCoercionResult = union(enum) {
2971229714 },
2971329715 .ptr_bit_range => |bit_range| {
2971429716 if (bit_range.actual_host != bit_range.wanted_host) {
29715 try sema.errNote(src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{
29717 try sema.errNote(src, msg, "pointer host size '{d}' cannot cast into pointer host size '{d}'", .{
2971629718 bit_range.actual_host, bit_range.wanted_host,
2971729719 });
2971829720 }
2971929721 if (bit_range.actual_offset != bit_range.wanted_offset) {
29720 try sema.errNote(src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{
29722 try sema.errNote(src, msg, "pointer bit offset '{d}' cannot cast into pointer bit offset '{d}'", .{
2972129723 bit_range.actual_offset, bit_range.wanted_offset,
2972229724 });
2972329725 }
......@@ -29730,13 +29732,13 @@ const InMemoryCoercionResult = union(enum) {
2973029732 break;
2973129733 },
2973229734 .double_ptr_to_anyopaque => |pair| {
29733 try sema.errNote(src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{
29735 try sema.errNote(src, msg, "cannot implicitly cast double pointer '{f}' to anyopaque pointer '{f}'", .{
2973429736 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2973529737 });
2973629738 break;
2973729739 },
2973829740 .slice_to_anyopaque => |pair| {
29739 try sema.errNote(src, msg, "cannot implicitly cast slice '{}' to anyopaque pointer '{}'", .{
29741 try sema.errNote(src, msg, "cannot implicitly cast slice '{f}' to anyopaque pointer '{f}'", .{
2974029742 pair.actual.fmt(pt), pair.wanted.fmt(pt),
2974129743 });
2974229744 try sema.errNote(src, msg, "consider using '.ptr'", .{});
......@@ -30510,7 +30512,7 @@ fn coerceVarArgParam(
3051030512 const coerced_ty = sema.typeOf(coerced);
3051130513 if (!try sema.validateExternType(coerced_ty, .param_ty)) {
3051230514 const msg = msg: {
30513 const msg = try sema.errMsg(inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(pt)});
30515 const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)});
3051430516 errdefer msg.destroy(sema.gpa);
3051530517
3051630518 try sema.explainWhyTypeIsNotExtern(msg, inst_src, coerced_ty, .param_ty);
......@@ -30613,7 +30615,7 @@ fn storePtr2(
3061330615 // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer.
3061430616 if (try elem_ty.comptimeOnlySema(pt)) {
3061530617 return sema.failWithOwnedErrorMsg(block, msg: {
30616 const msg = try sema.errMsg(src, "cannot store comptime-only type '{}' at runtime", .{elem_ty.fmt(pt)});
30618 const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)});
3061730619 errdefer msg.destroy(sema.gpa);
3061830620 try sema.errNote(ptr_src, msg, "operation is runtime due to this pointer", .{});
3061930621 break :msg msg;
......@@ -30646,7 +30648,7 @@ fn storePtr2(
3064630648 });
3064730649 return;
3064830650 }
30649 return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{
30651 return sema.fail(block, ptr_src, "unable to determine vector element index of type '{f}'", .{
3065030652 ptr_ty.fmt(pt),
3065130653 });
3065230654 }
......@@ -30815,19 +30817,19 @@ fn storePtrVal(
3081530817 .{},
3081630818 ),
3081730819 .undef => return sema.failWithUseOfUndef(block, src),
30818 .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}),
30820 .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {f}", .{err_name.fmt(ip)}),
3081930821 .null_payload => return sema.fail(block, src, "attempt to use null value", .{}),
3082030822 .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}),
3082130823 .needed_well_defined => |ty| return sema.fail(
3082230824 block,
3082330825 src,
30824 "comptime dereference requires '{}' to have a well-defined layout",
30826 "comptime dereference requires '{f}' to have a well-defined layout",
3082530827 .{ty.fmt(pt)},
3082630828 ),
3082730829 .out_of_bounds => |ty| return sema.fail(
3082830830 block,
3082930831 src,
30830 "dereference of '{}' exceeds bounds of containing decl of type '{}'",
30832 "dereference of '{f}' exceeds bounds of containing decl of type '{f}'",
3083130833 .{ ptr_ty.fmt(pt), ty.fmt(pt) },
3083230834 ),
3083330835 .exceeds_host_size => return sema.fail(block, src, "bit-pointer target exceeds host size", .{}),
......@@ -30853,7 +30855,7 @@ fn bitCast(
3085330855 const old_bits = old_ty.bitSize(zcu);
3085430856
3085530857 if (old_bits != dest_bits) {
30856 return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{
30858 return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{f}' has {d} bits but source type '{f}' has {d} bits", .{
3085730859 dest_ty.fmt(pt),
3085830860 dest_bits,
3085930861 old_ty.fmt(pt),
......@@ -30971,7 +30973,7 @@ fn coerceCompatiblePtrs(
3097130973 const inst_ty = sema.typeOf(inst);
3097230974 if (try sema.resolveValue(inst)) |val| {
3097330975 if (!val.isUndef(zcu) and val.isNull(zcu) and !dest_ty.isAllowzeroPtr(zcu)) {
30974 return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(pt)});
30976 return sema.fail(block, inst_src, "null pointer casted to type '{f}'", .{dest_ty.fmt(pt)});
3097530977 }
3097630978 // The comptime Value representation is compatible with both types.
3097730979 return Air.internedToRef(
......@@ -31017,7 +31019,7 @@ fn coerceEnumToUnion(
3101731019
3101831020 const tag_ty = union_ty.unionTagType(zcu) orelse {
3101931021 const msg = msg: {
31020 const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{
31022 const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{
3102131023 union_ty.fmt(pt), inst_ty.fmt(pt),
3102231024 });
3102331025 errdefer msg.destroy(sema.gpa);
......@@ -31031,7 +31033,7 @@ fn coerceEnumToUnion(
3103131033 const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);
3103231034 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
3103331035 const field_index = union_ty.unionTagFieldIndex(val, pt.zcu) orelse {
31034 return sema.fail(block, inst_src, "union '{}' has no tag with value '{}'", .{
31036 return sema.fail(block, inst_src, "union '{f}' has no tag with value '{f}'", .{
3103531037 union_ty.fmt(pt), val.fmtValueSema(pt, sema),
3103631038 });
3103731039 };
......@@ -31045,7 +31047,7 @@ fn coerceEnumToUnion(
3104531047 errdefer msg.destroy(sema.gpa);
3104631048
3104731049 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
31048 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
31050 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
3104931051 field_name.fmt(ip),
3105031052 });
3105131053 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -31056,13 +31058,13 @@ fn coerceEnumToUnion(
3105631058 const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {
3105731059 const msg = msg: {
3105831060 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
31059 const msg = try sema.errMsg(inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{
31061 const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{
3106031062 inst_ty.fmt(pt), union_ty.fmt(pt),
3106131063 field_ty.fmt(pt), field_name.fmt(ip),
3106231064 });
3106331065 errdefer msg.destroy(sema.gpa);
3106431066
31065 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
31067 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
3106631068 field_name.fmt(ip),
3106731069 });
3106831070 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -31078,7 +31080,7 @@ fn coerceEnumToUnion(
3107831080
3107931081 if (tag_ty.isNonexhaustiveEnum(zcu)) {
3108031082 const msg = msg: {
31081 const msg = try sema.errMsg(inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{
31083 const msg = try sema.errMsg(inst_src, "runtime coercion to union '{f}' from non-exhaustive enum", .{
3108231084 union_ty.fmt(pt),
3108331085 });
3108431086 errdefer msg.destroy(sema.gpa);
......@@ -31097,7 +31099,7 @@ fn coerceEnumToUnion(
3109731099 if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .noreturn) {
3109831100 const err_msg = msg orelse try sema.errMsg(
3109931101 inst_src,
31100 "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field",
31102 "runtime coercion from enum '{f}' to union '{f}' which has a 'noreturn' field",
3110131103 .{ tag_ty.fmt(pt), union_ty.fmt(pt) },
3110231104 );
3110331105 msg = err_msg;
......@@ -31120,7 +31122,7 @@ fn coerceEnumToUnion(
3112031122 const msg = msg: {
3112131123 const msg = try sema.errMsg(
3112231124 inst_src,
31123 "runtime coercion from enum '{}' to union '{}' which has non-void fields",
31125 "runtime coercion from enum '{f}' to union '{f}' which has non-void fields",
3112431126 .{ tag_ty.fmt(pt), union_ty.fmt(pt) },
3112531127 );
3112631128 errdefer msg.destroy(sema.gpa);
......@@ -31129,7 +31131,7 @@ fn coerceEnumToUnion(
3112931131 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
3113031132 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
3113131133 if (!(try field_ty.hasRuntimeBitsSema(pt))) continue;
31132 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{
31134 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{
3113331135 field_name.fmt(ip),
3113431136 field_ty.fmt(pt),
3113531137 });
......@@ -31170,7 +31172,7 @@ fn coerceArrayLike(
3117031172 const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(zcu));
3117131173 if (dest_len != inst_len) {
3117231174 const msg = msg: {
31173 const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{
31175 const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{
3117431176 dest_ty.fmt(pt), inst_ty.fmt(pt),
3117531177 });
3117631178 errdefer msg.destroy(sema.gpa);
......@@ -31258,7 +31260,7 @@ fn coerceTupleToArray(
3125831260
3125931261 if (dest_len != inst_len) {
3126031262 const msg = msg: {
31261 const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{
31263 const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{
3126231264 dest_ty.fmt(pt), inst_ty.fmt(pt),
3126331265 });
3126431266 errdefer msg.destroy(sema.gpa);
......@@ -31734,10 +31736,10 @@ fn analyzeLoad(
3173431736 const ptr_ty = sema.typeOf(ptr);
3173531737 const elem_ty = switch (ptr_ty.zigTypeTag(zcu)) {
3173631738 .pointer => ptr_ty.childType(zcu),
31737 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(pt)}),
31739 else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}),
3173831740 };
3173931741 if (elem_ty.zigTypeTag(zcu) == .@"opaque") {
31740 return sema.fail(block, ptr_src, "cannot load opaque type '{}'", .{elem_ty.fmt(pt)});
31742 return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)});
3174131743 }
3174231744
3174331745 if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| {
......@@ -31758,7 +31760,7 @@ fn analyzeLoad(
3175831760 const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data;
3175931761 return block.addBinOp(.ptr_elem_val, bin_op.lhs, bin_op.rhs);
3176031762 }
31761 return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{
31763 return sema.fail(block, ptr_src, "unable to determine vector element index of type '{f}'", .{
3176231764 ptr_ty.fmt(pt),
3176331765 });
3176431766 }
......@@ -32046,7 +32048,7 @@ fn analyzeSlice(
3204632048 const ptr_ptr_ty = sema.typeOf(ptr_ptr);
3204732049 const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(zcu)) {
3204832050 .pointer => ptr_ptr_ty.childType(zcu),
32049 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(pt)}),
32051 else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ptr_ty.fmt(pt)}),
3205032052 };
3205132053
3205232054 var array_ty = ptr_ptr_child_ty;
......@@ -32095,7 +32097,7 @@ fn analyzeSlice(
3209532097 try sema.errNote(
3209632098 start_src,
3209732099 msg,
32098 "expected '{}', found '{}'",
32100 "expected '{f}', found '{f}'",
3209932101 .{
3210032102 Value.zero_comptime_int.fmtValueSema(pt, sema),
3210132103 start_value.fmtValueSema(pt, sema),
......@@ -32111,7 +32113,7 @@ fn analyzeSlice(
3211132113 try sema.errNote(
3211232114 end_src,
3211332115 msg,
32114 "expected '{}', found '{}'",
32116 "expected '{f}', found '{f}'",
3211532117 .{
3211632118 Value.one_comptime_int.fmtValueSema(pt, sema),
3211732119 end_value.fmtValueSema(pt, sema),
......@@ -32126,7 +32128,7 @@ fn analyzeSlice(
3212632128 return sema.fail(
3212732129 block,
3212832130 end_src,
32129 "end index {} out of bounds for slice of single-item pointer",
32131 "end index {f} out of bounds for slice of single-item pointer",
3213032132 .{end_value.fmtValueSema(pt, sema)},
3213132133 );
3213232134 }
......@@ -32173,7 +32175,7 @@ fn analyzeSlice(
3217332175 elem_ty = ptr_ptr_child_ty.childType(zcu);
3217432176 },
3217532177 },
32176 else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(pt)}),
32178 else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}),
3217732179 }
3217832180
3217932181 const ptr = if (slice_ty.isSlice(zcu))
......@@ -32220,7 +32222,7 @@ fn analyzeSlice(
3222032222 return sema.fail(
3222132223 block,
3222232224 end_src,
32223 "end index {} out of bounds for array of length {}{s}",
32225 "end index {f} out of bounds for array of length {f}{s}",
3222432226 .{
3222532227 end_val.fmtValueSema(pt, sema),
3222632228 len_val.fmtValueSema(pt, sema),
......@@ -32265,7 +32267,7 @@ fn analyzeSlice(
3226532267 return sema.fail(
3226632268 block,
3226732269 end_src,
32268 "end index {} out of bounds for slice of length {d}{s}",
32270 "end index {f} out of bounds for slice of length {d}{s}",
3226932271 .{
3227032272 end_val.fmtValueSema(pt, sema),
3227132273 try slice_val.sliceLen(pt),
......@@ -32324,7 +32326,7 @@ fn analyzeSlice(
3232432326 return sema.fail(
3232532327 block,
3232632328 start_src,
32327 "start index {} is larger than end index {}",
32329 "start index {f} is larger than end index {f}",
3232832330 .{
3232932331 start_val.fmtValueSema(pt, sema),
3233032332 end_val.fmtValueSema(pt, sema),
......@@ -32348,13 +32350,13 @@ fn analyzeSlice(
3234832350 .needed_well_defined => |ty| return sema.fail(
3234932351 block,
3235032352 src,
32351 "comptime dereference requires '{}' to have a well-defined layout",
32353 "comptime dereference requires '{f}' to have a well-defined layout",
3235232354 .{ty.fmt(pt)},
3235332355 ),
3235432356 .out_of_bounds => |ty| return sema.fail(
3235532357 block,
3235632358 end_src,
32357 "slice end index {d} exceeds bounds of containing decl of type '{}'",
32359 "slice end index {d} exceeds bounds of containing decl of type '{f}'",
3235832360 .{ end_int, ty.fmt(pt) },
3235932361 ),
3236032362 };
......@@ -32363,7 +32365,7 @@ fn analyzeSlice(
3236332365 const msg = msg: {
3236432366 const msg = try sema.errMsg(src, "value in memory does not match slice sentinel", .{});
3236532367 errdefer msg.destroy(sema.gpa);
32366 try sema.errNote(src, msg, "expected '{}', found '{}'", .{
32368 try sema.errNote(src, msg, "expected '{f}', found '{f}'", .{
3236732369 expected_sentinel.fmtValueSema(pt, sema),
3236832370 actual_sentinel.fmtValueSema(pt, sema),
3236932371 });
......@@ -33251,7 +33253,7 @@ const PeerResolveResult = union(enum) {
3325133253 };
3325233254 },
3325333255 .field_error => |field_error| {
33254 const fmt = "struct field '{}' has conflicting types";
33256 const fmt = "struct field '{f}' has conflicting types";
3325533257 const args = .{field_error.field_name.fmt(&pt.zcu.intern_pool)};
3325633258 if (opt_msg) |msg| {
3325733259 try sema.errNote(src, msg, fmt, args);
......@@ -33282,7 +33284,7 @@ const PeerResolveResult = union(enum) {
3328233284 candidate_srcs.resolve(block, conflict_idx[1]),
3328333285 };
3328433286
33285 const fmt = "incompatible types: '{}' and '{}'";
33287 const fmt = "incompatible types: '{f}' and '{f}'";
3328633288 const args = .{
3328733289 conflict_tys[0].fmt(pt),
3328833290 conflict_tys[1].fmt(pt),
......@@ -33296,8 +33298,8 @@ const PeerResolveResult = union(enum) {
3329633298 break :msg msg;
3329733299 };
3329833300
33299 if (conflict_srcs[0]) |src_loc| try sema.errNote(src_loc, msg, "type '{}' here", .{conflict_tys[0].fmt(pt)});
33300 if (conflict_srcs[1]) |src_loc| try sema.errNote(src_loc, msg, "type '{}' here", .{conflict_tys[1].fmt(pt)});
33301 if (conflict_srcs[0]) |src_loc| try sema.errNote(src_loc, msg, "type '{f}' here", .{conflict_tys[0].fmt(pt)});
33302 if (conflict_srcs[1]) |src_loc| try sema.errNote(src_loc, msg, "type '{f}' here", .{conflict_tys[1].fmt(pt)});
3330133303
3330233304 // No child error
3330333305 break;
......@@ -34609,7 +34611,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
3460934611 if (struct_type.setLayoutWip(ip)) {
3461034612 const msg = try sema.errMsg(
3461134613 ty.srcLoc(zcu),
34612 "struct '{}' depends on itself",
34614 "struct '{f}' depends on itself",
3461334615 .{ty.fmt(pt)},
3461434616 );
3461534617 return sema.failWithOwnedErrorMsg(null, msg);
......@@ -34828,13 +34830,13 @@ fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_
3482834830 const zcu = pt.zcu;
3482934831
3483034832 if (!backing_int_ty.isInt(zcu)) {
34831 return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(pt)});
34833 return sema.fail(block, src, "expected backing integer type, found '{f}'", .{backing_int_ty.fmt(pt)});
3483234834 }
3483334835 if (backing_int_ty.bitSize(zcu) != fields_bit_sum) {
3483434836 return sema.fail(
3483534837 block,
3483634838 src,
34837 "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}",
34839 "backing integer type '{f}' has bit size {d} but the struct fields have a total bit size of {d}",
3483834840 .{ backing_int_ty.fmt(pt), backing_int_ty.bitSize(zcu), fields_bit_sum },
3483934841 );
3484034842 }
......@@ -34844,7 +34846,7 @@ fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
3484434846 const pt = sema.pt;
3484534847 if (!ty.isIndexable(pt.zcu)) {
3484634848 const msg = msg: {
34847 const msg = try sema.errMsg(src, "type '{}' does not support indexing", .{ty.fmt(pt)});
34849 const msg = try sema.errMsg(src, "type '{f}' does not support indexing", .{ty.fmt(pt)});
3484834850 errdefer msg.destroy(sema.gpa);
3484934851 try sema.errNote(src, msg, "operand must be an array, slice, tuple, or vector", .{});
3485034852 break :msg msg;
......@@ -34868,7 +34870,7 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
3486834870 }
3486934871 }
3487034872 const msg = msg: {
34871 const msg = try sema.errMsg(src, "type '{}' is not an indexable pointer", .{ty.fmt(pt)});
34873 const msg = try sema.errMsg(src, "type '{f}' is not an indexable pointer", .{ty.fmt(pt)});
3487234874 errdefer msg.destroy(sema.gpa);
3487334875 try sema.errNote(src, msg, "operand must be a slice, a many pointer or a pointer to an array", .{});
3487434876 break :msg msg;
......@@ -34936,7 +34938,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
3493634938 .field_types_wip, .layout_wip => {
3493734939 const msg = try sema.errMsg(
3493834940 ty.srcLoc(pt.zcu),
34939 "union '{}' depends on itself",
34941 "union '{f}' depends on itself",
3494034942 .{ty.fmt(pt)},
3494134943 );
3494234944 return sema.failWithOwnedErrorMsg(null, msg);
......@@ -35124,7 +35126,7 @@ pub fn resolveStructFieldTypes(
3512435126 if (struct_type.setFieldTypesWip(ip)) {
3512535127 const msg = try sema.errMsg(
3512635128 Type.fromInterned(ty).srcLoc(zcu),
35127 "struct '{}' depends on itself",
35129 "struct '{f}' depends on itself",
3512835130 .{Type.fromInterned(ty).fmt(pt)},
3512935131 );
3513035132 return sema.failWithOwnedErrorMsg(null, msg);
......@@ -35153,7 +35155,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
3515335155 if (struct_type.setInitsWip(ip)) {
3515435156 const msg = try sema.errMsg(
3515535157 ty.srcLoc(zcu),
35156 "struct '{}' depends on itself",
35158 "struct '{f}' depends on itself",
3515735159 .{ty.fmt(pt)},
3515835160 );
3515935161 return sema.failWithOwnedErrorMsg(null, msg);
......@@ -35177,11 +35179,7 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load
3517735179 switch (union_type.flagsUnordered(ip).status) {
3517835180 .none => {},
3517935181 .field_types_wip => {
35180 const msg = try sema.errMsg(
35181 ty.srcLoc(zcu),
35182 "union '{}' depends on itself",
35183 .{ty.fmt(pt)},
35184 );
35182 const msg = try sema.errMsg(ty.srcLoc(zcu), "union '{f}' depends on itself", .{ty.fmt(pt)});
3518535183 return sema.failWithOwnedErrorMsg(null, msg);
3518635184 },
3518735185 .have_field_types,
......@@ -35549,7 +35547,7 @@ fn structFields(
3554935547 switch (struct_type.layout) {
3555035548 .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) {
3555135549 const msg = msg: {
35552 const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)});
35550 const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
3555335551 errdefer msg.destroy(sema.gpa);
3555435552
3555535553 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field);
......@@ -35561,7 +35559,7 @@ fn structFields(
3556135559 },
3556235560 .@"packed" => if (!try sema.validatePackedType(field_ty)) {
3556335561 const msg = msg: {
35564 const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)});
35562 const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
3556535563 errdefer msg.destroy(sema.gpa);
3556635564
3556735565 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty);
......@@ -35808,7 +35806,7 @@ fn unionFields(
3580835806 // The provided type is an integer type and we must construct the enum tag type here.
3580935807 int_tag_ty = provided_ty;
3581035808 if (int_tag_ty.zigTypeTag(zcu) != .int and int_tag_ty.zigTypeTag(zcu) != .comptime_int) {
35811 return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(pt)});
35809 return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{f}'", .{int_tag_ty.fmt(pt)});
3581235810 }
3581335811
3581435812 if (fields_len > 0) {
......@@ -35817,7 +35815,7 @@ fn unionFields(
3581735815 const msg = msg: {
3581835816 const msg = try sema.errMsg(tag_ty_src, "specified integer tag type cannot represent every field", .{});
3581935817 errdefer msg.destroy(sema.gpa);
35820 try sema.errNote(tag_ty_src, msg, "type '{}' cannot fit values in range 0...{d}", .{
35818 try sema.errNote(tag_ty_src, msg, "type '{f}' cannot fit values in range 0...{d}", .{
3582135819 int_tag_ty.fmt(pt),
3582235820 fields_len - 1,
3582335821 });
......@@ -35832,7 +35830,7 @@ fn unionFields(
3583235830 // The provided type is the enum tag type.
3583335831 const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) {
3583435832 .enum_type => ip.loadEnumType(provided_ty.toIntern()),
35835 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(pt)}),
35833 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{f}'", .{provided_ty.fmt(pt)}),
3583635834 };
3583735835 union_type.setTagType(ip, provided_ty.toIntern());
3583835836 // The fields of the union must match the enum exactly.
......@@ -35929,7 +35927,7 @@ fn unionFields(
3592935927 if (result.overflow) return sema.fail(
3593035928 &block_scope,
3593135929 value_src,
35932 "enumeration value '{}' too large for type '{}'",
35930 "enumeration value '{f}' too large for type '{f}'",
3593335931 .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) },
3593435932 );
3593535933 last_tag_val = result.val;
......@@ -35947,7 +35945,7 @@ fn unionFields(
3594735945 const msg = msg: {
3594835946 const msg = try sema.errMsg(
3594935947 value_src,
35950 "enum tag value {} already taken",
35948 "enum tag value {f} already taken",
3595135949 .{enum_tag_val.fmtValueSema(pt, sema)},
3595235950 );
3595335951 errdefer msg.destroy(gpa);
......@@ -35975,7 +35973,7 @@ fn unionFields(
3597535973 const tag_ty = union_type.tagTypeUnordered(ip);
3597635974 const tag_info = ip.loadEnumType(tag_ty);
3597735975 const enum_index = tag_info.nameIndex(ip, field_name) orelse {
35978 return sema.fail(&block_scope, name_src, "no field named '{}' in enum '{}'", .{
35976 return sema.fail(&block_scope, name_src, "no field named '{f}' in enum '{f}'", .{
3597935977 field_name.fmt(ip), Type.fromInterned(tag_ty).fmt(pt),
3598035978 });
3598135979 };
......@@ -35992,7 +35990,7 @@ fn unionFields(
3599235990 .base_node_inst = Type.fromInterned(tag_ty).typeDeclInstAllowGeneratedTag(zcu).?,
3599335991 .offset = .{ .container_field_name = enum_index },
3599435992 };
35995 const msg = try sema.errMsg(name_src, "union field '{}' ordered differently than corresponding enum field", .{
35993 const msg = try sema.errMsg(name_src, "union field '{f}' ordered differently than corresponding enum field", .{
3599635994 field_name.fmt(ip),
3599735995 });
3599835996 errdefer msg.destroy(sema.gpa);
......@@ -36018,7 +36016,7 @@ fn unionFields(
3601836016 !try sema.validateExternType(field_ty, .union_field))
3601936017 {
3602036018 const msg = msg: {
36021 const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)});
36019 const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
3602236020 errdefer msg.destroy(sema.gpa);
3602336021
3602436022 try sema.explainWhyTypeIsNotExtern(msg, type_src, field_ty, .union_field);
......@@ -36029,7 +36027,7 @@ fn unionFields(
3602936027 return sema.failWithOwnedErrorMsg(&block_scope, msg);
3603036028 } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) {
3603136029 const msg = msg: {
36032 const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)});
36030 const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
3603336031 errdefer msg.destroy(sema.gpa);
3603436032
3603536033 try sema.explainWhyTypeIsNotPacked(msg, type_src, field_ty);
......@@ -36065,7 +36063,7 @@ fn unionFields(
3606536063
3606636064 for (tag_info.names.get(ip), 0..) |field_name, field_index| {
3606736065 if (explicit_tags_seen[field_index]) continue;
36068 try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{}' missing, declared here", .{
36066 try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{f}' missing, declared here", .{
3606936067 field_name.fmt(ip),
3607036068 });
3607136069 }
......@@ -36101,7 +36099,7 @@ fn generateUnionTagTypeNumbered(
3610136099 const name = try ip.getOrPutStringFmt(
3610236100 gpa,
3610336101 pt.tid,
36104 "@typeInfo({}).@\"union\".tag_type.?",
36102 "@typeInfo({f}).@\"union\".tag_type.?",
3610536103 .{union_name.fmt(ip)},
3610636104 .no_embedded_nulls,
3610736105 );
......@@ -36137,7 +36135,7 @@ fn generateUnionTagTypeSimple(
3613736135 const name = try ip.getOrPutStringFmt(
3613836136 gpa,
3613936137 pt.tid,
36140 "@typeInfo({}).@\"union\".tag_type.?",
36138 "@typeInfo({f}).@\"union\".tag_type.?",
3614136139 .{union_name.fmt(ip)},
3614236140 .no_embedded_nulls,
3614336141 );
......@@ -36671,13 +36669,13 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
3667136669 .needed_well_defined => |ty| return sema.fail(
3667236670 block,
3667336671 src,
36674 "comptime dereference requires '{}' to have a well-defined layout",
36672 "comptime dereference requires '{f}' to have a well-defined layout",
3667536673 .{ty.fmt(pt)},
3667636674 ),
3667736675 .out_of_bounds => |ty| return sema.fail(
3667836676 block,
3667936677 src,
36680 "dereference of '{}' exceeds bounds of containing decl of type '{}'",
36678 "dereference of '{f}' exceeds bounds of containing decl of type '{f}'",
3668136679 .{ ptr_ty.fmt(pt), ty.fmt(pt) },
3668236680 ),
3668336681 }
......@@ -36697,7 +36695,7 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value
3669736695 .success => |mv| return .{ .val = try mv.intern(pt, sema.arena) },
3669836696 .runtime_load => return .runtime_load,
3669936697 .undef => return sema.failWithUseOfUndef(block, src),
36700 .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}),
36698 .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {f}", .{err_name.fmt(ip)}),
3670136699 .null_payload => return sema.fail(block, src, "attempt to use null value", .{}),
3670236700 .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}),
3670336701 .needed_well_defined => |ty| return .{ .needed_well_defined = ty },
......@@ -36822,12 +36820,12 @@ fn intFromFloatScalar(
3682236820
3682336821 const float = val.toFloat(f128, zcu);
3682436822 if (std.math.isNan(float)) {
36825 return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{
36823 return sema.fail(block, src, "float value NaN cannot be stored in integer type '{f}'", .{
3682636824 int_ty.fmt(pt),
3682736825 });
3682836826 }
3682936827 if (std.math.isInf(float)) {
36830 return sema.fail(block, src, "float value Inf cannot be stored in integer type '{}'", .{
36828 return sema.fail(block, src, "float value Inf cannot be stored in integer type '{f}'", .{
3683136829 int_ty.fmt(pt),
3683236830 });
3683336831 }
......@@ -36842,7 +36840,7 @@ fn intFromFloatScalar(
3684236840 .exact => return sema.fail(
3684336841 block,
3684436842 src,
36845 "fractional component prevents float value '{}' from coercion to type '{}'",
36843 "fractional component prevents float value '{f}' from coercion to type '{f}'",
3684636844 .{ val.fmtValueSema(pt, sema), int_ty.fmt(pt) },
3684736845 ),
3684836846 .truncate => {},
......@@ -36854,7 +36852,7 @@ fn intFromFloatScalar(
3685436852
3685536853 const int_info = int_ty.intInfo(zcu);
3685636854 if (!big_int.toConst().fitsInTwosComp(int_info.signedness, int_info.bits)) {
36857 return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{
36855 return sema.fail(block, src, "float value '{f}' cannot be stored in integer type '{f}'", .{
3685836856 val.fmtValueSema(pt, sema), int_ty.fmt(pt),
3685936857 });
3686036858 }
......@@ -37175,7 +37173,14 @@ fn explainWhyValueContainsReferenceToComptimeVar(sema: *Sema, msg: *Zcu.ErrorMsg
3717537173 }
3717637174}
3717737175
37178fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, val: Value, intermediate_value_count: u32, start_value_name: InternPool.NullTerminatedString) Allocator.Error!union(enum) {
37176fn notePathToComptimeAllocPtr(
37177 sema: *Sema,
37178 msg: *Zcu.ErrorMsg,
37179 src: LazySrcLoc,
37180 val: Value,
37181 intermediate_value_count: u32,
37182 start_value_name: InternPool.NullTerminatedString,
37183) Allocator.Error!union(enum) {
3717937184 done,
3718037185 new_val: Value,
3718137186} {
......@@ -37186,9 +37191,9 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc,
3718637191
3718737192 var first_path: std.ArrayListUnmanaged(u8) = .empty;
3718837193 if (intermediate_value_count == 0) {
37189 try first_path.writer(arena).print("{i}", .{start_value_name.fmt(ip)});
37194 try first_path.print(arena, "{f}", .{start_value_name.fmt(ip)});
3719037195 } else {
37191 try first_path.writer(arena).print("v{}", .{intermediate_value_count - 1});
37196 try first_path.print(arena, "v{d}", .{intermediate_value_count - 1});
3719237197 }
3719337198
3719437199 const comptime_ptr = try sema.notePathToComptimeAllocPtrInner(val, &first_path);
......@@ -37213,30 +37218,26 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc,
3721337218 error.AnalysisFail => unreachable,
3721437219 };
3721537220
37216 var second_path: std.ArrayListUnmanaged(u8) = .empty;
37221 var second_path_aw: std.io.Writer.Allocating = .init(arena);
37222 defer second_path_aw.deinit();
3721737223 const inter_name = try std.fmt.allocPrint(arena, "v{d}", .{intermediate_value_count});
3721837224 const deriv_start = @import("print_value.zig").printPtrDerivation(
3721937225 derivation,
37220 second_path.writer(arena),
37226 &second_path_aw.writer,
3722137227 pt,
3722237228 .lvalue,
3722337229 .{ .str = inter_name },
3722437230 20,
37225 ) catch |err| switch (err) {
37226 error.OutOfMemory => |e| return e,
37227 error.AnalysisFail => unreachable,
37228 error.ComptimeReturn => unreachable,
37229 error.ComptimeBreak => unreachable,
37230 };
37231 ) catch return error.OutOfMemory;
3723137232
3723237233 switch (deriv_start) {
3723337234 .int, .nav_ptr => unreachable,
3723437235 .uav_ptr => |uav| {
37235 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items });
37236 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() });
3723637237 return .{ .new_val = .fromInterned(uav.val) };
3723737238 },
3723837239 .comptime_alloc_ptr => |cta_info| {
37239 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items });
37240 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() });
3724037241 const cta = sema.getComptimeAlloc(cta_info.idx);
3724137242 if (cta.is_const) {
3724237243 return .{ .new_val = cta_info.val };
......@@ -37246,7 +37247,7 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc,
3724637247 }
3724737248 },
3724837249 .comptime_field_ptr => {
37249 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items });
37250 try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() });
3725037251 try sema.errNote(src, msg, "'{s}' is a comptime field", .{inter_name});
3725137252 return .done;
3725237253 },
......@@ -37286,7 +37287,7 @@ fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayList
3728637287 const backing_enum = union_ty.unionTagTypeHypothetical(zcu);
3728737288 const field_idx = backing_enum.enumTagFieldIndex(.fromInterned(un.tag), zcu).?;
3728837289 const field_name = backing_enum.enumFieldName(field_idx, zcu);
37289 try path.writer(arena).print(".{i}", .{field_name.fmt(ip)});
37290 try path.print(arena, ".{f}", .{field_name.fmt(ip)});
3729037291 return sema.notePathToComptimeAllocPtrInner(.fromInterned(un.val), path);
3729137292 },
3729237293 .aggregate => |agg| {
......@@ -37301,17 +37302,17 @@ fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayList
3730137302 };
3730237303 const agg_ty: Type = .fromInterned(agg.ty);
3730337304 switch (agg_ty.zigTypeTag(zcu)) {
37304 .array, .vector => try path.writer(arena).print("[{d}]", .{elem_idx}),
37305 .array, .vector => try path.print(arena, "[{d}]", .{elem_idx}),
3730537306 .pointer => switch (elem_idx) {
3730637307 Value.slice_ptr_index => try path.appendSlice(arena, ".ptr"),
3730737308 Value.slice_len_index => try path.appendSlice(arena, ".len"),
3730837309 else => unreachable,
3730937310 },
3731037311 .@"struct" => if (agg_ty.isTuple(zcu)) {
37311 try path.writer(arena).print("[{d}]", .{elem_idx});
37312 try path.print(arena, "[{d}]", .{elem_idx});
3731237313 } else {
3731337314 const name = agg_ty.structFieldName(elem_idx, zcu).unwrap().?;
37314 try path.writer(arena).print(".{i}", .{name.fmt(ip)});
37315 try path.print(arena, ".{f}", .{name.fmt(ip)});
3731537316 },
3731637317 else => unreachable,
3731737318 }
......@@ -37588,7 +37589,7 @@ fn resolveDeclaredEnumInner(
3758837589 if (tag_type_ref != .none) {
3758937590 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
3759037591 if (ty.zigTypeTag(zcu) != .int and ty.zigTypeTag(zcu) != .comptime_int) {
37591 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)});
37592 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{f}'", .{ty.fmt(pt)});
3759237593 }
3759337594 break :ty ty;
3759437595 } else if (fields_len == 0) {
......@@ -37642,7 +37643,7 @@ fn resolveDeclaredEnumInner(
3764237643 .offset = .{ .container_field_value = conflict.prev_field_idx },
3764337644 };
3764437645 const msg = msg: {
37645 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
37646 const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
3764637647 errdefer msg.destroy(gpa);
3764737648 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
3764837649 break :msg msg;
......@@ -37665,7 +37666,7 @@ fn resolveDeclaredEnumInner(
3766537666 .offset = .{ .container_field_value = conflict.prev_field_idx },
3766637667 };
3766737668 const msg = msg: {
37668 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
37669 const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
3766937670 errdefer msg.destroy(gpa);
3767037671 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
3767137672 break :msg msg;
......@@ -37682,7 +37683,7 @@ fn resolveDeclaredEnumInner(
3768237683 };
3768337684
3768437685 if (tag_overflow) {
37685 const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{
37686 const msg = try sema.errMsg(value_src, "enumeration value '{f}' too large for type '{f}'", .{
3768637687 last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt),
3768737688 });
3768837689 return sema.failWithOwnedErrorMsg(block, msg);
src/Sema/LowerZon.zig+17-21
......@@ -338,7 +338,7 @@ fn failUnsupportedResultType(
338338 const gpa = sema.gpa;
339339 const pt = sema.pt;
340340 return sema.failWithOwnedErrorMsg(self.block, msg: {
341 const msg = try sema.errMsg(self.import_loc, "type '{}' is not available in ZON", .{ty.fmt(pt)});
341 const msg = try sema.errMsg(self.import_loc, "type '{f}' is not available in ZON", .{ty.fmt(pt)});
342342 errdefer msg.destroy(gpa);
343343 if (opt_note) |n| try sema.errNote(self.import_loc, msg, "{s}", .{n});
344344 break :msg msg;
......@@ -360,11 +360,7 @@ fn fail(
360360fn lowerExprKnownResTy(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) CompileError!InternPool.Index {
361361 const pt = self.sema.pt;
362362 return self.lowerExprKnownResTyInner(node, res_ty) catch |err| switch (err) {
363 error.WrongType => return self.fail(
364 node,
365 "expected type '{}'",
366 .{res_ty.fmt(pt)},
367 ),
363 error.WrongType => return self.fail(node, "expected type '{f}'", .{res_ty.fmt(pt)}),
368364 else => |e| return e,
369365 };
370366}
......@@ -428,7 +424,7 @@ fn lowerExprKnownResTyInner(
428424 .frame,
429425 .@"anyframe",
430426 .void,
431 => return self.fail(node, "type '{}' not available in ZON", .{res_ty.fmt(pt)}),
427 => return self.fail(node, "type '{f}' not available in ZON", .{res_ty.fmt(pt)}),
432428 }
433429}
434430
......@@ -458,7 +454,7 @@ fn lowerInt(
458454 // If lhs is unsigned and rhs is less than 0, we're out of bounds
459455 if (lhs_info.signedness == .unsigned and rhs < 0) return self.fail(
460456 node,
461 "type '{}' cannot represent integer value '{}'",
457 "type '{f}' cannot represent integer value '{d}'",
462458 .{ res_ty.fmt(self.sema.pt), rhs },
463459 );
464460
......@@ -478,7 +474,7 @@ fn lowerInt(
478474 if (rhs < min_int or rhs > max_int) {
479475 return self.fail(
480476 node,
481 "type '{}' cannot represent integer value '{}'",
477 "type '{f}' cannot represent integer value '{d}'",
482478 .{ res_ty.fmt(self.sema.pt), rhs },
483479 );
484480 }
......@@ -496,7 +492,7 @@ fn lowerInt(
496492 if (!val.fitsInTwosComp(int_info.signedness, int_info.bits)) {
497493 return self.fail(
498494 node,
499 "type '{}' cannot represent integer value '{}'",
495 "type '{f}' cannot represent integer value '{d}'",
500496 .{ res_ty.fmt(self.sema.pt), val },
501497 );
502498 }
......@@ -517,7 +513,7 @@ fn lowerInt(
517513 switch (big_int.setFloat(val, .trunc)) {
518514 .inexact => return self.fail(
519515 node,
520 "fractional component prevents float value '{}' from coercion to type '{}'",
516 "fractional component prevents float value '{d}' from coercion to type '{f}'",
521517 .{ val, res_ty.fmt(self.sema.pt) },
522518 ),
523519 .exact => {},
......@@ -528,8 +524,8 @@ fn lowerInt(
528524 if (!big_int.toConst().fitsInTwosComp(int_info.signedness, int_info.bits)) {
529525 return self.fail(
530526 node,
531 "type '{}' cannot represent integer value '{}'",
532 .{ val, res_ty.fmt(self.sema.pt) },
527 "type '{f}' cannot represent integer value '{d}'",
528 .{ res_ty.fmt(self.sema.pt), val },
533529 );
534530 }
535531
......@@ -550,7 +546,7 @@ fn lowerInt(
550546 if (val >= out_of_range) {
551547 return self.fail(
552548 node,
553 "type '{}' cannot represent integer value '{}'",
549 "type '{f}' cannot represent integer value '{d}'",
554550 .{ res_ty.fmt(self.sema.pt), val },
555551 );
556552 }
......@@ -584,7 +580,7 @@ fn lowerFloat(
584580 .pos_inf => b: {
585581 if (res_ty.toIntern() == .comptime_float_type) return self.fail(
586582 node,
587 "expected type '{}'",
583 "expected type '{f}'",
588584 .{res_ty.fmt(self.sema.pt)},
589585 );
590586 break :b try self.sema.pt.floatValue(res_ty, std.math.inf(f128));
......@@ -592,7 +588,7 @@ fn lowerFloat(
592588 .neg_inf => b: {
593589 if (res_ty.toIntern() == .comptime_float_type) return self.fail(
594590 node,
595 "expected type '{}'",
591 "expected type '{f}'",
596592 .{res_ty.fmt(self.sema.pt)},
597593 );
598594 break :b try self.sema.pt.floatValue(res_ty, -std.math.inf(f128));
......@@ -600,7 +596,7 @@ fn lowerFloat(
600596 .nan => b: {
601597 if (res_ty.toIntern() == .comptime_float_type) return self.fail(
602598 node,
603 "expected type '{}'",
599 "expected type '{f}'",
604600 .{res_ty.fmt(self.sema.pt)},
605601 );
606602 break :b try self.sema.pt.floatValue(res_ty, std.math.nan(f128));
......@@ -661,7 +657,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I
661657 const field_index = res_ty.enumFieldIndex(field_name_interned, self.sema.pt.zcu) orelse {
662658 return self.fail(
663659 node,
664 "enum {} has no member named '{}'",
660 "enum {f} has no member named '{f}'",
665661 .{
666662 res_ty.fmt(self.sema.pt),
667663 std.zig.fmtId(field_name.get(self.file.zoir.?)),
......@@ -795,7 +791,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
795791 const field_node = fields.vals.at(@intCast(i));
796792
797793 const name_index = struct_info.nameIndex(ip, field_name) orelse {
798 return self.fail(field_node, "unexpected field '{}'", .{field_name.fmt(ip)});
794 return self.fail(field_node, "unexpected field '{f}'", .{field_name.fmt(ip)});
799795 };
800796
801797 const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]);
......@@ -816,7 +812,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
816812
817813 const field_names = struct_info.field_names.get(ip);
818814 for (field_values, field_names) |*value, name| {
819 if (value.* == .none) return self.fail(node, "missing field '{}'", .{name.fmt(ip)});
815 if (value.* == .none) return self.fail(node, "missing field '{f}'", .{name.fmt(ip)});
820816 }
821817
822818 return self.sema.pt.intern(.{ .aggregate = .{
......@@ -934,7 +930,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
934930 .struct_literal => b: {
935931 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
936932 .struct_literal => |fields| fields,
937 else => return self.fail(node, "expected type '{}'", .{res_ty.fmt(self.sema.pt)}),
933 else => return self.fail(node, "expected type '{f}'", .{res_ty.fmt(self.sema.pt)}),
938934 };
939935 if (fields.names.len != 1) {
940936 return error.WrongType;
src/Type.zig+23-37
......@@ -121,15 +121,13 @@ pub fn eql(a: Type, b: Type, zcu: *const Zcu) bool {
121121 return a.toIntern() == b.toIntern();
122122}
123123
124pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
124pub fn format(ty: Type, writer: *std.io.Writer) !void {
125125 _ = ty;
126 _ = unused_fmt_string;
127 _ = options;
128126 _ = writer;
129127 @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
130128}
131129
132pub const Formatter = std.fmt.Formatter(format2);
130pub const Formatter = std.fmt.Formatter(Format, Format.default);
133131
134132pub fn fmt(ty: Type, pt: Zcu.PerThread) Formatter {
135133 return .{ .data = .{
......@@ -138,42 +136,28 @@ pub fn fmt(ty: Type, pt: Zcu.PerThread) Formatter {
138136 } };
139137}
140138
141const FormatContext = struct {
139const Format = struct {
142140 ty: Type,
143141 pt: Zcu.PerThread,
144};
145142
146fn format2(
147 ctx: FormatContext,
148 comptime unused_format_string: []const u8,
149 options: std.fmt.FormatOptions,
150 writer: anytype,
151) !void {
152 comptime assert(unused_format_string.len == 0);
153 _ = options;
154 return print(ctx.ty, writer, ctx.pt);
155}
143 fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
144 return print(f.ty, writer, f.pt);
145 }
146};
156147
157pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) {
148pub fn fmtDebug(ty: Type) std.fmt.Formatter(Type, dump) {
158149 return .{ .data = ty };
159150}
160151
161152/// This is a debug function. In order to print types in a meaningful way
162153/// we also need access to the module.
163pub fn dump(
164 start_type: Type,
165 comptime unused_format_string: []const u8,
166 options: std.fmt.FormatOptions,
167 writer: anytype,
168) @TypeOf(writer).Error!void {
169 _ = options;
170 comptime assert(unused_format_string.len == 0);
154pub fn dump(start_type: Type, writer: *std.io.Writer) std.io.Writer.Error!void {
171155 return writer.print("{any}", .{start_type.ip_index});
172156}
173157
174158/// Prints a name suitable for `@typeName`.
175159/// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels.
176pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error!void {
160pub fn print(ty: Type, writer: *std.io.Writer, pt: Zcu.PerThread) std.io.Writer.Error!void {
177161 const zcu = pt.zcu;
178162 const ip = &zcu.intern_pool;
179163 switch (ip.indexToKey(ty.toIntern())) {
......@@ -190,8 +174,8 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
190174
191175 if (info.sentinel != .none) switch (info.flags.size) {
192176 .one, .c => unreachable,
193 .many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(pt)}),
194 .slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(pt)}),
177 .many => try writer.print("[*:{f}]", .{Value.fromInterned(info.sentinel).fmtValue(pt)}),
178 .slice => try writer.print("[:{f}]", .{Value.fromInterned(info.sentinel).fmtValue(pt)}),
195179 } else switch (info.flags.size) {
196180 .one => try writer.writeAll("*"),
197181 .many => try writer.writeAll("[*]"),
......@@ -235,7 +219,7 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
235219 try writer.print("[{d}]", .{array_type.len});
236220 try print(Type.fromInterned(array_type.child), writer, pt);
237221 } else {
238 try writer.print("[{d}:{}]", .{
222 try writer.print("[{d}:{f}]", .{
239223 array_type.len,
240224 Value.fromInterned(array_type.sentinel).fmtValue(pt),
241225 });
......@@ -265,7 +249,7 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
265249 },
266250 .inferred_error_set_type => |func_index| {
267251 const func_nav = ip.getNav(zcu.funcInfo(func_index).owner_nav);
268 try writer.print("@typeInfo(@typeInfo(@TypeOf({})).@\"fn\".return_type.?).error_union.error_set", .{
252 try writer.print("@typeInfo(@typeInfo(@TypeOf({f})).@\"fn\".return_type.?).error_union.error_set", .{
269253 func_nav.fqn.fmt(ip),
270254 });
271255 },
......@@ -274,7 +258,7 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
274258 try writer.writeAll("error{");
275259 for (names.get(ip), 0..) |name, i| {
276260 if (i != 0) try writer.writeByte(',');
277 try writer.print("{}", .{name.fmt(ip)});
261 try writer.print("{f}", .{name.fmt(ip)});
278262 }
279263 try writer.writeAll("}");
280264 },
......@@ -317,7 +301,7 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
317301 },
318302 .struct_type => {
319303 const name = ip.loadStructType(ty.toIntern()).name;
320 try writer.print("{}", .{name.fmt(ip)});
304 try writer.print("{f}", .{name.fmt(ip)});
321305 },
322306 .tuple_type => |tuple| {
323307 if (tuple.types.len == 0) {
......@@ -328,22 +312,22 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
328312 try writer.writeAll(if (i == 0) " " else ", ");
329313 if (val != .none) try writer.writeAll("comptime ");
330314 try print(Type.fromInterned(field_ty), writer, pt);
331 if (val != .none) try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(pt)});
315 if (val != .none) try writer.print(" = {f}", .{Value.fromInterned(val).fmtValue(pt)});
332316 }
333317 try writer.writeAll(" }");
334318 },
335319
336320 .union_type => {
337321 const name = ip.loadUnionType(ty.toIntern()).name;
338 try writer.print("{}", .{name.fmt(ip)});
322 try writer.print("{f}", .{name.fmt(ip)});
339323 },
340324 .opaque_type => {
341325 const name = ip.loadOpaqueType(ty.toIntern()).name;
342 try writer.print("{}", .{name.fmt(ip)});
326 try writer.print("{f}", .{name.fmt(ip)});
343327 },
344328 .enum_type => {
345329 const name = ip.loadEnumType(ty.toIntern()).name;
346 try writer.print("{}", .{name.fmt(ip)});
330 try writer.print("{f}", .{name.fmt(ip)});
347331 },
348332 .func_type => |fn_info| {
349333 if (fn_info.is_noinline) {
......@@ -382,7 +366,9 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error
382366 }
383367 }
384368 switch (fn_info.cc) {
385 .auto, .async, .naked, .@"inline" => try writer.print("callconv(.{}) ", .{std.zig.fmtId(@tagName(fn_info.cc))}),
369 .auto, .async, .naked, .@"inline" => try writer.print("callconv(.{f}) ", .{
370 std.zig.fmtId(@tagName(fn_info.cc)),
371 }),
386372 else => try writer.print("callconv({any}) ", .{fn_info.cc}),
387373 }
388374 }
src/Value.zig+7-15
......@@ -15,31 +15,23 @@ const Value = @This();
1515
1616ip_index: InternPool.Index,
1717
18pub fn format(val: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
18pub fn format(val: Value, writer: *std.io.Writer) !void {
1919 _ = val;
20 _ = fmt;
21 _ = options;
2220 _ = writer;
2321 @compileError("do not use format values directly; use either fmtDebug or fmtValue");
2422}
2523
2624/// This is a debug function. In order to print values in a meaningful way
2725/// we also need access to the type.
28pub fn dump(
29 start_val: Value,
30 comptime fmt: []const u8,
31 _: std.fmt.FormatOptions,
32 out_stream: anytype,
33) !void {
34 comptime assert(fmt.len == 0);
35 try out_stream.print("(interned: {})", .{start_val.toIntern()});
26pub fn dump(start_val: Value, w: std.io.Writer) std.io.Writer.Error!void {
27 try w.print("(interned: {})", .{start_val.toIntern()});
3628}
3729
38pub fn fmtDebug(val: Value) std.fmt.Formatter(dump) {
30pub fn fmtDebug(val: Value) std.fmt.Formatter(Value, dump) {
3931 return .{ .data = val };
4032}
4133
42pub fn fmtValue(val: Value, pt: Zcu.PerThread) std.fmt.Formatter(print_value.format) {
34pub fn fmtValue(val: Value, pt: Zcu.PerThread) std.fmt.Formatter(print_value.FormatContext, print_value.format) {
4335 return .{ .data = .{
4436 .val = val,
4537 .pt = pt,
......@@ -48,7 +40,7 @@ pub fn fmtValue(val: Value, pt: Zcu.PerThread) std.fmt.Formatter(print_value.for
4840 } };
4941}
5042
51pub fn fmtValueSema(val: Value, pt: Zcu.PerThread, sema: *Sema) std.fmt.Formatter(print_value.formatSema) {
43pub fn fmtValueSema(val: Value, pt: Zcu.PerThread, sema: *Sema) std.fmt.Formatter(print_value.FormatContext, print_value.formatSema) {
5244 return .{ .data = .{
5345 .val = val,
5446 .pt = pt,
......@@ -57,7 +49,7 @@ pub fn fmtValueSema(val: Value, pt: Zcu.PerThread, sema: *Sema) std.fmt.Formatte
5749 } };
5850}
5951
60pub fn fmtValueSemaFull(ctx: print_value.FormatContext) std.fmt.Formatter(print_value.formatSema) {
52pub fn fmtValueSemaFull(ctx: print_value.FormatContext) std.fmt.Formatter(print_value.FormatContext, print_value.formatSema) {
6153 return .{ .data = ctx };
6254}
6355
src/Zcu.zig+123-206
......@@ -15,6 +15,7 @@ const BigIntConst = std.math.big.int.Const;
1515const BigIntMutable = std.math.big.int.Mutable;
1616const Target = std.Target;
1717const Ast = std.zig.Ast;
18const Writer = std.io.Writer;
1819
1920const Zcu = @This();
2021const Compilation = @import("Compilation.zig");
......@@ -858,7 +859,7 @@ pub const Namespace = struct {
858859 try ns.fileScope(zcu).renderFullyQualifiedDebugName(writer);
859860 break :sep ':';
860861 };
861 if (name != .empty) try writer.print("{c}{}", .{ sep, name.fmt(&zcu.intern_pool) });
862 if (name != .empty) try writer.print("{c}{f}", .{ sep, name.fmt(&zcu.intern_pool) });
862863 }
863864
864865 pub fn internFullyQualifiedName(
......@@ -870,7 +871,7 @@ pub const Namespace = struct {
870871 ) !InternPool.NullTerminatedString {
871872 const ns_name = Type.fromInterned(ns.owner_type).containerTypeName(ip);
872873 if (name == .empty) return ns_name;
873 return ip.getOrPutStringFmt(gpa, tid, "{}.{}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);
874 return ip.getOrPutStringFmt(gpa, tid, "{f}.{f}", .{ ns_name.fmt(ip), name.fmt(ip) }, .no_embedded_nulls);
874875 }
875876};
876877
......@@ -1039,12 +1040,12 @@ pub const File = struct {
10391040 if (stat.size > std.math.maxInt(u32))
10401041 return error.FileTooBig;
10411042
1042 const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
1043 const source = try gpa.allocSentinel(u8, @intCast(stat.size), 0);
10431044 errdefer gpa.free(source);
10441045
1045 const amt = try f.readAll(source);
1046 if (amt != stat.size)
1047 return error.UnexpectedEndOfFile;
1046 var file_reader = f.reader(&.{});
1047 file_reader.size = stat.size;
1048 try file_reader.interface.readSliceAll(source);
10481049
10491050 // Here we do not modify stat fields because this function is the one
10501051 // used for error reporting. We need to keep the stat fields stale so that
......@@ -1097,11 +1098,10 @@ pub const File = struct {
10971098 const gpa = pt.zcu.gpa;
10981099 const ip = &pt.zcu.intern_pool;
10991100 const strings = ip.getLocal(pt.tid).getMutableStrings(gpa);
1100 const slice = try strings.addManyAsSlice(file.fullyQualifiedNameLen());
1101 var fbs = std.io.fixedBufferStream(slice[0]);
1102 file.renderFullyQualifiedName(fbs.writer()) catch unreachable;
1103 assert(fbs.pos == slice[0].len);
1104 return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(slice[0].len), .no_embedded_nulls);
1101 var w: Writer = .fixed((try strings.addManyAsSlice(file.fullyQualifiedNameLen()))[0]);
1102 file.renderFullyQualifiedName(&w) catch unreachable;
1103 assert(w.end == w.buffer.len);
1104 return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(w.end), .no_embedded_nulls);
11051105 }
11061106
11071107 pub const Index = InternPool.FileIndex;
......@@ -1112,7 +1112,7 @@ pub const File = struct {
11121112 eb: *std.zig.ErrorBundle.Wip,
11131113 ) !std.zig.ErrorBundle.SourceLocationIndex {
11141114 return eb.addSourceLocation(.{
1115 .src_path = try eb.printString("{}", .{file.path.fmt(zcu.comp)}),
1115 .src_path = try eb.printString("{f}", .{file.path.fmt(zcu.comp)}),
11161116 .span_start = 0,
11171117 .span_main = 0,
11181118 .span_end = 0,
......@@ -1133,7 +1133,7 @@ pub const File = struct {
11331133 const end = start + tree.tokenSlice(tok).len;
11341134 const loc = std.zig.findLineColumn(source.bytes, start);
11351135 return eb.addSourceLocation(.{
1136 .src_path = try eb.printString("{}", .{file.path.fmt(zcu.comp)}),
1136 .src_path = try eb.printString("{f}", .{file.path.fmt(zcu.comp)}),
11371137 .span_start = start,
11381138 .span_main = start,
11391139 .span_end = @intCast(end),
......@@ -1190,13 +1190,8 @@ pub const ErrorMsg = struct {
11901190 gpa.destroy(err_msg);
11911191 }
11921192
1193 pub fn init(
1194 gpa: Allocator,
1195 src_loc: LazySrcLoc,
1196 comptime format: []const u8,
1197 args: anytype,
1198 ) !ErrorMsg {
1199 return ErrorMsg{
1193 pub fn init(gpa: Allocator, src_loc: LazySrcLoc, comptime format: []const u8, args: anytype) !ErrorMsg {
1194 return .{
12001195 .src_loc = src_loc,
12011196 .msg = try std.fmt.allocPrint(gpa, format, args),
12021197 };
......@@ -2811,10 +2806,18 @@ comptime {
28112806}
28122807
28132808pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir {
2814 return loadZirCacheBody(gpa, try cache_file.reader().readStruct(Zir.Header), cache_file);
2809 var buffer: [2000]u8 = undefined;
2810 var file_reader = cache_file.reader(&buffer);
2811 return result: {
2812 const header = file_reader.interface.takeStruct(Zir.Header) catch |err| break :result err;
2813 break :result loadZirCacheBody(gpa, header.*, &file_reader.interface);
2814 } catch |err| switch (err) {
2815 error.ReadFailed => return file_reader.err.?,
2816 else => |e| return e,
2817 };
28152818}
28162819
2817pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) !Zir {
2820pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_br: *std.io.Reader) !Zir {
28182821 var instructions: std.MultiArrayList(Zir.Inst) = .{};
28192822 errdefer instructions.deinit(gpa);
28202823
......@@ -2837,34 +2840,16 @@ pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.F
28372840 undefined;
28382841 defer if (data_has_safety_tag) gpa.free(safety_buffer);
28392842
2840 const data_ptr = if (data_has_safety_tag)
2841 @as([*]u8, @ptrCast(safety_buffer.ptr))
2842 else
2843 @as([*]u8, @ptrCast(zir.instructions.items(.data).ptr));
2844
2845 var iovecs = [_]std.posix.iovec{
2846 .{
2847 .base = @as([*]u8, @ptrCast(zir.instructions.items(.tag).ptr)),
2848 .len = header.instructions_len,
2849 },
2850 .{
2851 .base = data_ptr,
2852 .len = header.instructions_len * 8,
2853 },
2854 .{
2855 .base = zir.string_bytes.ptr,
2856 .len = header.string_bytes_len,
2857 },
2858 .{
2859 .base = @as([*]u8, @ptrCast(zir.extra.ptr)),
2860 .len = header.extra_len * 4,
2861 },
2843 var vecs = [_][]u8{
2844 @ptrCast(zir.instructions.items(.tag)),
2845 if (data_has_safety_tag)
2846 @ptrCast(safety_buffer)
2847 else
2848 @ptrCast(zir.instructions.items(.data)),
2849 zir.string_bytes,
2850 @ptrCast(zir.extra),
28622851 };
2863 const amt_read = try cache_file.readvAll(&iovecs);
2864 const amt_expected = zir.instructions.len * 9 +
2865 zir.string_bytes.len +
2866 zir.extra.len * 4;
2867 if (amt_read != amt_expected) return error.UnexpectedFileSize;
2852 try cache_br.readVecAll(&vecs);
28682853 if (data_has_safety_tag) {
28692854 const tags = zir.instructions.items(.tag);
28702855 for (zir.instructions.items(.data), 0..) |*data, i| {
......@@ -2876,7 +2861,6 @@ pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.F
28762861 };
28772862 }
28782863 }
2879
28802864 return zir;
28812865}
28822866
......@@ -2887,14 +2871,6 @@ pub fn saveZirCache(gpa: Allocator, cache_file: std.fs.File, stat: std.fs.File.S
28872871 undefined;
28882872 defer if (data_has_safety_tag) gpa.free(safety_buffer);
28892873
2890 const data_ptr: [*]const u8 = if (data_has_safety_tag)
2891 if (zir.instructions.len == 0)
2892 undefined
2893 else
2894 @ptrCast(safety_buffer.ptr)
2895 else
2896 @ptrCast(zir.instructions.items(.data).ptr);
2897
28982874 if (data_has_safety_tag) {
28992875 // The `Data` union has a safety tag but in the file format we store it without.
29002876 for (zir.instructions.items(.data), 0..) |*data, i| {
......@@ -2912,29 +2888,20 @@ pub fn saveZirCache(gpa: Allocator, cache_file: std.fs.File, stat: std.fs.File.S
29122888 .stat_inode = stat.inode,
29132889 .stat_mtime = stat.mtime,
29142890 };
2915 var iovecs: [5]std.posix.iovec_const = .{
2916 .{
2917 .base = @ptrCast(&header),
2918 .len = @sizeOf(Zir.Header),
2919 },
2920 .{
2921 .base = @ptrCast(zir.instructions.items(.tag).ptr),
2922 .len = zir.instructions.len,
2923 },
2924 .{
2925 .base = data_ptr,
2926 .len = zir.instructions.len * 8,
2927 },
2928 .{
2929 .base = zir.string_bytes.ptr,
2930 .len = zir.string_bytes.len,
2931 },
2932 .{
2933 .base = @ptrCast(zir.extra.ptr),
2934 .len = zir.extra.len * 4,
2935 },
2891 var vecs = [_][]const u8{
2892 @ptrCast((&header)[0..1]),
2893 @ptrCast(zir.instructions.items(.tag)),
2894 if (data_has_safety_tag)
2895 @ptrCast(safety_buffer)
2896 else
2897 @ptrCast(zir.instructions.items(.data)),
2898 zir.string_bytes,
2899 @ptrCast(zir.extra),
2900 };
2901 var cache_fw = cache_file.writer(&.{});
2902 cache_fw.interface.writeVecAll(&vecs) catch |err| switch (err) {
2903 error.WriteFailed => return cache_fw.err.?,
29362904 };
2937 try cache_file.writevAll(&iovecs);
29382905}
29392906
29402907pub fn saveZoirCache(cache_file: std.fs.File, stat: std.fs.File.Stat, zoir: Zoir) std.fs.File.WriteError!void {
......@@ -2950,48 +2917,24 @@ pub fn saveZoirCache(cache_file: std.fs.File, stat: std.fs.File.Stat, zoir: Zoir
29502917 .stat_inode = stat.inode,
29512918 .stat_mtime = stat.mtime,
29522919 };
2953 var iovecs: [9]std.posix.iovec_const = .{
2954 .{
2955 .base = @ptrCast(&header),
2956 .len = @sizeOf(Zoir.Header),
2957 },
2958 .{
2959 .base = @ptrCast(zoir.nodes.items(.tag)),
2960 .len = zoir.nodes.len * @sizeOf(Zoir.Node.Repr.Tag),
2961 },
2962 .{
2963 .base = @ptrCast(zoir.nodes.items(.data)),
2964 .len = zoir.nodes.len * 4,
2965 },
2966 .{
2967 .base = @ptrCast(zoir.nodes.items(.ast_node)),
2968 .len = zoir.nodes.len * 4,
2969 },
2970 .{
2971 .base = @ptrCast(zoir.extra),
2972 .len = zoir.extra.len * 4,
2973 },
2974 .{
2975 .base = @ptrCast(zoir.limbs),
2976 .len = zoir.limbs.len * @sizeOf(std.math.big.Limb),
2977 },
2978 .{
2979 .base = zoir.string_bytes.ptr,
2980 .len = zoir.string_bytes.len,
2981 },
2982 .{
2983 .base = @ptrCast(zoir.compile_errors),
2984 .len = zoir.compile_errors.len * @sizeOf(Zoir.CompileError),
2985 },
2986 .{
2987 .base = @ptrCast(zoir.error_notes),
2988 .len = zoir.error_notes.len * @sizeOf(Zoir.CompileError.Note),
2989 },
2920 var vecs = [_][]const u8{
2921 @ptrCast((&header)[0..1]),
2922 @ptrCast(zoir.nodes.items(.tag)),
2923 @ptrCast(zoir.nodes.items(.data)),
2924 @ptrCast(zoir.nodes.items(.ast_node)),
2925 @ptrCast(zoir.extra),
2926 @ptrCast(zoir.limbs),
2927 zoir.string_bytes,
2928 @ptrCast(zoir.compile_errors),
2929 @ptrCast(zoir.error_notes),
2930 };
2931 var cache_fw = cache_file.writer(&.{});
2932 cache_fw.interface.writeVecAll(&vecs) catch |err| switch (err) {
2933 error.WriteFailed => return cache_fw.err.?,
29902934 };
2991 try cache_file.writevAll(&iovecs);
29922935}
29932936
2994pub fn loadZoirCacheBody(gpa: Allocator, header: Zoir.Header, cache_file: std.fs.File) !Zoir {
2937pub fn loadZoirCacheBody(gpa: Allocator, header: Zoir.Header, cache_br: *std.io.Reader) !Zoir {
29952938 var zoir: Zoir = .{
29962939 .nodes = .empty,
29972940 .extra = &.{},
......@@ -3017,49 +2960,17 @@ pub fn loadZoirCacheBody(gpa: Allocator, header: Zoir.Header, cache_file: std.fs
30172960 zoir.compile_errors = try gpa.alloc(Zoir.CompileError, header.compile_errors_len);
30182961 zoir.error_notes = try gpa.alloc(Zoir.CompileError.Note, header.error_notes_len);
30192962
3020 var iovecs: [8]std.posix.iovec = .{
3021 .{
3022 .base = @ptrCast(zoir.nodes.items(.tag)),
3023 .len = header.nodes_len * @sizeOf(Zoir.Node.Repr.Tag),
3024 },
3025 .{
3026 .base = @ptrCast(zoir.nodes.items(.data)),
3027 .len = header.nodes_len * 4,
3028 },
3029 .{
3030 .base = @ptrCast(zoir.nodes.items(.ast_node)),
3031 .len = header.nodes_len * 4,
3032 },
3033 .{
3034 .base = @ptrCast(zoir.extra),
3035 .len = header.extra_len * 4,
3036 },
3037 .{
3038 .base = @ptrCast(zoir.limbs),
3039 .len = header.limbs_len * @sizeOf(std.math.big.Limb),
3040 },
3041 .{
3042 .base = zoir.string_bytes.ptr,
3043 .len = header.string_bytes_len,
3044 },
3045 .{
3046 .base = @ptrCast(zoir.compile_errors),
3047 .len = header.compile_errors_len * @sizeOf(Zoir.CompileError),
3048 },
3049 .{
3050 .base = @ptrCast(zoir.error_notes),
3051 .len = header.error_notes_len * @sizeOf(Zoir.CompileError.Note),
3052 },
3053 };
3054
3055 const bytes_expected = expected: {
3056 var n: usize = 0;
3057 for (iovecs) |v| n += v.len;
3058 break :expected n;
2963 var vecs = [_][]u8{
2964 @ptrCast(zoir.nodes.items(.tag)),
2965 @ptrCast(zoir.nodes.items(.data)),
2966 @ptrCast(zoir.nodes.items(.ast_node)),
2967 @ptrCast(zoir.extra),
2968 @ptrCast(zoir.limbs),
2969 zoir.string_bytes,
2970 @ptrCast(zoir.compile_errors),
2971 @ptrCast(zoir.error_notes),
30592972 };
3060
3061 const bytes_read = try cache_file.readvAll(&iovecs);
3062 if (bytes_read != bytes_expected) return error.UnexpectedFileSize;
2973 try cache_br.readVecAll(&vecs);
30632974 return zoir;
30642975}
30652976
......@@ -3071,7 +2982,7 @@ pub fn markDependeeOutdated(
30712982 marked_po: enum { not_marked_po, marked_po },
30722983 dependee: InternPool.Dependee,
30732984) !void {
3074 log.debug("outdated dependee: {}", .{zcu.fmtDependee(dependee)});
2985 log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)});
30752986 var it = zcu.intern_pool.dependencyIterator(dependee);
30762987 while (it.next()) |depender| {
30772988 if (zcu.outdated.getPtr(depender)) |po_dep_count| {
......@@ -3079,9 +2990,9 @@ pub fn markDependeeOutdated(
30792990 .not_marked_po => {},
30802991 .marked_po => {
30812992 po_dep_count.* -= 1;
3082 log.debug("outdated {} => already outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
2993 log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
30832994 if (po_dep_count.* == 0) {
3084 log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)});
2995 log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
30852996 try zcu.outdated_ready.put(zcu.gpa, depender, {});
30862997 }
30872998 },
......@@ -3102,9 +3013,9 @@ pub fn markDependeeOutdated(
31023013 depender,
31033014 new_po_dep_count,
31043015 );
3105 log.debug("outdated {} => new outdated {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count });
3016 log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count });
31063017 if (new_po_dep_count == 0) {
3107 log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)});
3018 log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
31083019 try zcu.outdated_ready.put(zcu.gpa, depender, {});
31093020 }
31103021 // If this is a Decl and was not previously PO, we must recursively
......@@ -3117,16 +3028,16 @@ pub fn markDependeeOutdated(
31173028}
31183029
31193030pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
3120 log.debug("up-to-date dependee: {}", .{zcu.fmtDependee(dependee)});
3031 log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)});
31213032 var it = zcu.intern_pool.dependencyIterator(dependee);
31223033 while (it.next()) |depender| {
31233034 if (zcu.outdated.getPtr(depender)) |po_dep_count| {
31243035 // This depender is already outdated, but it now has one
31253036 // less PO dependency!
31263037 po_dep_count.* -= 1;
3127 log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
3038 log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
31283039 if (po_dep_count.* == 0) {
3129 log.debug("outdated ready: {}", .{zcu.fmtAnalUnit(depender)});
3040 log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
31303041 try zcu.outdated_ready.put(zcu.gpa, depender, {});
31313042 }
31323043 continue;
......@@ -3140,11 +3051,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
31403051 };
31413052 if (ptr.* > 1) {
31423053 ptr.* -= 1;
3143 log.debug("up-to-date {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* });
3054 log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* });
31443055 continue;
31453056 }
31463057
3147 log.debug("up-to-date {} => {} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) });
3058 log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) });
31483059
31493060 // This dependency is no longer PO, i.e. is known to be up-to-date.
31503061 assert(zcu.potentially_outdated.swapRemove(depender));
......@@ -3173,7 +3084,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
31733084 .func => |func_index| .{ .interned = func_index }, // IES
31743085 .memoized_state => |stage| .{ .memoized_state = stage },
31753086 };
3176 log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)});
3087 log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)});
31773088 var it = ip.dependencyIterator(dependee);
31783089 while (it.next()) |po| {
31793090 if (zcu.outdated.getPtr(po)) |po_dep_count| {
......@@ -3183,17 +3094,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
31833094 _ = zcu.outdated_ready.swapRemove(po);
31843095 }
31853096 po_dep_count.* += 1;
3186 log.debug("po {} => {} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* });
3097 log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* });
31873098 continue;
31883099 }
31893100 if (zcu.potentially_outdated.getPtr(po)) |n| {
31903101 // There is now one more PO dependency.
31913102 n.* += 1;
3192 log.debug("po {} => {} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* });
3103 log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* });
31933104 continue;
31943105 }
31953106 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
3196 log.debug("po {} => {} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) });
3107 log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) });
31973108 // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO.
31983109 try zcu.markTransitiveDependersPotentiallyOutdated(po);
31993110 }
......@@ -3222,7 +3133,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
32223133
32233134 if (zcu.outdated_ready.count() > 0) {
32243135 const unit = zcu.outdated_ready.keys()[0];
3225 log.debug("findOutdatedToAnalyze: trivial {}", .{zcu.fmtAnalUnit(unit)});
3136 log.debug("findOutdatedToAnalyze: trivial {f}", .{zcu.fmtAnalUnit(unit)});
32263137 return unit;
32273138 }
32283139
......@@ -3273,7 +3184,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
32733184 }
32743185 }
32753186
3276 log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{
3187 log.debug("findOutdatedToAnalyze: heuristic returned '{f}' ({d} dependers)", .{
32773188 zcu.fmtAnalUnit(chosen_unit.?),
32783189 chosen_unit_dependers,
32793190 });
......@@ -4072,7 +3983,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
40723983 const referencer = kv.value;
40733984 try checked_types.putNoClobber(gpa, ty, {});
40743985
4075 log.debug("handle type '{}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});
3986 log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});
40763987
40773988 // If this type undergoes type resolution, the corresponding `AnalUnit` is automatically referenced.
40783989 const has_resolution: bool = switch (ip.indexToKey(ty)) {
......@@ -4108,7 +4019,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
41084019 // `comptime` decls are always analyzed.
41094020 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
41104021 if (!result.contains(unit)) {
4111 log.debug("type '{}': ref comptime %{}", .{
4022 log.debug("type '{f}': ref comptime %{}", .{
41124023 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
41134024 @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),
41144025 });
......@@ -4139,7 +4050,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
41394050 },
41404051 };
41414052 if (want_analysis) {
4142 log.debug("type '{}': ref test %{}", .{
4053 log.debug("type '{f}': ref test %{}", .{
41434054 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
41444055 @intFromEnum(inst_info.inst),
41454056 });
......@@ -4158,7 +4069,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
41584069 if (decl.linkage == .@"export") {
41594070 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
41604071 if (!result.contains(unit)) {
4161 log.debug("type '{}': ref named %{}", .{
4072 log.debug("type '{f}': ref named %{}", .{
41624073 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
41634074 @intFromEnum(inst_info.inst),
41644075 });
......@@ -4174,7 +4085,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
41744085 if (decl.linkage == .@"export") {
41754086 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
41764087 if (!result.contains(unit)) {
4177 log.debug("type '{}': ref named %{}", .{
4088 log.debug("type '{f}': ref named %{}", .{
41784089 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
41794090 @intFromEnum(inst_info.inst),
41804091 });
......@@ -4199,7 +4110,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
41994110 try unit_queue.put(gpa, other, kv.value); // same reference location
42004111 }
42014112
4202 log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)});
4113 log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)});
42034114
42044115 if (zcu.reference_table.get(unit)) |first_ref_idx| {
42054116 assert(first_ref_idx != std.math.maxInt(u32));
......@@ -4207,7 +4118,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
42074118 while (ref_idx != std.math.maxInt(u32)) {
42084119 const ref = zcu.all_references.items[ref_idx];
42094120 if (!result.contains(ref.referenced)) {
4210 log.debug("unit '{}': ref unit '{}'", .{
4121 log.debug("unit '{f}': ref unit '{f}'", .{
42114122 zcu.fmtAnalUnit(unit),
42124123 zcu.fmtAnalUnit(ref.referenced),
42134124 });
......@@ -4226,7 +4137,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
42264137 while (ref_idx != std.math.maxInt(u32)) {
42274138 const ref = zcu.all_type_references.items[ref_idx];
42284139 if (!checked_types.contains(ref.referenced)) {
4229 log.debug("unit '{}': ref type '{}'", .{
4140 log.debug("unit '{f}': ref type '{f}'", .{
42304141 zcu.fmtAnalUnit(unit),
42314142 Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip),
42324143 });
......@@ -4307,15 +4218,19 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
43074218 return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
43084219}
43094220
4310pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) {
4221pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(FormatAnalUnit, formatAnalUnit) {
43114222 return .{ .data = .{ .unit = unit, .zcu = zcu } };
43124223}
4313pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Formatter(formatDependee) {
4224pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Formatter(FormatDependee, formatDependee) {
43144225 return .{ .data = .{ .dependee = d, .zcu = zcu } };
43154226}
43164227
4317fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
4318 _ = .{ fmt, options };
4228const FormatAnalUnit = struct {
4229 unit: AnalUnit,
4230 zcu: *Zcu,
4231};
4232
4233fn formatAnalUnit(data: FormatAnalUnit, writer: *std.io.Writer) std.io.Writer.Error!void {
43194234 const zcu = data.zcu;
43204235 const ip = &zcu.intern_pool;
43214236 switch (data.unit.unwrap()) {
......@@ -4323,23 +4238,25 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co
43234238 const cu = ip.getComptimeUnit(cu_id);
43244239 if (cu.zir_index.resolveFull(ip)) |resolved| {
43254240 const file_path = zcu.fileByIndex(resolved.file).path;
4326 return writer.print("comptime(inst=('{}', %{}) [{}])", .{ file_path.fmt(zcu.comp), @intFromEnum(resolved.inst), @intFromEnum(cu_id) });
4241 return writer.print("comptime(inst=('{f}', %{}) [{}])", .{ file_path.fmt(zcu.comp), @intFromEnum(resolved.inst), @intFromEnum(cu_id) });
43274242 } else {
43284243 return writer.print("comptime(inst=<lost> [{}])", .{@intFromEnum(cu_id)});
43294244 }
43304245 },
4331 .nav_val => |nav| return writer.print("nav_val('{}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
4332 .nav_ty => |nav| return writer.print("nav_ty('{}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
4333 .type => |ty| return writer.print("ty('{}' [{}])", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }),
4246 .nav_val => |nav| return writer.print("nav_val('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
4247 .nav_ty => |nav| return writer.print("nav_ty('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
4248 .type => |ty| return writer.print("ty('{f}' [{}])", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }),
43344249 .func => |func| {
43354250 const nav = zcu.funcInfo(func).owner_nav;
4336 return writer.print("func('{}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) });
4251 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) });
43374252 },
43384253 .memoized_state => return writer.writeAll("memoized_state"),
43394254 }
43404255}
4341fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
4342 _ = .{ fmt, options };
4256
4257const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *Zcu };
4258
4259fn formatDependee(data: FormatDependee, writer: *std.io.Writer) std.io.Writer.Error!void {
43434260 const zcu = data.zcu;
43444261 const ip = &zcu.intern_pool;
43454262 switch (data.dependee) {
......@@ -4348,42 +4265,42 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
43484265 return writer.writeAll("inst(<lost>)");
43494266 };
43504267 const file_path = zcu.fileByIndex(info.file).path;
4351 return writer.print("inst('{}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
4268 return writer.print("inst('{f}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
43524269 },
43534270 .nav_val => |nav| {
43544271 const fqn = ip.getNav(nav).fqn;
4355 return writer.print("nav_val('{}')", .{fqn.fmt(ip)});
4272 return writer.print("nav_val('{f}')", .{fqn.fmt(ip)});
43564273 },
43574274 .nav_ty => |nav| {
43584275 const fqn = ip.getNav(nav).fqn;
4359 return writer.print("nav_ty('{}')", .{fqn.fmt(ip)});
4276 return writer.print("nav_ty('{f}')", .{fqn.fmt(ip)});
43604277 },
43614278 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
4362 .struct_type, .union_type, .enum_type => return writer.print("type('{}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}),
4363 .func => |f| return writer.print("ies('{}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}),
4279 .struct_type, .union_type, .enum_type => return writer.print("type('{f}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}),
4280 .func => |f| return writer.print("ies('{f}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}),
43644281 else => unreachable,
43654282 },
43664283 .zon_file => |file| {
43674284 const file_path = zcu.fileByIndex(file).path;
4368 return writer.print("zon_file('{}')", .{file_path.fmt(zcu.comp)});
4285 return writer.print("zon_file('{f}')", .{file_path.fmt(zcu.comp)});
43694286 },
43704287 .embed_file => |ef_idx| {
43714288 const ef = ef_idx.get(zcu);
4372 return writer.print("embed_file('{}')", .{ef.path.fmt(zcu.comp)});
4289 return writer.print("embed_file('{f}')", .{ef.path.fmt(zcu.comp)});
43734290 },
43744291 .namespace => |ti| {
43754292 const info = ti.resolveFull(ip) orelse {
43764293 return writer.writeAll("namespace(<lost>)");
43774294 };
43784295 const file_path = zcu.fileByIndex(info.file).path;
4379 return writer.print("namespace('{}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
4296 return writer.print("namespace('{f}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
43804297 },
43814298 .namespace_name => |k| {
43824299 const info = k.namespace.resolveFull(ip) orelse {
4383 return writer.print("namespace(<lost>, '{}')", .{k.name.fmt(ip)});
4300 return writer.print("namespace(<lost>, '{f}')", .{k.name.fmt(ip)});
43844301 };
43854302 const file_path = zcu.fileByIndex(info.file).path;
4386 return writer.print("namespace('{}', %{d}, '{}')", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst), k.name.fmt(ip) });
4303 return writer.print("namespace('{f}', %{d}, '{f}')", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst), k.name.fmt(ip) });
43874304 },
43884305 .memoized_state => return writer.writeAll("memoized_state"),
43894306 }
src/Zcu/PerThread.zig+65-58
......@@ -53,7 +53,7 @@ fn deinitFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
5353 const zcu = pt.zcu;
5454 const gpa = zcu.gpa;
5555 const file = zcu.fileByIndex(file_index);
56 log.debug("deinit File {}", .{file.path.fmt(zcu.comp)});
56 log.debug("deinit File {f}", .{file.path.fmt(zcu.comp)});
5757 file.path.deinit(gpa);
5858 file.unload(gpa);
5959 if (file.prev_zir) |prev_zir| {
......@@ -117,7 +117,7 @@ pub fn updateFile(
117117 var lock: std.fs.File.Lock = switch (file.status) {
118118 .never_loaded, .retryable_failure => lock: {
119119 // First, load the cached ZIR code, if any.
120 log.debug("AstGen checking cache: {} (local={}, digest={s})", .{
120 log.debug("AstGen checking cache: {f} (local={}, digest={s})", .{
121121 file.path.fmt(comp), want_local_cache, &hex_digest,
122122 });
123123
......@@ -130,11 +130,11 @@ pub fn updateFile(
130130 stat.inode == file.stat.inode;
131131
132132 if (unchanged_metadata) {
133 log.debug("unmodified metadata of file: {}", .{file.path.fmt(comp)});
133 log.debug("unmodified metadata of file: {f}", .{file.path.fmt(comp)});
134134 return;
135135 }
136136
137 log.debug("metadata changed: {}", .{file.path.fmt(comp)});
137 log.debug("metadata changed: {f}", .{file.path.fmt(comp)});
138138
139139 break :lock .exclusive;
140140 },
......@@ -190,7 +190,7 @@ pub fn updateFile(
190190 // failure was a race, or ENOENT, indicating deletion of the
191191 // directory of our open handle.
192192 if (builtin.os.tag != .macos) {
193 std.process.fatal("cache directory '{}' unexpectedly removed during compiler execution", .{
193 std.process.fatal("cache directory '{f}' unexpectedly removed during compiler execution", .{
194194 cache_directory,
195195 });
196196 }
......@@ -202,7 +202,7 @@ pub fn updateFile(
202202 }) catch |excl_err| switch (excl_err) {
203203 error.PathAlreadyExists => continue,
204204 error.FileNotFound => {
205 std.process.fatal("cache directory '{}' unexpectedly removed during compiler execution", .{
205 std.process.fatal("cache directory '{f}' unexpectedly removed during compiler execution", .{
206206 cache_directory,
207207 });
208208 },
......@@ -221,12 +221,12 @@ pub fn updateFile(
221221 };
222222 switch (result) {
223223 .success => {
224 log.debug("AstGen cached success: {}", .{file.path.fmt(comp)});
224 log.debug("AstGen cached success: {f}", .{file.path.fmt(comp)});
225225 break false;
226226 },
227227 .invalid => {},
228 .truncated => log.warn("unexpected EOF reading cached ZIR for {}", .{file.path.fmt(comp)}),
229 .stale => log.debug("AstGen cache stale: {}", .{file.path.fmt(comp)}),
228 .truncated => log.warn("unexpected EOF reading cached ZIR for {f}", .{file.path.fmt(comp)}),
229 .stale => log.debug("AstGen cache stale: {f}", .{file.path.fmt(comp)}),
230230 }
231231
232232 // If we already have the exclusive lock then it is our job to update.
......@@ -249,11 +249,14 @@ pub fn updateFile(
249249 if (stat.size > std.math.maxInt(u32))
250250 return error.FileTooBig;
251251
252 const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
252 const source = try gpa.allocSentinel(u8, @intCast(stat.size), 0);
253253 defer if (file.source == null) gpa.free(source);
254 const amt = try source_file.readAll(source);
255 if (amt != stat.size)
256 return error.UnexpectedEndOfFile;
254 var source_fr = source_file.reader(&.{});
255 source_fr.size = stat.size;
256 source_fr.interface.readSliceAll(source) catch |err| switch (err) {
257 error.ReadFailed => return source_fr.err.?,
258 error.EndOfStream => return error.UnexpectedEndOfFile,
259 };
257260
258261 file.source = source;
259262
......@@ -265,7 +268,7 @@ pub fn updateFile(
265268 file.zir = try AstGen.generate(gpa, file.tree.?);
266269 Zcu.saveZirCache(gpa, cache_file, stat, file.zir.?) catch |err| switch (err) {
267270 error.OutOfMemory => |e| return e,
268 else => log.warn("unable to write cached ZIR code for {} to {}{s}: {s}", .{
271 else => log.warn("unable to write cached ZIR code for {f} to {f}{s}: {s}", .{
269272 file.path.fmt(comp), cache_directory, &hex_digest, @errorName(err),
270273 }),
271274 };
......@@ -273,14 +276,14 @@ pub fn updateFile(
273276 .zon => {
274277 file.zoir = try ZonGen.generate(gpa, file.tree.?, .{});
275278 Zcu.saveZoirCache(cache_file, stat, file.zoir.?) catch |err| {
276 log.warn("unable to write cached ZOIR code for {} to {}{s}: {s}", .{
279 log.warn("unable to write cached ZOIR code for {f} to {f}{s}: {s}", .{
277280 file.path.fmt(comp), cache_directory, &hex_digest, @errorName(err),
278281 });
279282 };
280283 },
281284 }
282285
283 log.debug("AstGen fresh success: {}", .{file.path.fmt(comp)});
286 log.debug("AstGen fresh success: {f}", .{file.path.fmt(comp)});
284287 }
285288
286289 file.stat = .{
......@@ -340,13 +343,19 @@ fn loadZirZoirCache(
340343 .zon => Zoir.Header,
341344 };
342345
346 var buffer: [2000]u8 = undefined;
347 var cache_fr = cache_file.reader(&buffer);
348 cache_fr.size = stat.size;
349 const cache_br = &cache_fr.interface;
350
343351 // First we read the header to determine the lengths of arrays.
344 const header = cache_file.reader().readStruct(Header) catch |err| switch (err) {
352 const header = (cache_br.takeStruct(Header) catch |err| switch (err) {
353 error.ReadFailed => return cache_fr.err.?,
345354 // This can happen if Zig bails out of this function between creating
346355 // the cached file and writing it.
347356 error.EndOfStream => return .invalid,
348357 else => |e| return e,
349 };
358 }).*;
350359
351360 const unchanged_metadata =
352361 stat.size == header.stat_size and
......@@ -358,17 +367,15 @@ fn loadZirZoirCache(
358367 }
359368
360369 switch (mode) {
361 .zig => {
362 file.zir = Zcu.loadZirCacheBody(gpa, header, cache_file) catch |err| switch (err) {
363 error.UnexpectedFileSize => return .truncated,
364 else => |e| return e,
365 };
370 .zig => file.zir = Zcu.loadZirCacheBody(gpa, header, cache_br) catch |err| switch (err) {
371 error.ReadFailed => return cache_fr.err.?,
372 error.EndOfStream => return .truncated,
373 else => |e| return e,
366374 },
367 .zon => {
368 file.zoir = Zcu.loadZoirCacheBody(gpa, header, cache_file) catch |err| switch (err) {
369 error.UnexpectedFileSize => return .truncated,
370 else => |e| return e,
371 };
375 .zon => file.zoir = Zcu.loadZoirCacheBody(gpa, header, cache_br) catch |err| switch (err) {
376 error.ReadFailed => return cache_fr.err.?,
377 error.EndOfStream => return .truncated,
378 else => |e| return e,
372379 },
373380 }
374381
......@@ -477,11 +484,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
477484 if (std.zig.srcHashEql(old_hash, new_hash)) {
478485 break :hash_changed;
479486 }
480 log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{
481 old_inst,
482 new_inst,
483 std.fmt.fmtSliceHexLower(&old_hash),
484 std.fmt.fmtSliceHexLower(&new_hash),
487 log.debug("hash for (%{d} -> %{d}) changed: {x} -> {x}", .{
488 old_inst, new_inst, &old_hash, &new_hash,
485489 });
486490 }
487491 // The source hash associated with this instruction changed - invalidate relevant dependencies.
......@@ -649,7 +653,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
649653 // If this unit caused the error, it would have an entry in `failed_analysis`.
650654 // Since it does not, this must be a transitive failure.
651655 try zcu.transitive_failed_analysis.put(gpa, unit, {});
652 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(unit)});
656 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(unit)});
653657 }
654658 break :res .{ !prev_failed, true };
655659 },
......@@ -754,7 +758,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
754758
755759 const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id });
756760
757 log.debug("ensureComptimeUnitUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
761 log.debug("ensureComptimeUnitUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
758762
759763 assert(!zcu.analysis_in_progress.contains(anal_unit));
760764
......@@ -805,7 +809,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
805809 // If this unit caused the error, it would have an entry in `failed_analysis`.
806810 // Since it does not, this must be a transitive failure.
807811 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
808 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
812 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
809813 }
810814 return error.AnalysisFail;
811815 },
......@@ -835,7 +839,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
835839 const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id });
836840 const comptime_unit = ip.getComptimeUnit(cu_id);
837841
838 log.debug("analyzeComptimeUnit {}", .{zcu.fmtAnalUnit(anal_unit)});
842 log.debug("analyzeComptimeUnit {f}", .{zcu.fmtAnalUnit(anal_unit)});
839843
840844 const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
841845 const file = zcu.fileByIndex(inst_resolved.file);
......@@ -881,7 +885,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
881885 .r = .{ .simple = .comptime_keyword },
882886 } },
883887 .src_base_inst = comptime_unit.zir_index,
884 .type_name_ctx = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.comptime", .{
888 .type_name_ctx = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}.comptime", .{
885889 Type.fromInterned(zcu.namespacePtr(comptime_unit.namespace).owner_type).containerTypeName(ip).fmt(ip),
886890 }, .no_embedded_nulls),
887891 };
......@@ -933,7 +937,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
933937 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
934938 const nav = ip.getNav(nav_id);
935939
936 log.debug("ensureNavValUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
940 log.debug("ensureNavValUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
937941
938942 // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the
939943 // status is `.unresolved`, which indicates that the value is outdated because it has *never*
......@@ -991,7 +995,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
991995 // If this unit caused the error, it would have an entry in `failed_analysis`.
992996 // Since it does not, this must be a transitive failure.
993997 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
994 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
998 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
995999 }
9961000 break :res .{ !prev_failed, true };
9971001 },
......@@ -1062,7 +1066,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
10621066 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
10631067 const old_nav = ip.getNav(nav_id);
10641068
1065 log.debug("analyzeNavVal {}", .{zcu.fmtAnalUnit(anal_unit)});
1069 log.debug("analyzeNavVal {f}", .{zcu.fmtAnalUnit(anal_unit)});
10661070
10671071 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
10681072 const file = zcu.fileByIndex(inst_resolved.file);
......@@ -1321,7 +1325,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
13211325 const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
13221326 const nav = ip.getNav(nav_id);
13231327
1324 log.debug("ensureNavTypeUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
1328 log.debug("ensureNavTypeUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
13251329
13261330 const type_resolved_by_value: bool = from_val: {
13271331 const analysis = nav.analysis orelse break :from_val false;
......@@ -1391,7 +1395,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
13911395 // If this unit caused the error, it would have an entry in `failed_analysis`.
13921396 // Since it does not, this must be a transitive failure.
13931397 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1394 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
1398 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
13951399 }
13961400 break :res .{ !prev_failed, true };
13971401 },
......@@ -1433,7 +1437,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
14331437 const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
14341438 const old_nav = ip.getNav(nav_id);
14351439
1436 log.debug("analyzeNavType {}", .{zcu.fmtAnalUnit(anal_unit)});
1440 log.debug("analyzeNavType {f}", .{zcu.fmtAnalUnit(anal_unit)});
14371441
14381442 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
14391443 const file = zcu.fileByIndex(inst_resolved.file);
......@@ -1563,7 +1567,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
15631567 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);
15641568 const anal_unit: AnalUnit = .wrap(.{ .func = func_index });
15651569
1566 log.debug("ensureFuncBodyUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
1570 log.debug("ensureFuncBodyUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
15671571
15681572 const func = zcu.funcInfo(maybe_coerced_func_index);
15691573
......@@ -1607,7 +1611,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
16071611 // If this function caused the error, it would have an entry in `failed_analysis`.
16081612 // Since it does not, this must be a transitive failure.
16091613 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1610 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
1614 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
16111615 }
16121616 // We consider the IES to be outdated if the function previously succeeded analysis; in this case,
16131617 // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting
......@@ -1677,7 +1681,7 @@ fn analyzeFuncBody(
16771681 else
16781682 .none;
16791683
1680 log.debug("analyze and generate fn body {}", .{zcu.fmtAnalUnit(anal_unit)});
1684 log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)});
16811685
16821686 var air = try pt.analyzeFnBodyInner(func_index);
16831687 errdefer air.deinit(gpa);
......@@ -2299,7 +2303,7 @@ pub fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!voi
22992303
23002304 Builtin.updateFileOnDisk(file, comp) catch |err| comp.setMiscFailure(
23012305 .write_builtin_zig,
2302 "unable to write '{}': {s}",
2306 "unable to write '{f}': {s}",
23032307 .{ file.path.fmt(comp), @errorName(err) },
23042308 );
23052309}
......@@ -2414,8 +2418,12 @@ fn updateEmbedFileInner(
24142418 const old_len = strings.mutate.len;
24152419 errdefer strings.shrinkRetainingCapacity(old_len);
24162420 const bytes = (try strings.addManyAsSlice(size_plus_one))[0];
2417 const actual_read = try file.readAll(bytes[0..size]);
2418 if (actual_read != size) return error.UnexpectedEof;
2421 var fr = file.reader(&.{});
2422 fr.size = stat.size;
2423 fr.interface.readSliceAll(bytes[0..size]) catch |err| switch (err) {
2424 error.ReadFailed => return fr.err.?,
2425 error.EndOfStream => return error.UnexpectedEof,
2426 };
24192427 bytes[size] = 0;
24202428 break :str try ip.getOrPutTrailingString(gpa, tid, @intCast(bytes.len), .maybe_embedded_nulls);
24212429 };
......@@ -2584,7 +2592,7 @@ const ScanDeclIter = struct {
25842592 var gop = try iter.seen_decls.getOrPut(gpa, name);
25852593 var next_suffix: u32 = 0;
25862594 while (gop.found_existing) {
2587 name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}_{d}", .{ name.fmt(ip), next_suffix }, .no_embedded_nulls);
2595 name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}_{d}", .{ name.fmt(ip), next_suffix }, .no_embedded_nulls);
25882596 gop = try iter.seen_decls.getOrPut(gpa, name);
25892597 next_suffix += 1;
25902598 }
......@@ -2716,7 +2724,7 @@ const ScanDeclIter = struct {
27162724
27172725 if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) {
27182726 log.debug(
2719 "scanDecl queue analyze_comptime_unit file='{s}' unit={}",
2727 "scanDecl queue analyze_comptime_unit file='{s}' unit={f}",
27202728 .{ namespace.fileScope(zcu).sub_file_path, zcu.fmtAnalUnit(unit) },
27212729 );
27222730 try comp.queueJob(.{ .analyze_comptime_unit = unit });
......@@ -3134,7 +3142,7 @@ fn processExportsInner(
31343142 if (gop.found_existing) {
31353143 new_export.status = .failed_retryable;
31363144 try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
3137 const msg = try Zcu.ErrorMsg.create(gpa, new_export.src, "exported symbol collision: {}", .{
3145 const msg = try Zcu.ErrorMsg.create(gpa, new_export.src, "exported symbol collision: {f}", .{
31383146 new_export.opts.name.fmt(ip),
31393147 });
31403148 errdefer msg.destroy(gpa);
......@@ -4376,12 +4384,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
43764384 defer liveness.deinit(gpa);
43774385
43784386 if (build_options.enable_debug_extensions and comp.verbose_air) {
4379 std.debug.lockStdErr();
4380 defer std.debug.unlockStdErr();
4381 const stderr = std.io.getStdErr().writer();
4382 stderr.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)}) catch {};
4387 const stderr = std.debug.lockStderrWriter(&.{});
4388 defer std.debug.unlockStderrWriter();
4389 stderr.print("# Begin Function AIR: {f}:\n", .{fqn.fmt(ip)}) catch {};
43834390 air.write(stderr, pt, liveness);
4384 stderr.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)}) catch {};
4391 stderr.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}) catch {};
43854392 }
43864393
43874394 if (std.debug.runtime_safety) {
src/arch/riscv64/CodeGen.zig+53-74
......@@ -435,7 +435,7 @@ const InstTracking = struct {
435435 fn trackSpill(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) !void {
436436 try function.freeValue(inst_tracking.short);
437437 inst_tracking.reuseFrame();
438 tracking_log.debug("%{d} => {} (spilled)", .{ inst, inst_tracking.* });
438 tracking_log.debug("%{d} => {f} (spilled)", .{ inst, inst_tracking.* });
439439 }
440440
441441 fn verifyMaterialize(inst_tracking: InstTracking, target: InstTracking) void {
......@@ -499,14 +499,14 @@ const InstTracking = struct {
499499 else => target.long,
500500 } else target.long;
501501 inst_tracking.short = target.short;
502 tracking_log.debug("%{d} => {} (materialize)", .{ inst, inst_tracking.* });
502 tracking_log.debug("%{d} => {f} (materialize)", .{ inst, inst_tracking.* });
503503 }
504504
505505 fn resurrect(inst_tracking: *InstTracking, inst: Air.Inst.Index, scope_generation: u32) void {
506506 switch (inst_tracking.short) {
507507 .dead => |die_generation| if (die_generation >= scope_generation) {
508508 inst_tracking.reuseFrame();
509 tracking_log.debug("%{d} => {} (resurrect)", .{ inst, inst_tracking.* });
509 tracking_log.debug("%{d} => {f} (resurrect)", .{ inst, inst_tracking.* });
510510 },
511511 else => {},
512512 }
......@@ -516,7 +516,7 @@ const InstTracking = struct {
516516 if (inst_tracking.short == .dead) return;
517517 try function.freeValue(inst_tracking.short);
518518 inst_tracking.short = .{ .dead = function.scope_generation };
519 tracking_log.debug("%{d} => {} (death)", .{ inst, inst_tracking.* });
519 tracking_log.debug("%{d} => {f} (death)", .{ inst, inst_tracking.* });
520520 }
521521
522522 fn reuse(
......@@ -527,15 +527,15 @@ const InstTracking = struct {
527527 ) void {
528528 inst_tracking.short = .{ .dead = function.scope_generation };
529529 if (new_inst) |inst|
530 tracking_log.debug("%{d} => {} (reuse %{d})", .{ inst, inst_tracking.*, old_inst })
530 tracking_log.debug("%{d} => {f} (reuse %{d})", .{ inst, inst_tracking.*, old_inst })
531531 else
532 tracking_log.debug("tmp => {} (reuse %{d})", .{ inst_tracking.*, old_inst });
532 tracking_log.debug("tmp => {f} (reuse %{d})", .{ inst_tracking.*, old_inst });
533533 }
534534
535535 fn liveOut(inst_tracking: *InstTracking, function: *Func, inst: Air.Inst.Index) void {
536536 for (inst_tracking.getRegs()) |reg| {
537537 if (function.register_manager.isRegFree(reg)) {
538 tracking_log.debug("%{d} => {} (live-out)", .{ inst, inst_tracking.* });
538 tracking_log.debug("%{d} => {f} (live-out)", .{ inst, inst_tracking.* });
539539 continue;
540540 }
541541
......@@ -562,16 +562,11 @@ const InstTracking = struct {
562562 // Perform side-effects of freeValue manually.
563563 function.register_manager.freeReg(reg);
564564
565 tracking_log.debug("%{d} => {} (live-out %{d})", .{ inst, inst_tracking.*, tracked_inst });
565 tracking_log.debug("%{d} => {f} (live-out %{d})", .{ inst, inst_tracking.*, tracked_inst });
566566 }
567567 }
568568
569 pub fn format(
570 inst_tracking: InstTracking,
571 comptime _: []const u8,
572 _: std.fmt.FormatOptions,
573 writer: anytype,
574 ) @TypeOf(writer).Error!void {
569 pub fn format(inst_tracking: InstTracking, writer: *std.io.Writer) std.io.Writer.Error!void {
575570 if (!std.meta.eql(inst_tracking.long, inst_tracking.short)) try writer.print("|{}| ", .{inst_tracking.long});
576571 try writer.print("{}", .{inst_tracking.short});
577572 }
......@@ -802,7 +797,7 @@ pub fn generate(
802797 function.mir_instructions.deinit(gpa);
803798 }
804799
805 wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
800 wip_mir_log.debug("{f}:", .{fmtNav(func.owner_nav, ip)});
806801
807802 try function.frame_allocs.resize(gpa, FrameIndex.named_count);
808803 function.frame_allocs.set(
......@@ -937,12 +932,7 @@ const FormatWipMirData = struct {
937932 func: *Func,
938933 inst: Mir.Inst.Index,
939934};
940fn formatWipMir(
941 data: FormatWipMirData,
942 comptime _: []const u8,
943 _: std.fmt.FormatOptions,
944 writer: anytype,
945) @TypeOf(writer).Error!void {
935fn formatWipMir(data: FormatWipMirData, writer: *std.io.Writer) std.io.Writer.Error!void {
946936 const pt = data.func.pt;
947937 const comp = pt.zcu.comp;
948938 var lower: Lower = .{
......@@ -982,7 +972,7 @@ fn formatWipMir(
982972 first = false;
983973 }
984974}
985fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
975fn fmtWipMir(func: *Func, inst: Mir.Inst.Index) std.fmt.Formatter(FormatWipMirData, formatWipMir) {
986976 return .{ .data = .{ .func = func, .inst = inst } };
987977}
988978
......@@ -990,15 +980,10 @@ const FormatNavData = struct {
990980 ip: *const InternPool,
991981 nav_index: InternPool.Nav.Index,
992982};
993fn formatNav(
994 data: FormatNavData,
995 comptime _: []const u8,
996 _: std.fmt.FormatOptions,
997 writer: anytype,
998) @TypeOf(writer).Error!void {
999 try writer.print("{}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)});
1000}
1001fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) {
983fn formatNav(data: FormatNavData, writer: *std.io.Writer) std.io.Writer.Error!void {
984 try writer.print("{f}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)});
985}
986fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(FormatNavData, formatNav) {
1002987 return .{ .data = .{
1003988 .ip = ip,
1004989 .nav_index = nav_index,
......@@ -1009,31 +994,25 @@ const FormatAirData = struct {
1009994 func: *Func,
1010995 inst: Air.Inst.Index,
1011996};
1012fn formatAir(
1013 data: FormatAirData,
1014 comptime _: []const u8,
1015 _: std.fmt.FormatOptions,
1016 writer: anytype,
1017) @TypeOf(writer).Error!void {
1018 data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness);
1019}
1020fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
997fn formatAir(data: FormatAirData, writer: *std.io.Writer) std.io.Writer.Error!void {
998 // Not acceptable implementation because it ignores `writer`:
999 //data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness);
1000 _ = data;
1001 _ = writer;
1002 @panic("unimplemented");
1003}
1004fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {
10211005 return .{ .data = .{ .func = func, .inst = inst } };
10221006}
10231007
10241008const FormatTrackingData = struct {
10251009 func: *Func,
10261010};
1027fn formatTracking(
1028 data: FormatTrackingData,
1029 comptime _: []const u8,
1030 _: std.fmt.FormatOptions,
1031 writer: anytype,
1032) @TypeOf(writer).Error!void {
1011fn formatTracking(data: FormatTrackingData, writer: *std.io.Writer) std.io.Writer.Error!void {
10331012 var it = data.func.inst_tracking.iterator();
1034 while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* });
1013 while (it.next()) |entry| try writer.print("\n%{d} = {f}", .{ entry.key_ptr.*, entry.value_ptr.* });
10351014}
1036fn fmtTracking(func: *Func) std.fmt.Formatter(formatTracking) {
1015fn fmtTracking(func: *Func) std.fmt.Formatter(FormatTrackingData, formatTracking) {
10371016 return .{ .data = .{ .func = func } };
10381017}
10391018
......@@ -1049,7 +1028,7 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
10491028 .pseudo_dbg_epilogue_begin,
10501029 .pseudo_dead,
10511030 => false,
1052 }) wip_mir_log.debug("{}", .{func.fmtWipMir(result_index)});
1031 }) wip_mir_log.debug("{f}", .{func.fmtWipMir(result_index)});
10531032 return result_index;
10541033}
10551034
......@@ -1303,7 +1282,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
13031282 switch (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu)) {
13041283 .@"enum" => {
13051284 const enum_ty = Type.fromInterned(lazy_sym.ty);
1306 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)});
1285 wip_mir_log.debug("{f}.@tagName:", .{enum_ty.fmt(pt)});
13071286
13081287 const param_regs = abi.Registers.Integer.function_arg_regs;
13091288 const ret_reg = param_regs[0];
......@@ -1385,7 +1364,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
13851364 });
13861365 },
13871366 else => return func.fail(
1388 "TODO implement {s} for {}",
1367 "TODO implement {s} for {f}",
13891368 .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) },
13901369 ),
13911370 }
......@@ -1399,8 +1378,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13991378
14001379 for (body) |inst| {
14011380 if (func.liveness.isUnused(inst) and !func.air.mustLower(inst, ip)) continue;
1402 wip_mir_log.debug("{}", .{func.fmtAir(inst)});
1403 verbose_tracking_log.debug("{}", .{func.fmtTracking()});
1381 wip_mir_log.debug("{f}", .{func.fmtAir(inst)});
1382 verbose_tracking_log.debug("{f}", .{func.fmtTracking()});
14041383
14051384 const old_air_bookkeeping = func.air_bookkeeping;
14061385 try func.ensureProcessDeathCapacity(Air.Liveness.bpi);
......@@ -1679,18 +1658,18 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
16791658 var it = func.register_manager.free_registers.iterator(.{ .kind = .unset });
16801659 while (it.next()) |index| {
16811660 const tracked_inst = func.register_manager.registers[index];
1682 tracking_log.debug("tracked inst: {}", .{tracked_inst});
1661 tracking_log.debug("tracked inst: {f}", .{tracked_inst});
16831662 const tracking = func.getResolvedInstValue(tracked_inst);
16841663 for (tracking.getRegs()) |reg| {
16851664 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
16861665 } else return std.debug.panic(
1687 \\%{} takes up these regs: {any}, however this regs {any}, don't use it
1666 \\%{f} takes up these regs: {any}, however this regs {any}, don't use it
16881667 , .{ tracked_inst, tracking.getRegs(), RegisterManager.regAtTrackedIndex(@intCast(index)) });
16891668 }
16901669 }
16911670 }
16921671 }
1693 verbose_tracking_log.debug("{}", .{func.fmtTracking()});
1672 verbose_tracking_log.debug("{f}", .{func.fmtTracking()});
16941673}
16951674
16961675fn getValue(func: *Func, value: MCValue, inst: ?Air.Inst.Index) !void {
......@@ -1713,7 +1692,7 @@ fn freeValue(func: *Func, value: MCValue) !void {
17131692
17141693fn feed(func: *Func, bt: *Air.Liveness.BigTomb, operand: Air.Inst.Ref) !void {
17151694 if (bt.feed()) if (operand.toIndex()) |inst| {
1716 log.debug("feed inst: %{}", .{inst});
1695 log.debug("feed inst: %{f}", .{inst});
17171696 try func.processDeath(inst);
17181697 };
17191698}
......@@ -1843,7 +1822,7 @@ fn computeFrameLayout(func: *Func) !FrameLayout {
18431822 total_alloc_size + 64 + args_frame_size + spill_frame_size + call_frame_size,
18441823 @intCast(frame_align[@intFromEnum(FrameIndex.base_ptr)].toByteUnits().?),
18451824 );
1846 log.debug("frame size: {}", .{acc_frame_size});
1825 log.debug("frame size: {d}", .{acc_frame_size});
18471826
18481827 // store the ra at total_size - 8, so it's the very first thing in the stack
18491828 // relative to the fp
......@@ -1907,7 +1886,7 @@ fn splitType(func: *Func, ty: Type) ![2]Type {
19071886 else => return func.fail("TODO: splitType class {}", .{class}),
19081887 };
19091888 } else if (parts[0].abiSize(zcu) + parts[1].abiSize(zcu) == ty.abiSize(zcu)) return parts;
1910 return func.fail("TODO implement splitType for {}", .{ty.fmt(func.pt)});
1889 return func.fail("TODO implement splitType for {f}", .{ty.fmt(func.pt)});
19111890}
19121891
19131892/// Truncates the value in the register in place.
......@@ -2020,7 +1999,7 @@ fn allocMemPtr(func: *Func, inst: Air.Inst.Index) !FrameIndex {
20201999 const val_ty = ptr_ty.childType(zcu);
20212000 return func.allocFrameIndex(FrameAlloc.init(.{
20222001 .size = math.cast(u32, val_ty.abiSize(zcu)) orelse {
2023 return func.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(pt)});
2002 return func.fail("type '{f}' too big to fit into stack frame", .{val_ty.fmt(pt)});
20242003 },
20252004 .alignment = ptr_ty.ptrAlignment(zcu).max(.@"1"),
20262005 }));
......@@ -2160,7 +2139,7 @@ pub fn spillRegisters(func: *Func, comptime registers: []const Register) !void {
21602139/// allocated. A second call to `copyToTmpRegister` may return the same register.
21612140/// This can have a side effect of spilling instructions to the stack to free up a register.
21622141fn copyToTmpRegister(func: *Func, ty: Type, mcv: MCValue) !Register {
2163 log.debug("copyToTmpRegister ty: {}", .{ty.fmt(func.pt)});
2142 log.debug("copyToTmpRegister ty: {f}", .{ty.fmt(func.pt)});
21642143 const reg = try func.register_manager.allocReg(null, func.regTempClassForType(ty));
21652144 try func.genSetReg(ty, reg, mcv);
21662145 return reg;
......@@ -2245,7 +2224,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void {
22452224 break :result null; // TODO
22462225
22472226 break :result dst_mcv;
2248 } orelse return func.fail("TODO: implement airIntCast from {} to {}", .{
2227 } orelse return func.fail("TODO: implement airIntCast from {f} to {f}", .{
22492228 src_ty.fmt(pt), dst_ty.fmt(pt),
22502229 });
22512230
......@@ -2633,7 +2612,7 @@ fn genBinOp(
26332612 .add_sat,
26342613 => {
26352614 if (bit_size != 64 or !is_unsigned)
2636 return func.fail("TODO: genBinOp ty: {}", .{lhs_ty.fmt(pt)});
2615 return func.fail("TODO: genBinOp ty: {f}", .{lhs_ty.fmt(pt)});
26372616
26382617 const tmp_reg = try func.copyToTmpRegister(rhs_ty, .{ .register = rhs_reg });
26392618 const tmp_lock = func.register_manager.lockRegAssumeUnused(tmp_reg);
......@@ -4065,7 +4044,7 @@ fn airGetUnionTag(func: *Func, inst: Air.Inst.Index) !void {
40654044 );
40664045 } else {
40674046 return func.fail(
4068 "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {}",
4047 "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}, tag {f}",
40694048 .{ frame_mcv, tag_ty.fmt(pt) },
40704049 );
40714050 }
......@@ -4186,7 +4165,7 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
41864165
41874166 switch (scalar_ty.zigTypeTag(zcu)) {
41884167 .int => if (ty.zigTypeTag(zcu) == .vector) {
4189 return func.fail("TODO implement airAbs for {}", .{ty.fmt(pt)});
4168 return func.fail("TODO implement airAbs for {f}", .{ty.fmt(pt)});
41904169 } else {
41914170 const int_info = scalar_ty.intInfo(zcu);
41924171 const int_bits = int_info.bits;
......@@ -4267,7 +4246,7 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
42674246
42684247 break :result return_mcv;
42694248 },
4270 else => return func.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(pt)}),
4249 else => return func.fail("TODO: implement airAbs {f}", .{scalar_ty.fmt(pt)}),
42714250 }
42724251
42734252 break :result .unreach;
......@@ -4331,7 +4310,7 @@ fn airByteSwap(func: *Func, inst: Air.Inst.Index) !void {
43314310
43324311 break :result dest_mcv;
43334312 },
4334 else => return func.fail("TODO: airByteSwap {}", .{ty.fmt(pt)}),
4313 else => return func.fail("TODO: airByteSwap {f}", .{ty.fmt(pt)}),
43354314 }
43364315 };
43374316 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -4397,7 +4376,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
43974376 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),
43984377 }
43994378 },
4400 else => return func.fail("TODO: airUnaryMath ty: {}", .{ty.fmt(pt)}),
4379 else => return func.fail("TODO: airUnaryMath ty: {f}", .{ty.fmt(pt)}),
44014380 }
44024381
44034382 break :result MCValue{ .register = dst_reg };
......@@ -4497,7 +4476,7 @@ fn load(func: *Func, dst_mcv: MCValue, ptr_mcv: MCValue, ptr_ty: Type) InnerErro
44974476 const zcu = pt.zcu;
44984477 const dst_ty = ptr_ty.childType(zcu);
44994478
4500 log.debug("loading {}:{} into {}", .{ ptr_mcv, ptr_ty.fmt(pt), dst_mcv });
4479 log.debug("loading {}:{f} into {}", .{ ptr_mcv, ptr_ty.fmt(pt), dst_mcv });
45014480
45024481 switch (ptr_mcv) {
45034482 .none,
......@@ -4550,7 +4529,7 @@ fn airStore(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
45504529fn store(func: *Func, ptr_mcv: MCValue, src_mcv: MCValue, ptr_ty: Type) !void {
45514530 const zcu = func.pt.zcu;
45524531 const src_ty = ptr_ty.childType(zcu);
4553 log.debug("storing {}:{} in {}:{}", .{ src_mcv, src_ty.fmt(func.pt), ptr_mcv, ptr_ty.fmt(func.pt) });
4532 log.debug("storing {}:{f} in {}:{f}", .{ src_mcv, src_ty.fmt(func.pt), ptr_mcv, ptr_ty.fmt(func.pt) });
45544533
45554534 switch (ptr_mcv) {
45564535 .none => unreachable,
......@@ -7305,7 +7284,7 @@ fn airBitCast(func: *Func, inst: Air.Inst.Index) !void {
73057284 const bit_size = dst_ty.bitSize(zcu);
73067285 if (abi_size * 8 <= bit_size) break :result dst_mcv;
73077286
7308 return func.fail("TODO: airBitCast {} to {}", .{ src_ty.fmt(pt), dst_ty.fmt(pt) });
7287 return func.fail("TODO: airBitCast {f} to {f}", .{ src_ty.fmt(pt), dst_ty.fmt(pt) });
73097288 };
73107289 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
73117290}
......@@ -8121,7 +8100,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void {
81218100 );
81228101 break :result .{ .load_frame = .{ .index = frame_index } };
81238102 },
8124 else => return func.fail("TODO: airAggregate {}", .{result_ty.fmt(pt)}),
8103 else => return func.fail("TODO: airAggregate {f}", .{result_ty.fmt(pt)}),
81258104 }
81268105 };
81278106
......@@ -8322,7 +8301,7 @@ fn resolveCallingConventionValues(
83228301 };
83238302
83248303 result.return_value = switch (ret_tracking_i) {
8325 else => return func.fail("ty {} took {} tracking return indices", .{ ret_ty.fmt(pt), ret_tracking_i }),
8304 else => return func.fail("ty {f} took {} tracking return indices", .{ ret_ty.fmt(pt), ret_tracking_i }),
83268305 1 => ret_tracking[0],
83278306 2 => InstTracking.init(.{ .register_pair = .{
83288307 ret_tracking[0].short.register, ret_tracking[1].short.register,
......@@ -8377,7 +8356,7 @@ fn resolveCallingConventionValues(
83778356 else => return func.fail("TODO: C calling convention arg class {}", .{class}),
83788357 } else {
83798358 arg.* = switch (arg_mcv_i) {
8380 else => return func.fail("ty {} took {} tracking arg indices", .{ ty.fmt(pt), arg_mcv_i }),
8359 else => return func.fail("ty {f} took {} tracking arg indices", .{ ty.fmt(pt), arg_mcv_i }),
83818360 1 => arg_mcv[0],
83828361 2 => .{ .register_pair = .{ arg_mcv[0].register, arg_mcv[1].register } },
83838362 };
src/arch/riscv64/Emit.zig+1-1
......@@ -172,7 +172,7 @@ const Reloc = struct {
172172
173173fn fixupRelocs(emit: *Emit) Error!void {
174174 for (emit.relocs.items) |reloc| {
175 log.debug("target inst: {}", .{emit.lower.mir.instructions.get(reloc.target)});
175 log.debug("target inst: {f}", .{emit.lower.mir.instructions.get(reloc.target)});
176176 const target = emit.code_offset_mapping.get(reloc.target) orelse
177177 return emit.fail("relocation target not found!", .{});
178178
src/arch/riscv64/Lower.zig+1-1
......@@ -61,7 +61,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
6161 defer lower.result_relocs_len = undefined;
6262
6363 const inst = lower.mir.instructions.get(index);
64 log.debug("lowerMir {}", .{inst});
64 log.debug("lowerMir {f}", .{inst});
6565 switch (inst.tag) {
6666 else => try lower.generic(inst),
6767 .pseudo_dbg_line_column,
src/arch/riscv64/Mir.zig+1-7
......@@ -92,13 +92,7 @@ pub const Inst = struct {
9292 },
9393 };
9494
95 pub fn format(
96 inst: Inst,
97 comptime fmt: []const u8,
98 _: std.fmt.FormatOptions,
99 writer: anytype,
100 ) !void {
101 assert(fmt.len == 0);
95 pub fn format(inst: Inst, writer: *std.io.Writer) std.io.Writer.Error!void {
10296 try writer.print("Tag: {s}, Data: {s}", .{ @tagName(inst.tag), @tagName(inst.data) });
10397 }
10498};
src/arch/riscv64/bits.zig-17
......@@ -255,23 +255,6 @@ pub const FrameIndex = enum(u32) {
255255 pub fn isNamed(fi: FrameIndex) bool {
256256 return @intFromEnum(fi) < named_count;
257257 }
258
259 pub fn format(
260 fi: FrameIndex,
261 comptime fmt: []const u8,
262 options: std.fmt.FormatOptions,
263 writer: anytype,
264 ) @TypeOf(writer).Error!void {
265 try writer.writeAll("FrameIndex");
266 if (fi.isNamed()) {
267 try writer.writeByte('.');
268 try writer.writeAll(@tagName(fi));
269 } else {
270 try writer.writeByte('(');
271 try std.fmt.formatType(@intFromEnum(fi), fmt, options, writer, 0);
272 try writer.writeByte(')');
273 }
274 }
275258};
276259
277260/// A linker symbol not yet allocated in VM.
src/arch/sparc64/CodeGen.zig+6-6
......@@ -723,7 +723,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
723723
724724 if (std.debug.runtime_safety) {
725725 if (self.air_bookkeeping < old_air_bookkeeping + 1) {
726 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[@intFromEnum(inst)] });
726 std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{t}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[@intFromEnum(inst)] });
727727 }
728728 }
729729 }
......@@ -1001,7 +1001,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void {
10011001 switch (self.args[arg_index]) {
10021002 .stack_offset => |off| {
10031003 const abi_size = math.cast(u32, ty.abiSize(zcu)) orelse {
1004 return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(pt)});
1004 return self.fail("type '{f}' too big to fit into stack frame", .{ty.fmt(pt)});
10051005 };
10061006 const offset = off + abi_size;
10071007 break :blk .{ .stack_offset = offset };
......@@ -2748,7 +2748,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
27482748 }
27492749
27502750 const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse {
2751 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)});
2751 return self.fail("type '{f}' too big to fit into stack frame", .{elem_ty.fmt(pt)});
27522752 };
27532753 // TODO swap this for inst.ty.ptrAlign
27542754 const abi_align = elem_ty.abiAlignment(zcu);
......@@ -2760,7 +2760,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
27602760 const zcu = pt.zcu;
27612761 const elem_ty = self.typeOfIndex(inst);
27622762 const abi_size = math.cast(u32, elem_ty.abiSize(zcu)) orelse {
2763 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(pt)});
2763 return self.fail("type '{f}' too big to fit into stack frame", .{elem_ty.fmt(pt)});
27642764 };
27652765 const abi_align = elem_ty.abiAlignment(zcu);
27662766 self.stack_align = self.stack_align.max(abi_align);
......@@ -4111,7 +4111,7 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
41114111 while (true) {
41124112 i -= 1;
41134113 if (self.branch_stack.items[i].inst_table.get(inst)) |mcv| {
4114 log.debug("getResolvedInstValue %{} => {}", .{ inst, mcv });
4114 log.debug("getResolvedInstValue %{f} => {}", .{ inst, mcv });
41154115 assert(mcv != .dead);
41164116 return mcv;
41174117 }
......@@ -4382,7 +4382,7 @@ fn processDeath(self: *Self, inst: Air.Inst.Index) void {
43824382 const prev_value = self.getResolvedInstValue(inst);
43834383 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
43844384 branch.inst_table.putAssumeCapacity(inst, .dead);
4385 log.debug("%{} death: {} -> .dead", .{ inst, prev_value });
4385 log.debug("%{f} death: {} -> .dead", .{ inst, prev_value });
43864386 switch (prev_value) {
43874387 .register => |reg| {
43884388 self.register_manager.freeReg(reg);
src/arch/wasm/CodeGen.zig+19-26
......@@ -1463,7 +1463,7 @@ fn allocStack(cg: *CodeGen, ty: Type) !WValue {
14631463 }
14641464
14651465 const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse {
1466 return cg.fail("Type {} with ABI size of {d} exceeds stack frame size", .{
1466 return cg.fail("Type {f} with ABI size of {d} exceeds stack frame size", .{
14671467 ty.fmt(pt), ty.abiSize(zcu),
14681468 });
14691469 };
......@@ -1497,7 +1497,7 @@ fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue {
14971497
14981498 const abi_alignment = ptr_ty.ptrAlignment(zcu);
14991499 const abi_size = std.math.cast(u32, pointee_ty.abiSize(zcu)) orelse {
1500 return cg.fail("Type {} with ABI size of {d} exceeds stack frame size", .{
1500 return cg.fail("Type {f} with ABI size of {d} exceeds stack frame size", .{
15011501 pointee_ty.fmt(pt), pointee_ty.abiSize(zcu),
15021502 });
15031503 };
......@@ -1959,7 +1959,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
19591959 .wasm_memory_size => cg.airWasmMemorySize(inst),
19601960 .wasm_memory_grow => cg.airWasmMemoryGrow(inst),
19611961
1962 .memcpy => cg.airMemcpy(inst),
1962 .memcpy, .memmove => cg.airMemcpy(inst),
19631963
19641964 .ret_addr => cg.airRetAddr(inst),
19651965 .tag_name => cg.airTagName(inst),
......@@ -1983,7 +1983,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
19831983 .c_va_copy,
19841984 .c_va_end,
19851985 .c_va_start,
1986 .memmove,
19871986 => |tag| return cg.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
19881987
19891988 .atomic_load => cg.airAtomicLoad(inst),
......@@ -2046,7 +2045,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
20462045 try cg.genInst(inst);
20472046
20482047 if (std.debug.runtime_safety and cg.air_bookkeeping < old_bookkeeping_value + 1) {
2049 std.debug.panic("Missing call to `finishAir` in AIR instruction %{d} ('{}')", .{
2048 std.debug.panic("Missing call to `finishAir` in AIR instruction %{d} ('{t}')", .{
20502049 inst,
20512050 cg.air.instructions.items(.tag)[@intFromEnum(inst)],
20522051 });
......@@ -2404,10 +2403,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr
24042403 try cg.memcpy(lhs, rhs, .{ .imm32 = @as(u32, @intCast(ty.abiSize(zcu))) });
24052404 },
24062405 else => if (abi_size > 8) {
2407 return cg.fail("TODO: `store` for type `{}` with abisize `{d}`", .{
2408 ty.fmt(pt),
2409 abi_size,
2410 });
2406 return cg.fail("TODO: `store` for type `{f}` with abisize `{d}`", .{ ty.fmt(pt), abi_size });
24112407 },
24122408 }
24132409 try cg.emitWValue(lhs);
......@@ -2596,10 +2592,7 @@ fn binOp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WV
25962592 if (ty.zigTypeTag(zcu) == .int) {
25972593 return cg.binOpBigInt(lhs, rhs, ty, op);
25982594 } else {
2599 return cg.fail(
2600 "TODO: Implement binary operation for type: {}",
2601 .{ty.fmt(pt)},
2602 );
2595 return cg.fail("TODO: Implement binary operation for type: {f}", .{ty.fmt(pt)});
26032596 }
26042597 }
26052598
......@@ -2817,7 +2810,7 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
28172810
28182811 switch (scalar_ty.zigTypeTag(zcu)) {
28192812 .int => if (ty.zigTypeTag(zcu) == .vector) {
2820 return cg.fail("TODO implement airAbs for {}", .{ty.fmt(pt)});
2813 return cg.fail("TODO implement airAbs for {f}", .{ty.fmt(pt)});
28212814 } else {
28222815 const int_bits = ty.intInfo(zcu).bits;
28232816 const wasm_bits = toWasmBits(int_bits) orelse {
......@@ -3244,7 +3237,7 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
32443237 return .{ .imm32 = @intFromBool(!val.isNull(zcu)) };
32453238 },
32463239 .aggregate => switch (ip.indexToKey(ty.ip_index)) {
3247 .array_type => return cg.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(pt)}),
3240 .array_type => return cg.fail("Wasm TODO: LowerConstant for {f}", .{ty.fmt(pt)}),
32483241 .vector_type => {
32493242 assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct);
32503243 var buf: [16]u8 = undefined;
......@@ -3332,7 +3325,7 @@ fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {
33323325 },
33333326 else => unreachable,
33343327 },
3335 else => return cg.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(zcu)}),
3328 else => return cg.fail("Wasm TODO: emitUndefined for type: {t}\n", .{ty.zigTypeTag(zcu)}),
33363329 }
33373330}
33383331
......@@ -3608,7 +3601,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
36083601 } else {
36093602 const int_info = operand_ty.intInfo(zcu);
36103603 const wasm_bits = toWasmBits(int_info.bits) orelse {
3611 return cg.fail("TODO: Implement binary NOT for {}", .{operand_ty.fmt(pt)});
3604 return cg.fail("TODO: Implement binary NOT for {f}", .{operand_ty.fmt(pt)});
36123605 };
36133606
36143607 switch (wasm_bits) {
......@@ -3874,7 +3867,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
38743867 },
38753868 else => result: {
38763869 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, zcu)) orelse {
3877 return cg.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(pt)});
3870 return cg.fail("Field type '{f}' too big to fit into stack frame", .{field_ty.fmt(pt)});
38783871 };
38793872 if (isByRef(field_ty, zcu, cg.target)) {
38803873 switch (operand) {
......@@ -4360,7 +4353,7 @@ fn isNull(cg: *CodeGen, operand: WValue, optional_ty: Type, opcode: std.wasm.Opc
43604353 // a pointer to the stack value
43614354 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
43624355 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {
4363 return cg.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(pt)});
4356 return cg.fail("Optional type {f} too big to fit into stack frame", .{optional_ty.fmt(pt)});
43644357 };
43654358 try cg.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 });
43664359 }
......@@ -4430,7 +4423,7 @@ fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void
44304423 }
44314424
44324425 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {
4433 return cg.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(pt)});
4426 return cg.fail("Optional type {f} too big to fit into stack frame", .{opt_ty.fmt(pt)});
44344427 };
44354428
44364429 try cg.emitWValue(operand);
......@@ -4462,7 +4455,7 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
44624455 break :result cg.reuseOperand(ty_op.operand, operand);
44634456 }
44644457 const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {
4465 return cg.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(pt)});
4458 return cg.fail("Optional type {f} too big to fit into stack frame", .{op_ty.fmt(pt)});
44664459 };
44674460
44684461 // Create optional type, set the non-null bit, and store the operand inside the optional type
......@@ -6196,7 +6189,7 @@ fn airMulWithOverflow(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
61966189 _ = try cg.load(overflow_ret, Type.i32, 0);
61976190 try cg.addLocal(.local_set, overflow_bit.local.value);
61986191 break :blk res;
6199 } else return cg.fail("TODO: @mulWithOverflow for {}", .{ty.fmt(pt)});
6192 } else return cg.fail("TODO: @mulWithOverflow for {f}", .{ty.fmt(pt)});
62006193 var bin_op_local = try mul.toLocal(cg, ty);
62016194 defer bin_op_local.free(cg);
62026195
......@@ -6749,7 +6742,7 @@ fn airMod(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
67496742 const add = try cg.binOp(rem, rhs, ty, .add);
67506743 break :result try cg.binOp(add, rhs, ty, .rem);
67516744 }
6752 return cg.fail("TODO: @mod for {}", .{ty.fmt(pt)});
6745 return cg.fail("TODO: @mod for {f}", .{ty.fmt(pt)});
67536746 };
67546747
67556748 return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs });
......@@ -6767,7 +6760,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
67676760 const lhs = try cg.resolveInst(bin_op.lhs);
67686761 const rhs = try cg.resolveInst(bin_op.rhs);
67696762 const wasm_bits = toWasmBits(int_info.bits) orelse {
6770 return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});
6763 return cg.fail("TODO: mul_sat for {f}", .{ty.fmt(pt)});
67716764 };
67726765
67736766 switch (wasm_bits) {
......@@ -6804,7 +6797,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
68046797 },
68056798 64 => {
68066799 if (!(int_info.bits == 64 and int_info.signedness == .signed)) {
6807 return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});
6800 return cg.fail("TODO: mul_sat for {f}", .{ty.fmt(pt)});
68086801 }
68096802 const overflow_ret = try cg.allocStack(Type.i32);
68106803 _ = try cg.callIntrinsic(
......@@ -6822,7 +6815,7 @@ fn airSatMul(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
68226815 },
68236816 128 => {
68246817 if (!(int_info.bits == 128 and int_info.signedness == .signed)) {
6825 return cg.fail("TODO: mul_sat for {}", .{ty.fmt(pt)});
6818 return cg.fail("TODO: mul_sat for {f}", .{ty.fmt(pt)});
68266819 }
68276820 const overflow_ret = try cg.allocStack(Type.i32);
68286821 const ret = try cg.callIntrinsic(
src/arch/x86_64/CodeGen.zig+226-256
......@@ -6,6 +6,7 @@ const log = std.log.scoped(.codegen);
66const tracking_log = std.log.scoped(.tracking);
77const verbose_tracking_log = std.log.scoped(.verbose_tracking);
88const wip_mir_log = std.log.scoped(.wip_mir);
9const Writer = std.io.Writer;
910
1011const Air = @import("../../Air.zig");
1112const Allocator = std.mem.Allocator;
......@@ -524,52 +525,47 @@ pub const MCValue = union(enum) {
524525 };
525526 }
526527
527 pub fn format(
528 mcv: MCValue,
529 comptime _: []const u8,
530 _: std.fmt.FormatOptions,
531 writer: anytype,
532 ) @TypeOf(writer).Error!void {
528 pub fn format(mcv: MCValue, w: *Writer) Writer.Error!void {
533529 switch (mcv) {
534 .none, .unreach, .dead, .undef => try writer.print("({s})", .{@tagName(mcv)}),
535 .immediate => |pl| try writer.print("0x{x}", .{pl}),
536 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),
537 inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),
538 .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),
539 .register_triple => |pl| try writer.print("{s}:{s}:{s}", .{
530 .none, .unreach, .dead, .undef => try w.print("({s})", .{@tagName(mcv)}),
531 .immediate => |pl| try w.print("0x{x}", .{pl}),
532 .memory => |pl| try w.print("[ds:0x{x}]", .{pl}),
533 inline .eflags, .register => |pl| try w.print("{s}", .{@tagName(pl)}),
534 .register_pair => |pl| try w.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),
535 .register_triple => |pl| try w.print("{s}:{s}:{s}", .{
540536 @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]),
541537 }),
542 .register_quadruple => |pl| try writer.print("{s}:{s}:{s}:{s}", .{
538 .register_quadruple => |pl| try w.print("{s}:{s}:{s}:{s}", .{
543539 @tagName(pl[3]), @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]),
544540 }),
545 .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),
546 .register_overflow => |pl| try writer.print("{s}:{s}", .{
541 .register_offset => |pl| try w.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),
542 .register_overflow => |pl| try w.print("{s}:{s}", .{
547543 @tagName(pl.eflags),
548544 @tagName(pl.reg),
549545 }),
550 .register_mask => |pl| try writer.print("mask({s},{}):{c}{s}", .{
546 .register_mask => |pl| try w.print("mask({s},{f}):{c}{s}", .{
551547 @tagName(pl.info.kind),
552548 pl.info.scalar,
553549 @as(u8, if (pl.info.inverted) '!' else ' '),
554550 @tagName(pl.reg),
555551 }),
556 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
557 .indirect_load_frame => |pl| try writer.print("[[{} + 0x{x}]]", .{ pl.index, pl.off }),
558 .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
559 .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }),
560 .load_nav => |pl| try writer.print("[nav:{d}]", .{@intFromEnum(pl)}),
561 .lea_nav => |pl| try writer.print("nav:{d}", .{@intFromEnum(pl)}),
562 .load_uav => |pl| try writer.print("[uav:{d}]", .{@intFromEnum(pl.val)}),
563 .lea_uav => |pl| try writer.print("uav:{d}", .{@intFromEnum(pl.val)}),
564 .load_lazy_sym => |pl| try writer.print("[lazy:{s}:{d}]", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }),
565 .lea_lazy_sym => |pl| try writer.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }),
566 .load_extern_func => |pl| try writer.print("[extern:{d}]", .{@intFromEnum(pl)}),
567 .lea_extern_func => |pl| try writer.print("extern:{d}", .{@intFromEnum(pl)}),
568 .elementwise_args => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{
552 .indirect => |pl| try w.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
553 .indirect_load_frame => |pl| try w.print("[[{} + 0x{x}]]", .{ pl.index, pl.off }),
554 .load_frame => |pl| try w.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
555 .lea_frame => |pl| try w.print("{} + 0x{x}", .{ pl.index, pl.off }),
556 .load_nav => |pl| try w.print("[nav:{d}]", .{@intFromEnum(pl)}),
557 .lea_nav => |pl| try w.print("nav:{d}", .{@intFromEnum(pl)}),
558 .load_uav => |pl| try w.print("[uav:{d}]", .{@intFromEnum(pl.val)}),
559 .lea_uav => |pl| try w.print("uav:{d}", .{@intFromEnum(pl.val)}),
560 .load_lazy_sym => |pl| try w.print("[lazy:{s}:{d}]", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }),
561 .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }),
562 .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}),
563 .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}),
564 .elementwise_args => |pl| try w.print("elementwise:{d}:[{} + 0x{x}]", .{
569565 pl.regs, pl.frame_index, pl.frame_off,
570566 }),
571 .reserved_frame => |pl| try writer.print("(dead:{})", .{pl}),
572 .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}),
567 .reserved_frame => |pl| try w.print("(dead:{})", .{pl}),
568 .air_ref => |pl| try w.print("(air:0x{x})", .{@intFromEnum(pl)}),
573569 }
574570 }
575571};
......@@ -639,7 +635,7 @@ const InstTracking = struct {
639635 .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } },
640636 else => unreachable,
641637 }
642 tracking_log.debug("spill {} from {} to {}", .{ inst, self.short, self.long });
638 tracking_log.debug("spill {f} from {f} to {f}", .{ inst, self.short, self.long });
643639 try cg.genCopy(cg.typeOfIndex(inst), self.long, self.short, .{});
644640 for (self.short.getRegs()) |reg| if (reg.isClass(.x87)) try cg.asmRegister(.{ .f_, .free }, reg);
645641 }
......@@ -672,7 +668,7 @@ const InstTracking = struct {
672668 else => {}, // TODO process stack allocation death
673669 }
674670 self.reuseFrame();
675 tracking_log.debug("{} => {} (spilled)", .{ inst, self.* });
671 tracking_log.debug("{f} => {f} (spilled)", .{ inst, self.* });
676672 }
677673
678674 fn verifyMaterialize(self: InstTracking, target: InstTracking) void {
......@@ -749,7 +745,7 @@ const InstTracking = struct {
749745 else => target.long,
750746 } else target.long;
751747 self.short = target.short;
752 tracking_log.debug("{} => {} (materialize)", .{ inst, self.* });
748 tracking_log.debug("{f} => {f} (materialize)", .{ inst, self.* });
753749 }
754750
755751 fn resurrect(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index, scope_generation: u32) !void {
......@@ -757,7 +753,7 @@ const InstTracking = struct {
757753 .dead => |die_generation| if (die_generation >= scope_generation) {
758754 self.reuseFrame();
759755 try function.getValue(self.short, inst);
760 tracking_log.debug("{} => {} (resurrect)", .{ inst, self.* });
756 tracking_log.debug("{f} => {f} (resurrect)", .{ inst, self.* });
761757 },
762758 else => {},
763759 }
......@@ -768,7 +764,7 @@ const InstTracking = struct {
768764 try function.freeValue(self.short, opts);
769765 if (self.long == .none) self.long = self.short;
770766 self.short = .{ .dead = function.scope_generation };
771 tracking_log.debug("{} => {} (death)", .{ inst, self.* });
767 tracking_log.debug("{f} => {f} (death)", .{ inst, self.* });
772768 }
773769
774770 fn reuse(
......@@ -778,13 +774,13 @@ const InstTracking = struct {
778774 old_inst: Air.Inst.Index,
779775 ) void {
780776 self.short = .{ .dead = function.scope_generation };
781 tracking_log.debug("{?} => {} (reuse {})", .{ new_inst, self.*, old_inst });
777 tracking_log.debug("{?f} => {f} (reuse {f})", .{ new_inst, self.*, old_inst });
782778 }
783779
784780 fn liveOut(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) void {
785781 for (self.getRegs()) |reg| {
786782 if (function.register_manager.isRegFree(reg)) {
787 tracking_log.debug("{} => {} (live-out)", .{ inst, self.* });
783 tracking_log.debug("{f} => {f} (live-out)", .{ inst, self.* });
788784 continue;
789785 }
790786
......@@ -812,18 +808,13 @@ const InstTracking = struct {
812808 // Perform side-effects of freeValue manually.
813809 function.register_manager.freeReg(reg);
814810
815 tracking_log.debug("{} => {} (live-out {})", .{ inst, self.*, tracked_inst });
811 tracking_log.debug("{f} => {f} (live-out {f})", .{ inst, self.*, tracked_inst });
816812 }
817813 }
818814
819 pub fn format(
820 tracking: InstTracking,
821 comptime _: []const u8,
822 _: std.fmt.FormatOptions,
823 writer: anytype,
824 ) @TypeOf(writer).Error!void {
825 if (!std.meta.eql(tracking.long, tracking.short)) try writer.print("|{}| ", .{tracking.long});
826 try writer.print("{}", .{tracking.short});
815 pub fn format(tracking: InstTracking, bw: *Writer) Writer.Error!void {
816 if (!std.meta.eql(tracking.long, tracking.short)) try bw.print("|{f}| ", .{tracking.long});
817 try bw.print("{f}", .{tracking.short});
827818 }
828819};
829820
......@@ -939,7 +930,7 @@ pub fn generate(
939930 function.inst_tracking.putAssumeCapacityNoClobber(temp.toIndex(), .init(.none));
940931 }
941932
942 wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
933 wip_mir_log.debug("{f}:", .{fmtNav(func.owner_nav, ip)});
943934
944935 try function.frame_allocs.resize(gpa, FrameIndex.named_count);
945936 function.frame_allocs.set(
......@@ -1097,15 +1088,10 @@ const FormatNavData = struct {
10971088 ip: *const InternPool,
10981089 nav_index: InternPool.Nav.Index,
10991090};
1100fn formatNav(
1101 data: FormatNavData,
1102 comptime _: []const u8,
1103 _: std.fmt.FormatOptions,
1104 writer: anytype,
1105) @TypeOf(writer).Error!void {
1106 try writer.print("{}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)});
1091fn formatNav(data: FormatNavData, w: *Writer) Writer.Error!void {
1092 try w.print("{f}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)});
11071093}
1108fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) {
1094fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(FormatNavData, formatNav) {
11091095 return .{ .data = .{
11101096 .ip = ip,
11111097 .nav_index = nav_index,
......@@ -1116,15 +1102,14 @@ const FormatAirData = struct {
11161102 self: *CodeGen,
11171103 inst: Air.Inst.Index,
11181104};
1119fn formatAir(
1120 data: FormatAirData,
1121 comptime _: []const u8,
1122 _: std.fmt.FormatOptions,
1123 writer: anytype,
1124) @TypeOf(writer).Error!void {
1125 data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
1105fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void {
1106 // not acceptable implementation because it ignores `w`:
1107 //data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
1108 _ = data;
1109 _ = w;
1110 @panic("TODO: unimplemented");
11261111}
1127fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
1112fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {
11281113 return .{ .data = .{ .self = self, .inst = inst } };
11291114}
11301115
......@@ -1132,12 +1117,7 @@ const FormatWipMirData = struct {
11321117 self: *CodeGen,
11331118 inst: Mir.Inst.Index,
11341119};
1135fn formatWipMir(
1136 data: FormatWipMirData,
1137 comptime _: []const u8,
1138 _: std.fmt.FormatOptions,
1139 writer: anytype,
1140) @TypeOf(writer).Error!void {
1120fn formatWipMir(data: FormatWipMirData, w: *Writer) Writer.Error!void {
11411121 var lower: Lower = .{
11421122 .target = data.self.target,
11431123 .allocator = data.self.gpa,
......@@ -1152,27 +1132,22 @@ fn formatWipMir(
11521132 lower.err_msg.?.deinit(data.self.gpa);
11531133 lower.err_msg = null;
11541134 }
1155 try writer.writeAll(lower.err_msg.?.msg);
1135 try w.writeAll(lower.err_msg.?.msg);
11561136 return;
11571137 },
1158 error.OutOfMemory, error.InvalidInstruction, error.CannotEncode => |e| {
1159 try writer.writeAll(switch (e) {
1160 error.OutOfMemory => "Out of memory",
1161 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
1162 error.CannotEncode => "CodeGen failed to encode the instruction.",
1163 });
1138 else => |e| {
1139 try w.writeAll(@errorName(e));
11641140 return;
11651141 },
1166 else => |e| return e,
11671142 }).insts) |lowered_inst| {
1168 if (!first) try writer.writeAll("\ndebug(wip_mir): ");
1169 try writer.print(" | {}", .{lowered_inst});
1143 if (!first) try w.writeAll("\ndebug(wip_mir): ");
1144 try w.print(" | {f}", .{lowered_inst});
11701145 first = false;
11711146 }
11721147 if (first) {
11731148 const ip = &data.self.pt.zcu.intern_pool;
11741149 const mir_inst = lower.mir.instructions.get(data.inst);
1175 try writer.print(" | .{s}", .{@tagName(mir_inst.ops)});
1150 try w.print(" | .{s}", .{@tagName(mir_inst.ops)});
11761151 switch (mir_inst.ops) {
11771152 else => unreachable,
11781153 .pseudo_dbg_prologue_end_none,
......@@ -1184,20 +1159,20 @@ fn formatWipMir(
11841159 .pseudo_dbg_var_none,
11851160 .pseudo_dead_none,
11861161 => {},
1187 .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try writer.print(
1162 .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try w.print(
11881163 " {[line]d}, {[column]d}",
11891164 mir_inst.data.line_column,
11901165 ),
1191 .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try writer.print(" {}", .{
1166 .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try w.print(" {f}", .{
11921167 ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip),
11931168 }),
1194 .pseudo_dbg_arg_i_s, .pseudo_dbg_var_i_s => try writer.print(" {d}", .{
1169 .pseudo_dbg_arg_i_s, .pseudo_dbg_var_i_s => try w.print(" {d}", .{
11951170 @as(i32, @bitCast(mir_inst.data.i.i)),
11961171 }),
1197 .pseudo_dbg_arg_i_u, .pseudo_dbg_var_i_u => try writer.print(" {d}", .{
1172 .pseudo_dbg_arg_i_u, .pseudo_dbg_var_i_u => try w.print(" {d}", .{
11981173 mir_inst.data.i.i,
11991174 }),
1200 .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => try writer.print(" {d}", .{
1175 .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => try w.print(" {d}", .{
12011176 mir_inst.data.i64,
12021177 }),
12031178 .pseudo_dbg_arg_ro, .pseudo_dbg_var_ro => {
......@@ -1205,44 +1180,39 @@ fn formatWipMir(
12051180 .base = .{ .reg = mir_inst.data.ro.reg },
12061181 .disp = mir_inst.data.ro.off,
12071182 }) };
1208 try writer.print(" {}", .{mem_op.fmt(.m)});
1183 try w.print(" {f}", .{mem_op.fmt(.m)});
12091184 },
12101185 .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => {
12111186 const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{
12121187 .base = .{ .frame = mir_inst.data.fa.index },
12131188 .disp = mir_inst.data.fa.off,
12141189 }) };
1215 try writer.print(" {}", .{mem_op.fmt(.m)});
1190 try w.print(" {f}", .{mem_op.fmt(.m)});
12161191 },
12171192 .pseudo_dbg_arg_m, .pseudo_dbg_var_m => {
12181193 const mem_op: encoder.Instruction.Operand = .{
12191194 .mem = lower.mir.extraData(Mir.Memory, mir_inst.data.x.payload).data.decode(),
12201195 };
1221 try writer.print(" {}", .{mem_op.fmt(.m)});
1196 try w.print(" {f}", .{mem_op.fmt(.m)});
12221197 },
1223 .pseudo_dbg_arg_val, .pseudo_dbg_var_val => try writer.print(" {}", .{
1198 .pseudo_dbg_arg_val, .pseudo_dbg_var_val => try w.print(" {f}", .{
12241199 Value.fromInterned(mir_inst.data.ip_index).fmtValue(data.self.pt),
12251200 }),
12261201 }
12271202 }
12281203}
1229fn fmtWipMir(self: *CodeGen, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
1204fn fmtWipMir(self: *CodeGen, inst: Mir.Inst.Index) std.fmt.Formatter(FormatWipMirData, formatWipMir) {
12301205 return .{ .data = .{ .self = self, .inst = inst } };
12311206}
12321207
12331208const FormatTrackingData = struct {
12341209 self: *CodeGen,
12351210};
1236fn formatTracking(
1237 data: FormatTrackingData,
1238 comptime _: []const u8,
1239 _: std.fmt.FormatOptions,
1240 writer: anytype,
1241) @TypeOf(writer).Error!void {
1211fn formatTracking(data: FormatTrackingData, w: *Writer) Writer.Error!void {
12421212 var it = data.self.inst_tracking.iterator();
1243 while (it.next()) |entry| try writer.print("\n{} = {}", .{ entry.key_ptr.*, entry.value_ptr.* });
1213 while (it.next()) |entry| try w.print("\n{f} = {f}", .{ entry.key_ptr.*, entry.value_ptr.* });
12441214}
1245fn fmtTracking(self: *CodeGen) std.fmt.Formatter(formatTracking) {
1215fn fmtTracking(self: *CodeGen) std.fmt.Formatter(FormatTrackingData, formatTracking) {
12461216 return .{ .data = .{ .self = self } };
12471217}
12481218
......@@ -1251,7 +1221,7 @@ fn addInst(self: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
12511221 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
12521222 const result_index: Mir.Inst.Index = @intCast(self.mir_instructions.len);
12531223 self.mir_instructions.appendAssumeCapacity(inst);
1254 if (inst.ops != .pseudo_dead_none) wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)});
1224 if (inst.ops != .pseudo_dead_none) wip_mir_log.debug("{f}", .{self.fmtWipMir(result_index)});
12551225 return result_index;
12561226}
12571227
......@@ -2056,7 +2026,7 @@ fn gen(
20562026 .{},
20572027 );
20582028 self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } };
2059 tracking_log.debug("spill {} to {}", .{ self.ret_mcv.long, frame_index });
2029 tracking_log.debug("spill {f} to {}", .{ self.ret_mcv.long, frame_index });
20602030 },
20612031 else => unreachable,
20622032 }
......@@ -2334,8 +2304,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
23342304
23352305 for (body) |inst| {
23362306 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue;
2337 wip_mir_log.debug("{}", .{cg.fmtAir(inst)});
2338 verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
2307 wip_mir_log.debug("{f}", .{cg.fmtAir(inst)});
2308 verbose_tracking_log.debug("{f}", .{cg.fmtTracking()});
23392309
23402310 cg.reused_operands = .initEmpty();
23412311 try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);
......@@ -4339,7 +4309,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
43394309 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
43404310 } },
43414311 } }) catch |err| switch (err) {
4342 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
4312 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
43434313 @tagName(air_tag),
43444314 cg.typeOf(bin_op.lhs).fmt(pt),
43454315 ops[0].tracking(cg),
......@@ -4351,7 +4321,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
43514321 else => unreachable,
43524322 .add, .add_optimized => {},
43534323 .add_wrap => res[0].wrapInt(cg) catch |err| switch (err) {
4354 error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{
4324 error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{
43554325 @tagName(air_tag),
43564326 cg.typeOf(bin_op.lhs).fmt(pt),
43574327 res[0].tracking(cg),
......@@ -12917,7 +12887,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1291712887 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
1291812888 } },
1291912889 } }) catch |err| switch (err) {
12920 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
12890 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
1292112891 @tagName(air_tag),
1292212892 cg.typeOf(bin_op.lhs).fmt(pt),
1292312893 ops[0].tracking(cg),
......@@ -14947,7 +14917,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1494714917 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
1494814918 } },
1494914919 } }) catch |err| switch (err) {
14950 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
14920 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
1495114921 @tagName(air_tag),
1495214922 cg.typeOf(bin_op.lhs).fmt(pt),
1495314923 ops[0].tracking(cg),
......@@ -14959,7 +14929,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1495914929 else => unreachable,
1496014930 .sub, .sub_optimized => {},
1496114931 .sub_wrap => res[0].wrapInt(cg) catch |err| switch (err) {
14962 error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{
14932 error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{
1496314933 @tagName(air_tag),
1496414934 cg.typeOf(bin_op.lhs).fmt(pt),
1496514935 res[0].tracking(cg),
......@@ -21794,7 +21764,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2179421764 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
2179521765 } },
2179621766 } }) catch |err| switch (err) {
21797 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
21767 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
2179821768 @tagName(air_tag),
2179921769 cg.typeOf(bin_op.lhs).fmt(pt),
2180021770 ops[0].tracking(cg),
......@@ -24587,7 +24557,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2458724557 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
2458824558 } },
2458924559 } }) catch |err| switch (err) {
24590 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
24560 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
2459124561 @tagName(air_tag),
2459224562 ty.fmt(pt),
2459324563 ops[0].tracking(cg),
......@@ -27287,7 +27257,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2728727257 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
2728827258 } },
2728927259 } }) catch |err| switch (err) {
27290 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
27260 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
2729127261 @tagName(air_tag),
2729227262 ty.fmt(pt),
2729327263 ops[0].tracking(cg),
......@@ -27296,7 +27266,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2729627266 else => |e| return e,
2729727267 };
2729827268 res[0].wrapInt(cg) catch |err| switch (err) {
27299 error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{
27269 error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{
2730027270 @tagName(air_tag),
2730127271 cg.typeOf(bin_op.lhs).fmt(pt),
2730227272 res[0].tracking(cg),
......@@ -32512,7 +32482,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
3251232482 .{ .@"0:", ._, .mov, .memad(.dst0q, .add_size, -8), .tmp3q, ._, ._ },
3251332483 } },
3251432484 } }) catch |err| switch (err) {
32515 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
32485 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
3251632486 @tagName(air_tag),
3251732487 cg.typeOf(bin_op.lhs).fmt(pt),
3251832488 ops[0].tracking(cg),
......@@ -33606,7 +33576,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
3360633576 assert(air_tag == .div_exact);
3360733577 res[0] = ops[0].divTruncInts(&ops[1], cg) catch |err| break :err err;
3360833578 }) catch |err| switch (err) {
33609 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
33579 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
3361033580 @tagName(air_tag),
3361133581 ty.fmt(pt),
3361233582 ops[0].tracking(cg),
......@@ -34837,7 +34807,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
3483734807 } }) else err: {
3483834808 res[0] = ops[0].divTruncInts(&ops[1], cg) catch |err| break :err err;
3483934809 }) catch |err| switch (err) {
34840 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
34810 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
3484134811 @tagName(air_tag),
3484234812 ty.fmt(pt),
3484334813 ops[0].tracking(cg),
......@@ -36148,7 +36118,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
3614836118 } },
3614936119 } },
3615036120 }) catch |err| switch (err) {
36151 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
36121 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
3615236122 @tagName(air_tag),
3615336123 cg.typeOf(bin_op.lhs).fmt(pt),
3615436124 ops[0].tracking(cg),
......@@ -37614,7 +37584,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
3761437584 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
3761537585 } },
3761637586 } })) catch |err| switch (err) {
37617 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
37587 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
3761837588 @tagName(air_tag),
3761937589 ty.fmt(pt),
3762037590 ops[0].tracking(cg),
......@@ -39248,7 +39218,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
3924839218 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
3924939219 } },
3925039220 } }) catch |err| switch (err) {
39251 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
39221 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
3925239222 @tagName(air_tag),
3925339223 cg.typeOf(bin_op.lhs).fmt(pt),
3925439224 ops[0].tracking(cg),
......@@ -42077,7 +42047,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
4207742047 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
4207842048 } },
4207942049 } }) catch |err| switch (err) {
42080 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
42050 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
4208142051 @tagName(air_tag),
4208242052 cg.typeOf(bin_op.lhs).fmt(pt),
4208342053 ops[0].tracking(cg),
......@@ -42191,7 +42161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
4219142161 .{ ._, ._, .lea, .dst0p, .leai(.src0, .dst0), ._, ._ },
4219242162 } },
4219342163 } }) catch |err| switch (err) {
42194 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
42164 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
4219542165 @tagName(air_tag),
4219642166 cg.typeOf(bin_op.lhs).fmt(pt),
4219742167 ops[0].tracking(cg),
......@@ -42320,7 +42290,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
4232042290 .{ ._, ._, .lea, .dst0p, .leai(.src0, .dst0), ._, ._ },
4232142291 } },
4232242292 } }) catch |err| switch (err) {
42323 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
42293 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
4232442294 @tagName(air_tag),
4232542295 cg.typeOf(bin_op.lhs).fmt(pt),
4232642296 ops[0].tracking(cg),
......@@ -46485,7 +46455,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
4648546455 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
4648646456 } },
4648746457 } }) catch |err| switch (err) {
46488 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
46458 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
4648946459 @tagName(air_tag),
4649046460 cg.typeOf(bin_op.lhs).fmt(pt),
4649146461 ops[0].tracking(cg),
......@@ -50644,7 +50614,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
5064450614 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
5064550615 } },
5064650616 } }) catch |err| switch (err) {
50647 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
50617 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
5064850618 @tagName(air_tag),
5064950619 cg.typeOf(bin_op.lhs).fmt(pt),
5065050620 ops[0].tracking(cg),
......@@ -51493,7 +51463,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
5149351463 .{ ._, ._, .mov, .memad(.dst0q, .add_src0_size, -8), .tmp0q, ._, ._ },
5149451464 } },
5149551465 } }) catch |err| switch (err) {
51496 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
51466 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
5149751467 @tagName(air_tag),
5149851468 ty_pl.ty.toType().fmt(pt),
5149951469 ops[0].tracking(cg),
......@@ -52398,7 +52368,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
5239852368 .{ ._, ._, .mov, .memad(.dst0q, .add_src0_size, -8), .tmp0q, ._, ._ },
5239952369 } },
5240052370 } }) catch |err| switch (err) {
52401 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
52371 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
5240252372 @tagName(air_tag),
5240352373 ty_pl.ty.toType().fmt(pt),
5240452374 ops[0].tracking(cg),
......@@ -55995,7 +55965,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
5599555965 .{ ._, ._, .@"or", .tmp2q, .tmp1q, ._, ._ },
5599655966 } },
5599755967 } }) catch |err| switch (err) {
55998 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
55968 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
5599955969 @tagName(air_tag),
5600055970 ty_pl.ty.toType().fmt(pt),
5600155971 ops[0].tracking(cg),
......@@ -59340,7 +59310,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
5934059310 .{ ._, ._, .@"or", .tmp4q, .tmp5q, ._, ._ },
5934159311 } },
5934259312 } }) catch |err| switch (err) {
59343 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
59313 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
5934459314 @tagName(air_tag),
5934559315 ty_pl.ty.toType().fmt(pt),
5934659316 ops[0].tracking(cg),
......@@ -59735,7 +59705,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
5973559705 } },
5973659706 } },
5973759707 }) catch |err| switch (err) {
59738 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
59708 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
5973959709 @tagName(air_tag),
5974059710 cg.typeOf(bin_op.lhs).fmt(pt),
5974159711 ops[0].tracking(cg),
......@@ -60298,7 +60268,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6029860268 .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
6029960269 } },
6030060270 } }) catch |err| switch (err) {
60301 error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{
60271 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f}", .{
6030260272 @tagName(air_tag),
6030360273 cg.typeOf(bin_op.lhs).fmt(pt),
6030460274 cg.typeOf(bin_op.rhs).fmt(pt),
......@@ -60660,7 +60630,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6066060630 .{ ._, ._ns, .j, .@"0b", ._, ._, ._ },
6066160631 } },
6066260632 } }) catch |err| switch (err) {
60663 error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{
60633 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f}", .{
6066460634 @tagName(air_tag),
6066560635 cg.typeOf(bin_op.lhs).fmt(pt),
6066660636 cg.typeOf(bin_op.rhs).fmt(pt),
......@@ -60672,7 +60642,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6067260642 switch (air_tag) {
6067360643 else => unreachable,
6067460644 .shl => res[0].wrapInt(cg) catch |err| switch (err) {
60675 error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{
60645 error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{
6067660646 @tagName(air_tag),
6067760647 cg.typeOf(bin_op.lhs).fmt(pt),
6067860648 res[0].tracking(cg),
......@@ -60839,7 +60809,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6083960809 .{ ._, ._, .@"or", .dst0d, .tmp0d, ._, ._ },
6084060810 } },
6084160811 } }) catch |err| switch (err) {
60842 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
60812 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
6084360813 @tagName(air_tag),
6084460814 cg.typeOf(bin_op.rhs).fmt(pt),
6084560815 ops[1].tracking(cg),
......@@ -64096,7 +64066,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6409664066 .{ .@"0:", ._, .mov, .memad(.dst0q, .add_size, -8), .tmp1q, ._, ._ },
6409764067 } },
6409864068 } }) catch |err| switch (err) {
64099 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
64069 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
6410064070 @tagName(air_tag),
6410164071 lhs_ty.fmt(pt),
6410264072 ops[0].tracking(cg),
......@@ -65329,7 +65299,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6532965299 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
6533065300 } },
6533165301 } }) catch |err| switch (err) {
65332 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
65302 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
6533365303 @tagName(air_tag),
6533465304 ty_op.ty.toType().fmt(pt),
6533565305 ops[0].tracking(cg),
......@@ -68483,7 +68453,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6848368453 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
6848468454 } },
6848568455 } }) catch |err| switch (err) {
68486 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
68456 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
6848768457 @tagName(air_tag),
6848868458 cg.typeOf(ty_op.operand).fmt(pt),
6848968459 ops[0].tracking(cg),
......@@ -68880,7 +68850,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6888068850 .{ .@"0:", ._, .lea, .dst0d, .leasia(.dst0, .@"8", .tmp0, .add_8_src0_size), ._, ._ },
6888168851 } },
6888268852 } }) catch |err| switch (err) {
68883 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
68853 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
6888468854 @tagName(air_tag),
6888568855 cg.typeOf(ty_op.operand).fmt(pt),
6888668856 ops[0].tracking(cg),
......@@ -69768,7 +69738,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
6976869738 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
6976969739 } },
6977069740 } }) catch |err| switch (err) {
69771 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
69741 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
6977269742 @tagName(air_tag),
6977369743 cg.typeOf(ty_op.operand).fmt(pt),
6977469744 ops[0].tracking(cg),
......@@ -70417,7 +70387,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7041770387 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
7041870388 } },
7041970389 } }) catch |err| switch (err) {
70420 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
70390 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
7042170391 @tagName(air_tag),
7042270392 ty_op.ty.toType().fmt(pt),
7042370393 ops[0].tracking(cg),
......@@ -73519,7 +73489,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7351973489 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
7352073490 } },
7352173491 } }) catch |err| switch (err) {
73522 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
73492 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
7352373493 @tagName(air_tag),
7352473494 ty_op.ty.toType().fmt(pt),
7352573495 ops[0].tracking(cg),
......@@ -74457,7 +74427,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7445774427 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
7445874428 } },
7445974429 } }) catch |err| switch (err) {
74460 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
74430 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
7446174431 @tagName(air_tag),
7446274432 cg.typeOf(un_op).fmt(pt),
7446374433 ops[0].tracking(cg),
......@@ -75183,7 +75153,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7518375153 } },
7518475154 } },
7518575155 }) catch |err| switch (err) {
75186 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
75156 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
7518775157 @tagName(air_tag),
7518875158 cg.typeOf(un_op).fmt(pt),
7518975159 ops[0].tracking(cg),
......@@ -76734,7 +76704,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7673476704 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
7673576705 } },
7673676706 } }) catch |err| switch (err) {
76737 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
76707 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
7673876708 @tagName(air_tag),
7673976709 cg.typeOf(ty_op.operand).fmt(pt),
7674076710 ops[0].tracking(cg),
......@@ -77926,7 +77896,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7792677896 } },
7792777897 } },
7792877898 }) catch |err| switch (err) {
77929 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
77899 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
7793077900 @tagName(air_tag),
7793177901 cg.typeOf(un_op).fmt(pt),
7793277902 ops[0].tracking(cg),
......@@ -78466,7 +78436,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7846678436 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
7846778437 } },
7846878438 } }) catch |err| switch (err) {
78469 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
78439 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
7847078440 @tagName(air_tag),
7847178441 cg.typeOf(un_op).fmt(pt),
7847278442 ops[0].tracking(cg),
......@@ -78913,7 +78883,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7891378883 } else err: {
7891478884 res[0] = ops[0].cmpInts(cmp_op, &ops[1], cg) catch |err| break :err err;
7891578885 }) catch |err| switch (err) {
78916 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
78886 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
7891778887 @tagName(air_tag),
7891878888 cg.typeOf(bin_op.lhs).fmt(pt),
7891978889 ops[0].tracking(cg),
......@@ -79458,7 +79428,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7945879428 .@"struct", .@"union" => {
7945979429 assert(ty.containerLayout(zcu) == .@"packed");
7946079430 for (&ops) |*op| op.wrapInt(cg) catch |err| switch (err) {
79461 error.SelectFailed => return cg.fail("failed to select {s} wrap {} {}", .{
79431 error.SelectFailed => return cg.fail("failed to select {s} wrap {f} {f}", .{
7946279432 @tagName(air_tag),
7946379433 ty.fmt(pt),
7946479434 op.tracking(cg),
......@@ -79470,7 +79440,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
7947079440 res[0] = ops[0].cmpInts(cmp_op, &ops[1], cg) catch |err| break :err err;
7947179441 },
7947279442 }) catch |err| switch (err) {
79473 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
79443 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
7947479444 @tagName(air_tag),
7947579445 ty.fmt(pt),
7947679446 ops[0].tracking(cg),
......@@ -86551,7 +86521,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
8655186521 } },
8655286522 }),
8655386523 }) catch |err| switch (err) {
86554 error.SelectFailed => return cg.fail("failed to select {s} {s} {} {} {}", .{
86524 error.SelectFailed => return cg.fail("failed to select {s} {s} {f} {f} {f}", .{
8655586525 @tagName(air_tag),
8655686526 @tagName(vector_cmp.compareOperator()),
8655786527 cg.typeOf(vector_cmp.lhs).fmt(pt),
......@@ -88546,7 +88516,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
8854688516 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
8854788517 } },
8854888518 } }) catch |err| switch (err) {
88549 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
88519 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
8855088520 @tagName(air_tag),
8855188521 ty_op.ty.toType().fmt(pt),
8855288522 cg.typeOf(ty_op.operand).fmt(pt),
......@@ -90221,7 +90191,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9022190191 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
9022290192 } },
9022390193 } }) catch |err| switch (err) {
90224 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
90194 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
9022590195 @tagName(air_tag),
9022690196 ty_op.ty.toType().fmt(pt),
9022790197 cg.typeOf(ty_op.operand).fmt(pt),
......@@ -94899,7 +94869,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
9489994869 .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
9490094870 } },
9490194871 } }) catch |err| switch (err) {
94902 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
94872 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
9490394873 @tagName(air_tag),
9490494874 dst_ty.fmt(pt),
9490594875 src_ty.fmt(pt),
......@@ -100565,7 +100535,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100565100535 .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
100566100536 } },
100567100537 } }) catch |err| switch (err) {
100568 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
100538 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
100569100539 @tagName(air_tag),
100570100540 ty_op.ty.toType().fmt(pt),
100571100541 cg.typeOf(ty_op.operand).fmt(pt),
......@@ -111427,7 +111397,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
111427111397 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
111428111398 } },
111429111399 } }) catch |err| switch (err) {
111430 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
111400 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
111431111401 @tagName(air_tag),
111432111402 ty_op.ty.toType().fmt(pt),
111433111403 cg.typeOf(ty_op.operand).fmt(pt),
......@@ -123446,7 +123416,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
123446123416 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
123447123417 } },
123448123418 } }) catch |err| switch (err) {
123449 error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
123419 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f}", .{
123450123420 @tagName(air_tag),
123451123421 ty_op.ty.toType().fmt(pt),
123452123422 cg.typeOf(ty_op.operand).fmt(pt),
......@@ -157216,7 +157186,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
157216157186 } },
157217157187 } },
157218157188 }) catch |err| switch (err) {
157219 error.SelectFailed => return cg.fail("failed to select {s}.{s} {} {}", .{
157189 error.SelectFailed => return cg.fail("failed to select {s}.{s} {f} {f}", .{
157220157190 @tagName(air_tag),
157221157191 @tagName(reduce.operation),
157222157192 cg.typeOf(reduce.operand).fmt(pt),
......@@ -157227,7 +157197,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
157227157197 switch (reduce.operation) {
157228157198 .And, .Or, .Xor, .Min, .Max => {},
157229157199 .Add, .Mul => if (cg.intInfo(res_ty)) |_| res[0].wrapInt(cg) catch |err| switch (err) {
157230 error.SelectFailed => return cg.fail("failed to select {s}.{s} wrap {} {}", .{
157200 error.SelectFailed => return cg.fail("failed to select {s}.{s} wrap {f} {f}", .{
157231157201 @tagName(air_tag),
157232157202 @tagName(reduce.operation),
157233157203 res_ty.fmt(pt),
......@@ -164510,7 +164480,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
164510164480 } },
164511164481 } },
164512164482 }) catch |err| switch (err) {
164513 error.SelectFailed => return cg.fail("failed to select {s}.{s} {} {}", .{
164483 error.SelectFailed => return cg.fail("failed to select {s}.{s} {f} {f}", .{
164514164484 @tagName(air_tag),
164515164485 @tagName(reduce.operation),
164516164486 cg.typeOf(reduce.operand).fmt(pt),
......@@ -166307,7 +166277,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166307166277 .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
166308166278 } },
166309166279 } }) catch |err| switch (err) {
166310 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
166280 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
166311166281 @tagName(air_tag),
166312166282 ty_op.ty.toType().fmt(pt),
166313166283 ops[0].tracking(cg),
......@@ -166323,7 +166293,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166323166293 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
166324166294 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }) ++ .{undefined};
166325166295 ops[2] = ops[0].getByteLen(cg) catch |err| switch (err) {
166326 error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{
166296 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f}", .{
166327166297 @tagName(air_tag),
166328166298 cg.typeOf(bin_op.lhs).fmt(pt),
166329166299 cg.typeOf(bin_op.rhs).fmt(pt),
......@@ -166363,7 +166333,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166363166333 } },
166364166334 }},
166365166335 }) catch |err| switch (err) {
166366 error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {} {}", .{
166336 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f} {f}", .{
166367166337 @tagName(air_tag),
166368166338 cg.typeOf(bin_op.lhs).fmt(pt),
166369166339 cg.typeOf(bin_op.rhs).fmt(pt),
......@@ -166464,7 +166434,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166464166434 .{ ._, ._, .@"test", .src0p, .src0p, ._, ._ },
166465166435 } },
166466166436 } }) catch |err| switch (err) {
166467 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
166437 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
166468166438 @tagName(air_tag),
166469166439 cg.typeOf(un_op).fmt(pt),
166470166440 ops[0].tracking(cg),
......@@ -166552,7 +166522,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166552166522 .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
166553166523 } },
166554166524 } }) catch |err| switch (err) {
166555 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
166525 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
166556166526 @tagName(air_tag),
166557166527 cg.typeOf(un_op).fmt(pt),
166558166528 ops[0].tracking(cg),
......@@ -166654,7 +166624,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166654166624 .{ ._, ._, .lea, .dst1d, .leai(.dst1, .tmp1), ._, ._ },
166655166625 } },
166656166626 } }) catch |err| switch (err) {
166657 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
166627 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
166658166628 @tagName(air_tag),
166659166629 cg.typeOf(un_op).fmt(pt),
166660166630 ops[0].tracking(cg),
......@@ -166752,7 +166722,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166752166722 .{ ._, ._, .@"test", .src0d, .src0d, ._, ._ },
166753166723 } },
166754166724 } }) catch |err| switch (err) {
166755 error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
166725 error.SelectFailed => return cg.fail("failed to select {s} {f} {f}", .{
166756166726 @tagName(air_tag),
166757166727 ty_op.ty.toType().fmt(pt),
166758166728 ops[0].tracking(cg),
......@@ -166804,7 +166774,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166804166774 }
166805166775 }
166806166776 },
166807 .@"packed" => return cg.fail("failed to select {s} {}", .{
166777 .@"packed" => return cg.fail("failed to select {s} {f}", .{
166808166778 @tagName(air_tag),
166809166779 agg_ty.fmt(pt),
166810166780 }),
......@@ -166825,7 +166795,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
166825166795 elem_disp += @intCast(field_type.abiSize(zcu));
166826166796 }
166827166797 },
166828 else => return cg.fail("failed to select {s} {}", .{
166798 else => return cg.fail("failed to select {s} {f}", .{
166829166799 @tagName(air_tag),
166830166800 agg_ty.fmt(pt),
166831166801 }),
......@@ -168123,7 +168093,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168123168093 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
168124168094 } },
168125168095 } }) catch |err| switch (err) {
168126 error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{
168096 error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f}", .{
168127168097 @tagName(air_tag),
168128168098 cg.typeOf(bin_op.lhs).fmt(pt),
168129168099 ops[0].tracking(cg),
......@@ -168223,7 +168193,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168223168193 .{ ._, ._, .cmp, .src0d, .lea(.tmp1d), ._, ._ },
168224168194 } },
168225168195 } }) catch |err| switch (err) {
168226 error.SelectFailed => return cg.fail("failed to select {s} {}", .{
168196 error.SelectFailed => return cg.fail("failed to select {s} {f}", .{
168227168197 @tagName(air_tag),
168228168198 ops[0].tracking(cg),
168229168199 }),
......@@ -168242,12 +168212,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168242168212 .ref => {
168243168213 const result = try cg.allocRegOrMem(err_ret_trace_index, true);
168244168214 try cg.genCopy(.usize, result, ops[0].tracking(cg).short, .{});
168245 tracking_log.debug("{} => {} (birth)", .{ err_ret_trace_index, result });
168215 tracking_log.debug("{f} => {f} (birth)", .{ err_ret_trace_index, result });
168246168216 cg.inst_tracking.putAssumeCapacityNoClobber(err_ret_trace_index, .init(result));
168247168217 },
168248168218 .temp => |temp_index| {
168249168219 const temp_tracking = temp_index.tracking(cg);
168250 tracking_log.debug("{} => {} (birth)", .{ err_ret_trace_index, temp_tracking.short });
168220 tracking_log.debug("{f} => {f} (birth)", .{ err_ret_trace_index, temp_tracking.short });
168251168221 cg.inst_tracking.putAssumeCapacityNoClobber(err_ret_trace_index, temp_tracking.*);
168252168222 assert(cg.reuseTemp(err_ret_trace_index, temp_index.toIndex(), temp_tracking));
168253168223 },
......@@ -168917,7 +168887,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168917168887 try cg.resetTemps(@enumFromInt(0));
168918168888 cg.checkInvariantsAfterAirInst();
168919168889 }
168920 verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
168890 verbose_tracking_log.debug("{f}", .{cg.fmtTracking()});
168921168891}
168922168892
168923168893fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
......@@ -168927,7 +168897,7 @@ fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
168927168897 switch (ip.indexToKey(lazy_sym.ty)) {
168928168898 .enum_type => {
168929168899 const enum_ty: Type = .fromInterned(lazy_sym.ty);
168930 wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)});
168900 wip_mir_log.debug("{f}.@tagName:", .{enum_ty.fmt(pt)});
168931168901
168932168902 const param_regs = abi.getCAbiIntParamRegs(.auto);
168933168903 const param_locks = cg.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);
......@@ -168976,7 +168946,7 @@ fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
168976168946 },
168977168947 .error_set_type => |error_set_type| {
168978168948 const err_ty: Type = .fromInterned(lazy_sym.ty);
168979 wip_mir_log.debug("{}.@errorCast:", .{err_ty.fmt(pt)});
168949 wip_mir_log.debug("{f}.@errorCast:", .{err_ty.fmt(pt)});
168980168950
168981168951 const param_regs = abi.getCAbiIntParamRegs(.auto);
168982168952 const param_locks = cg.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);
......@@ -169016,7 +168986,7 @@ fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
169016168986 try cg.asmOpOnly(.{ ._, .ret });
169017168987 },
169018168988 else => return cg.fail(
169019 "TODO implement {s} for {}",
168989 "TODO implement {s} for {f}",
169020168990 .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) },
169021168991 ),
169022168992 }
......@@ -169076,7 +169046,7 @@ fn finishAirResult(self: *CodeGen, inst: Air.Inst.Index, result: MCValue) void {
169076169046 .none, .dead, .unreach => {},
169077169047 else => unreachable, // Why didn't the result die?
169078169048 } else {
169079 tracking_log.debug("{} => {} (birth)", .{ inst, result });
169049 tracking_log.debug("{f} => {f} (birth)", .{ inst, result });
169080169050 self.inst_tracking.putAssumeCapacityNoClobber(inst, .init(result));
169081169051 // In some cases, an operand may be reused as the result.
169082169052 // If that operand died and was a register, it was freed by
......@@ -169226,7 +169196,7 @@ fn allocMemPtr(self: *CodeGen, inst: Air.Inst.Index) !FrameIndex {
169226169196 const val_ty = ptr_ty.childType(zcu);
169227169197 return self.allocFrameIndex(.init(.{
169228169198 .size = std.math.cast(u32, val_ty.abiSize(zcu)) orelse {
169229 return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(pt)});
169199 return self.fail("type '{f}' too big to fit into stack frame", .{val_ty.fmt(pt)});
169230169200 },
169231169201 .alignment = ptr_ty.ptrAlignment(zcu).max(.@"1"),
169232169202 }));
......@@ -169244,7 +169214,7 @@ fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok
169244169214 const pt = self.pt;
169245169215 const zcu = pt.zcu;
169246169216 const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse {
169247 return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(pt)});
169217 return self.fail("type '{f}' too big to fit into stack frame", .{ty.fmt(pt)});
169248169218 };
169249169219
169250169220 if (reg_ok) need_mem: {
......@@ -169749,7 +169719,7 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {
169749169719 );
169750169720 }
169751169721 break :result dst_mcv;
169752 } orelse return self.fail("TODO implement airFpext from {} to {}", .{
169722 } orelse return self.fail("TODO implement airFpext from {f} to {f}", .{
169753169723 src_ty.fmt(pt), dst_ty.fmt(pt),
169754169724 });
169755169725 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -170004,7 +169974,7 @@ fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {
170004169974 );
170005169975
170006169976 break :result dst_mcv;
170007 }) orelse return self.fail("TODO implement airIntCast from {} to {}", .{
169977 }) orelse return self.fail("TODO implement airIntCast from {f} to {f}", .{
170008169978 src_ty.fmt(pt), dst_ty.fmt(pt),
170009169979 });
170010169980 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -170076,7 +170046,7 @@ fn airTrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
170076170046 else => null,
170077170047 },
170078170048 else => null,
170079 }) orelse return self.fail("TODO implement airTrunc for {}", .{dst_ty.fmt(pt)});
170049 }) orelse return self.fail("TODO implement airTrunc for {f}", .{dst_ty.fmt(pt)});
170080170050
170081170051 const dst_info = dst_elem_ty.intInfo(zcu);
170082170052 const src_info = src_elem_ty.intInfo(zcu);
......@@ -170497,7 +170467,7 @@ fn airAddSat(self: *CodeGen, inst: Air.Inst.Index) !void {
170497170467 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
170498170468 const ty = self.typeOf(bin_op.lhs);
170499170469 if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail(
170500 "TODO implement airAddSat for {}",
170470 "TODO implement airAddSat for {f}",
170501170471 .{ty.fmt(pt)},
170502170472 );
170503170473
......@@ -170575,7 +170545,7 @@ fn airSubSat(self: *CodeGen, inst: Air.Inst.Index) !void {
170575170545 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
170576170546 const ty = self.typeOf(bin_op.lhs);
170577170547 if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail(
170578 "TODO implement airSubSat for {}",
170548 "TODO implement airSubSat for {f}",
170579170549 .{ty.fmt(pt)},
170580170550 );
170581170551
......@@ -170726,7 +170696,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void {
170726170696 }
170727170697
170728170698 if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail(
170729 "TODO implement airMulSat for {}",
170699 "TODO implement airMulSat for {f}",
170730170700 .{ty.fmt(pt)},
170731170701 );
170732170702
......@@ -171020,7 +170990,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
171020170990 const tuple_ty = self.typeOfIndex(inst);
171021170991 const dst_ty = self.typeOf(bin_op.lhs);
171022170992 const result: MCValue = switch (dst_ty.zigTypeTag(zcu)) {
171023 .vector => return self.fail("TODO implement airMulWithOverflow for {}", .{dst_ty.fmt(pt)}),
170993 .vector => return self.fail("TODO implement airMulWithOverflow for {f}", .{dst_ty.fmt(pt)}),
171024170994 .int => result: {
171025170995 const dst_info = dst_ty.intInfo(zcu);
171026170996 if (dst_info.bits > 128 and dst_info.signedness == .unsigned) {
......@@ -171373,7 +171343,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
171373171343 else => {
171374171344 // For now, this is the only supported multiply that doesn't fit in a register.
171375171345 if (dst_info.bits > 128 or src_bits != 64)
171376 return self.fail("TODO implement airWithOverflow from {} to {}", .{
171346 return self.fail("TODO implement airWithOverflow from {f} to {f}", .{
171377171347 src_ty.fmt(pt), dst_ty.fmt(pt),
171378171348 });
171379171349
......@@ -171774,7 +171744,7 @@ fn airShlShrBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
171774171744 },
171775171745 else => {},
171776171746 }
171777 return self.fail("TODO implement airShlShrBinOp for {}", .{lhs_ty.fmt(pt)});
171747 return self.fail("TODO implement airShlShrBinOp for {f}", .{lhs_ty.fmt(pt)});
171778171748 };
171779171749 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
171780171750}
......@@ -172034,7 +172004,7 @@ fn airUnwrapErrUnionErr(self: *CodeGen, inst: Air.Inst.Index) !void {
172034172004 .index = frame_addr.index,
172035172005 .off = frame_addr.off + @as(i32, @intCast(err_off)),
172036172006 } },
172037 else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}),
172007 else => return self.fail("TODO implement unwrap_err_err for {f}", .{operand}),
172038172008 }
172039172009 };
172040172010 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -172196,7 +172166,7 @@ fn genUnwrapErrUnionPayloadMir(
172196172166 else
172197172167 .{ .register = try self.copyToTmpRegister(payload_ty, result_mcv) };
172198172168 },
172199 else => return self.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}),
172169 else => return self.fail("TODO implement genUnwrapErrUnionPayloadMir for {f}", .{err_union}),
172200172170 }
172201172171 };
172202172172
......@@ -172362,7 +172332,7 @@ fn airSliceLen(self: *CodeGen, inst: Air.Inst.Index) !void {
172362172332 .index = frame_addr.index,
172363172333 .off = frame_addr.off + 8,
172364172334 } },
172365 else => return self.fail("TODO implement slice_len for {}", .{src_mcv}),
172335 else => return self.fail("TODO implement slice_len for {f}", .{src_mcv}),
172366172336 };
172367172337 if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
172368172338 switch (src_mcv) {
......@@ -172645,7 +172615,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
172645172615 }.to64(),
172646172616 ),
172647172617 },
172648 else => return self.fail("TODO airArrayElemVal for {s} of {}", .{
172618 else => return self.fail("TODO airArrayElemVal for {s} of {f}", .{
172649172619 @tagName(array_mat_mcv), array_ty.fmt(pt),
172650172620 }),
172651172621 }
......@@ -172688,7 +172658,7 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
172688172658 .load_extern_func,
172689172659 .lea_extern_func,
172690172660 => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}),
172691 else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{
172661 else => return self.fail("TODO airArrayElemVal_val for {s} of {f}", .{
172692172662 @tagName(array_mcv), array_ty.fmt(pt),
172693172663 }),
172694172664 }
......@@ -172881,7 +172851,7 @@ fn airGetUnionTag(self: *CodeGen, inst: Air.Inst.Index) !void {
172881172851 }
172882172852
172883172853 return self.fail(
172884 "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}",
172854 "TODO implement get_union_tag for ABI larger than 8 bytes and operand {f}",
172885172855 .{operand},
172886172856 );
172887172857 },
......@@ -172893,7 +172863,7 @@ fn airGetUnionTag(self: *CodeGen, inst: Air.Inst.Index) !void {
172893172863 .register = registerAlias(result.register, @intCast(layout.tag_size)),
172894172864 };
172895172865 },
172896 else => return self.fail("TODO implement get_union_tag for {}", .{operand}),
172866 else => return self.fail("TODO implement get_union_tag for {f}", .{operand}),
172897172867 }
172898172868 };
172899172869
......@@ -172909,7 +172879,7 @@ fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
172909172879
172910172880 const dst_ty = self.typeOfIndex(inst);
172911172881 const src_ty = self.typeOf(ty_op.operand);
172912 if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airClz for {}", .{
172882 if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airClz for {f}", .{
172913172883 src_ty.fmt(pt),
172914172884 });
172915172885
......@@ -173105,7 +173075,7 @@ fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
173105173075
173106173076 const dst_ty = self.typeOfIndex(inst);
173107173077 const src_ty = self.typeOf(ty_op.operand);
173108 if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airCtz for {}", .{
173078 if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airCtz for {f}", .{
173109173079 src_ty.fmt(pt),
173110173080 });
173111173081
......@@ -173277,7 +173247,7 @@ fn airPopCount(self: *CodeGen, inst: Air.Inst.Index) !void {
173277173247 const src_ty = self.typeOf(ty_op.operand);
173278173248 const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));
173279173249 if (src_ty.zigTypeTag(zcu) == .vector or src_abi_size > 16)
173280 return self.fail("TODO implement airPopCount for {}", .{src_ty.fmt(pt)});
173250 return self.fail("TODO implement airPopCount for {f}", .{src_ty.fmt(pt)});
173281173251 const src_mcv = try self.resolveInst(ty_op.operand);
173282173252
173283173253 const mat_src_mcv = switch (src_mcv) {
......@@ -173430,7 +173400,7 @@ fn genByteSwap(
173430173400 const has_movbe = self.hasFeature(.movbe);
173431173401
173432173402 if (src_ty.zigTypeTag(zcu) == .vector) return self.fail(
173433 "TODO implement genByteSwap for {}",
173403 "TODO implement genByteSwap for {f}",
173434173404 .{src_ty.fmt(pt)},
173435173405 );
173436173406
......@@ -173739,7 +173709,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A
173739173709 const result = result: {
173740173710 const scalar_bits = ty.scalarType(zcu).floatBits(self.target);
173741173711 if (scalar_bits == 80) {
173742 if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement floatSign for {}", .{
173712 if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement floatSign for {f}", .{
173743173713 ty.fmt(pt),
173744173714 });
173745173715
......@@ -173763,7 +173733,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A
173763173733 const abi_size: u32 = switch (ty.abiSize(zcu)) {
173764173734 1...16 => 16,
173765173735 17...32 => 32,
173766 else => return self.fail("TODO implement floatSign for {}", .{
173736 else => return self.fail("TODO implement floatSign for {f}", .{
173767173737 ty.fmt(pt),
173768173738 }),
173769173739 };
......@@ -173822,7 +173792,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A
173822173792 .abs => .{ .v_pd, .@"and" },
173823173793 else => unreachable,
173824173794 },
173825 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(pt)}),
173795 80 => return self.fail("TODO implement floatSign for {f}", .{ty.fmt(pt)}),
173826173796 else => unreachable,
173827173797 },
173828173798 registerAlias(dst_reg, abi_size),
......@@ -173848,7 +173818,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A
173848173818 .abs => .{ ._pd, .@"and" },
173849173819 else => unreachable,
173850173820 },
173851 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(pt)}),
173821 80 => return self.fail("TODO implement floatSign for {f}", .{ty.fmt(pt)}),
173852173822 else => unreachable,
173853173823 },
173854173824 registerAlias(dst_reg, abi_size),
......@@ -173928,7 +173898,7 @@ fn genRoundLibcall(self: *CodeGen, ty: Type, src_mcv: MCValue, mode: bits.RoundM
173928173898 if (self.getRoundTag(ty)) |_| return .none;
173929173899
173930173900 if (ty.zigTypeTag(zcu) != .float)
173931 return self.fail("TODO implement genRound for {}", .{ty.fmt(pt)});
173901 return self.fail("TODO implement genRound for {f}", .{ty.fmt(pt)});
173932173902
173933173903 var sym_buf: ["__trunc?".len]u8 = undefined;
173934173904 return try self.genCall(.{ .extern_func = .{
......@@ -174164,7 +174134,7 @@ fn airAbs(self: *CodeGen, inst: Air.Inst.Index) !void {
174164174134 },
174165174135 .float => return self.floatSign(inst, .abs, ty_op.operand, ty),
174166174136 },
174167 }) orelse return self.fail("TODO implement airAbs for {}", .{ty.fmt(pt)});
174137 }) orelse return self.fail("TODO implement airAbs for {f}", .{ty.fmt(pt)});
174168174138
174169174139 const abi_size: u32 = @intCast(ty.abiSize(zcu));
174170174140 const src_mcv = try self.resolveInst(ty_op.operand);
......@@ -174323,7 +174293,7 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {
174323174293 else => unreachable,
174324174294 },
174325174295 else => unreachable,
174326 }) orelse return self.fail("TODO implement airSqrt for {}", .{ty.fmt(pt)});
174296 }) orelse return self.fail("TODO implement airSqrt for {f}", .{ty.fmt(pt)});
174327174297 switch (mir_tag[0]) {
174328174298 .v_ss, .v_sd => if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
174329174299 mir_tag,
......@@ -174481,7 +174451,7 @@ fn packedLoad(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue)
174481174451 return;
174482174452 }
174483174453
174484 if (val_abi_size > 8) return self.fail("TODO implement packed load of {}", .{val_ty.fmt(pt)});
174454 if (val_abi_size > 8) return self.fail("TODO implement packed load of {f}", .{val_ty.fmt(pt)});
174485174455
174486174456 const limb_abi_size: u31 = @min(val_abi_size, 8);
174487174457 const limb_abi_bits = limb_abi_size * 8;
......@@ -174753,7 +174723,7 @@ fn packedStore(self: *CodeGen, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue)
174753174723 limb_mem,
174754174724 registerAlias(tmp_reg, limb_abi_size),
174755174725 );
174756 } else return self.fail("TODO: implement packed store of {}", .{src_ty.fmt(pt)});
174726 } else return self.fail("TODO: implement packed store of {f}", .{src_ty.fmt(pt)});
174757174727 }
174758174728}
174759174729
......@@ -174856,7 +174826,7 @@ fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_a
174856174826 const zcu = pt.zcu;
174857174827 const src_ty = self.typeOf(src_air);
174858174828 if (src_ty.zigTypeTag(zcu) == .vector)
174859 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(pt)});
174829 return self.fail("TODO implement genUnOp for {f}", .{src_ty.fmt(pt)});
174860174830
174861174831 var src_mcv = try self.resolveInst(src_air);
174862174832 switch (src_mcv) {
......@@ -174943,7 +174913,7 @@ fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_a
174943174913fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void {
174944174914 const pt = self.pt;
174945174915 const abi_size: u32 = @intCast(dst_ty.abiSize(pt.zcu));
174946 if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ mir_tag, dst_ty.fmt(pt) });
174916 if (abi_size > 8) return self.fail("TODO implement {} for {f}", .{ mir_tag, dst_ty.fmt(pt) });
174947174917 switch (dst_mcv) {
174948174918 .none,
174949174919 .unreach,
......@@ -175672,7 +175642,7 @@ fn genBinOp(
175672175642 },
175673175643 floatLibcAbiSuffix(lhs_ty),
175674175644 }),
175675 else => return self.fail("TODO implement genBinOp for {s} {}", .{
175645 else => return self.fail("TODO implement genBinOp for {s} {f}", .{
175676175646 @tagName(air_tag), lhs_ty.fmt(pt),
175677175647 }),
175678175648 } catch unreachable;
......@@ -175785,7 +175755,7 @@ fn genBinOp(
175785175755 );
175786175756 break :adjusted .{ .register = dst_reg };
175787175757 },
175788 80, 128 => return self.fail("TODO implement genBinOp for {s} of {}", .{
175758 80, 128 => return self.fail("TODO implement genBinOp for {s} of {f}", .{
175789175759 @tagName(air_tag), lhs_ty.fmt(pt),
175790175760 }),
175791175761 else => unreachable,
......@@ -175819,7 +175789,7 @@ fn genBinOp(
175819175789 if (sse_op and ((lhs_ty.scalarType(zcu).isRuntimeFloat() and
175820175790 lhs_ty.scalarType(zcu).floatBits(self.target) == 80) or
175821175791 lhs_ty.abiSize(zcu) > self.vectorSize(.float)))
175822 return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(air_tag), lhs_ty.fmt(pt) });
175792 return self.fail("TODO implement genBinOp for {s} {f}", .{ @tagName(air_tag), lhs_ty.fmt(pt) });
175823175793
175824175794 const maybe_mask_reg = switch (air_tag) {
175825175795 else => null,
......@@ -176199,7 +176169,7 @@ fn genBinOp(
176199176169 }
176200176170 },
176201176171
176202 else => return self.fail("TODO implement genBinOp for {s} {}", .{
176172 else => return self.fail("TODO implement genBinOp for {s} {f}", .{
176203176173 @tagName(air_tag), lhs_ty.fmt(pt),
176204176174 }),
176205176175 }
......@@ -176953,7 +176923,7 @@ fn genBinOp(
176953176923 else => unreachable,
176954176924 },
176955176925 },
176956 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
176926 }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{
176957176927 @tagName(air_tag), lhs_ty.fmt(pt),
176958176928 });
176959176929
......@@ -177086,7 +177056,7 @@ fn genBinOp(
177086177056 else => unreachable,
177087177057 },
177088177058 else => unreachable,
177089 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
177059 }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{
177090177060 @tagName(air_tag), lhs_ty.fmt(pt),
177091177061 }),
177092177062 mask_reg,
......@@ -177118,7 +177088,7 @@ fn genBinOp(
177118177088 else => unreachable,
177119177089 },
177120177090 else => unreachable,
177121 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
177091 }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{
177122177092 @tagName(air_tag), lhs_ty.fmt(pt),
177123177093 }),
177124177094 dst_reg,
......@@ -177154,7 +177124,7 @@ fn genBinOp(
177154177124 else => unreachable,
177155177125 },
177156177126 else => unreachable,
177157 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
177127 }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{
177158177128 @tagName(air_tag), lhs_ty.fmt(pt),
177159177129 }),
177160177130 mask_reg,
......@@ -177185,7 +177155,7 @@ fn genBinOp(
177185177155 else => unreachable,
177186177156 },
177187177157 else => unreachable,
177188 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
177158 }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{
177189177159 @tagName(air_tag), lhs_ty.fmt(pt),
177190177160 }),
177191177161 dst_reg,
......@@ -177215,7 +177185,7 @@ fn genBinOp(
177215177185 else => unreachable,
177216177186 },
177217177187 else => unreachable,
177218 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
177188 }) orelse return self.fail("TODO implement genBinOp for {s} {f}", .{
177219177189 @tagName(air_tag), lhs_ty.fmt(pt),
177220177190 });
177221177191 try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_reg, mask_reg);
......@@ -178022,7 +177992,7 @@ fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void {
178022177992
178023177993 break :result dst_mcv;
178024177994 },
178025 else => return self.fail("TODO implement arg for {}", .{src_mcv}),
177995 else => return self.fail("TODO implement arg for {f}", .{src_mcv}),
178026177996 }
178027177997 };
178028177998 return self.finishAir(inst, result, .{ .none, .none, .none });
......@@ -179079,7 +179049,7 @@ fn genCondBrMir(self: *CodeGen, ty: Type, mcv: MCValue) !Mir.Inst.Index {
179079179049 const reg = try self.copyToTmpRegister(ty, mcv);
179080179050 return self.genCondBrMir(ty, .{ .register = reg });
179081179051 }
179082 return self.fail("TODO implement condbr when condition is {} with abi larger than 8 bytes", .{mcv});
179052 return self.fail("TODO implement condbr when condition is {f} with abi larger than 8 bytes", .{mcv});
179083179053 },
179084179054 else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}),
179085179055 }
......@@ -179166,7 +179136,7 @@ fn isErr(self: *CodeGen, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCVal
179166179136 } },
179167179137 .{ .immediate = 0 },
179168179138 ),
179169 else => return self.fail("TODO implement isErr for {}", .{eu_mcv}),
179139 else => return self.fail("TODO implement isErr for {f}", .{eu_mcv}),
179170179140 }
179171179141
179172179142 if (maybe_inst) |inst| self.eflags_inst = inst;
......@@ -180916,7 +180886,7 @@ fn moveStrategy(cg: *CodeGen, ty: Type, class: Register.Class, aligned: bool) !M
180916180886 },
180917180887 .ip, .cr, .dr => {},
180918180888 }
180919 return cg.fail("TODO moveStrategy for {}", .{ty.fmt(pt)});
180889 return cg.fail("TODO moveStrategy for {f}", .{ty.fmt(pt)});
180920180890}
180921180891
180922180892const CopyOptions = struct {
......@@ -181048,7 +181018,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
181048181018 break :src_info .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
181049181019 },
181050181020 .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref), opts),
181051 else => return self.fail("TODO implement genCopy for {s} of {}", .{
181021 else => return self.fail("TODO implement genCopy for {s} of {f}", .{
181052181022 @tagName(src_mcv), ty.fmt(pt),
181053181023 }),
181054181024 };
......@@ -181424,7 +181394,7 @@ fn genSetReg(
181424181394 80 => null,
181425181395 else => unreachable,
181426181396 },
181427 }) orelse return self.fail("TODO implement genSetReg for {}", .{ty.fmt(pt)}),
181397 }) orelse return self.fail("TODO implement genSetReg for {f}", .{ty.fmt(pt)}),
181428181398 dst_alias,
181429181399 registerAlias(src_reg, abi_size),
181430181400 ),
......@@ -181532,7 +181502,7 @@ fn genSetReg(
181532181502 assert(!ty.optionalReprIsPayload(zcu));
181533181503 break :first_ty opt_child;
181534181504 },
181535 else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, ty.fmt(pt) }),
181505 else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, ty.fmt(pt) }),
181536181506 });
181537181507 const first_size: u31 = @intCast(first_ty.abiSize(zcu));
181538181508 const frame_size = std.math.ceilPowerOfTwoAssert(u32, abi_size);
......@@ -181854,7 +181824,7 @@ fn genSetMem(
181854181824 opts,
181855181825 );
181856181826 },
181857 else => return self.fail("TODO implement genSetMem for {s} of {}", .{
181827 else => return self.fail("TODO implement genSetMem for {s} of {f}", .{
181858181828 @tagName(src_mcv), ty.fmt(pt),
181859181829 }),
181860181830 },
......@@ -182167,7 +182137,7 @@ fn airFloatFromInt(self: *CodeGen, inst: Air.Inst.Index) !void {
182167182137 32, 64 => src_size > 8,
182168182138 else => unreachable,
182169182139 }) {
182170 if (src_bits > 128) return self.fail("TODO implement airFloatFromInt from {} to {}", .{
182140 if (src_bits > 128) return self.fail("TODO implement airFloatFromInt from {f} to {f}", .{
182171182141 src_ty.fmt(pt), dst_ty.fmt(pt),
182172182142 });
182173182143
......@@ -182209,7 +182179,7 @@ fn airFloatFromInt(self: *CodeGen, inst: Air.Inst.Index) !void {
182209182179 else => unreachable,
182210182180 },
182211182181 else => null,
182212 }) orelse return self.fail("TODO implement airFloatFromInt from {} to {}", .{
182182 }) orelse return self.fail("TODO implement airFloatFromInt from {f} to {f}", .{
182213182183 src_ty.fmt(pt), dst_ty.fmt(pt),
182214182184 });
182215182185 const dst_alias = dst_reg.to128();
......@@ -182247,7 +182217,7 @@ fn airIntFromFloat(self: *CodeGen, inst: Air.Inst.Index) !void {
182247182217 32, 64 => dst_size > 8,
182248182218 else => unreachable,
182249182219 }) {
182250 if (dst_bits > 128) return self.fail("TODO implement airIntFromFloat from {} to {}", .{
182220 if (dst_bits > 128) return self.fail("TODO implement airIntFromFloat from {f} to {f}", .{
182251182221 src_ty.fmt(pt), dst_ty.fmt(pt),
182252182222 });
182253182223
......@@ -182531,7 +182501,7 @@ fn atomicOp(
182531182501 else => null,
182532182502 },
182533182503 else => unreachable,
182534 }) orelse return self.fail("TODO implement atomicOp of {s} for {}", .{
182504 }) orelse return self.fail("TODO implement atomicOp of {s} for {f}", .{
182535182505 @tagName(op), val_ty.fmt(pt),
182536182506 });
182537182507 try self.genSetReg(sse_reg, val_ty, .{ .register = .rax }, .{});
......@@ -183286,7 +183256,7 @@ fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
183286183256 else => unreachable,
183287183257 },
183288183258 }
183289 return self.fail("TODO implement airSplat for {}", .{vector_ty.fmt(pt)});
183259 return self.fail("TODO implement airSplat for {f}", .{vector_ty.fmt(pt)});
183290183260 };
183291183261 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
183292183262}
......@@ -183322,12 +183292,12 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
183322183292 else
183323183293 try self.copyToTmpRegister(pred_ty, pred_mcv)
183324183294 else
183325 return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)}),
183295 return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)}),
183326183296 else => unreachable,
183327183297 },
183328183298 .register_mask => |pred_reg_mask| {
183329183299 if (pred_reg_mask.info.scalar.bitSize(self.target) != 8 * elem_abi_size)
183330 return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
183300 return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)});
183331183301
183332183302 const mask_reg: Register = if (need_xmm0 and pred_reg_mask.reg.id() != comptime Register.xmm0.id()) mask_reg: {
183333183303 try self.register_manager.getKnownReg(.xmm0, null);
......@@ -183401,7 +183371,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
183401183371 else
183402183372 null
183403183373 else
183404 null) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
183374 null) orelse return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)});
183405183375 if (has_avx) {
183406183376 const rhs_alias = if (reuse_mcv.isRegister())
183407183377 registerAlias(reuse_mcv.getReg().?, abi_size)
......@@ -183554,7 +183524,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
183554183524 else => unreachable,
183555183525 }),
183556183526 );
183557 } else return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
183527 } else return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)});
183558183528 const elem_bits: u16 = @intCast(elem_abi_size * 8);
183559183529 if (!pred_fits_in_elem) if (self.hasFeature(.ssse3)) {
183560183530 const mask_len = elem_abi_size * vec_len;
......@@ -183583,7 +183553,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
183583183553 mask_alias,
183584183554 mask_mem,
183585183555 );
183586 } else return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
183556 } else return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)});
183587183557 {
183588183558 const mask_elem_ty = try pt.intType(.unsigned, elem_bits);
183589183559 const mask_ty = try pt.vectorType(.{ .len = vec_len, .child = mask_elem_ty.toIntern() });
......@@ -183706,7 +183676,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
183706183676 else => null,
183707183677 },
183708183678 },
183709 }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
183679 }) orelse return self.fail("TODO implement airSelect for {f}", .{ty.fmt(pt)});
183710183680 if (has_avx) {
183711183681 const rhs_alias = if (rhs_mcv.isRegister())
183712183682 registerAlias(rhs_mcv.getReg().?, abi_size)
......@@ -184551,7 +184521,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
184551184521 }
184552184522
184553184523 break :result null;
184554 }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{
184524 }) orelse return self.fail("TODO implement airShuffle from {f} and {f} to {f} with {f}", .{
184555184525 lhs_ty.fmt(pt),
184556184526 rhs_ty.fmt(pt),
184557184527 dst_ty.fmt(pt),
......@@ -184800,7 +184770,7 @@ fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void {
184800184770 32, 64 => !self.hasFeature(.fma),
184801184771 else => unreachable,
184802184772 }) {
184803 if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement airMulAdd for {}", .{
184773 if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement airMulAdd for {f}", .{
184804184774 ty.fmt(pt),
184805184775 });
184806184776
......@@ -184930,7 +184900,7 @@ fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void {
184930184900 else => unreachable,
184931184901 }
184932184902 else
184933 unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{ty.fmt(pt)});
184903 unreachable) orelse return self.fail("TODO implement airMulAdd for {f}", .{ty.fmt(pt)});
184934184904
184935184905 var mops: [3]MCValue = undefined;
184936184906 for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv;
......@@ -185130,7 +185100,7 @@ fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void {
185130185100 assert(classes.len == 1);
185131185101 unreachable;
185132185102 },
185133 else => return self.fail("TODO implement c_va_arg for {} on SysV", .{promote_ty.fmt(pt)}),
185103 else => return self.fail("TODO implement c_va_arg for {f} on SysV", .{promote_ty.fmt(pt)}),
185134185104 }
185135185105
185136185106 if (unused) break :result .unreach;
......@@ -185779,7 +185749,7 @@ fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Ty
185779185749 for (parts) |part| part_sizes += part.abiSize(zcu);
185780185750 if (part_sizes == ty.abiSize(zcu)) return parts;
185781185751 };
185782 return self.fail("TODO implement splitType({d}, {})", .{ parts_len, ty.fmt(pt) });
185752 return self.fail("TODO implement splitType({d}, {f})", .{ parts_len, ty.fmt(pt) });
185783185753}
185784185754
185785185755/// Truncates the value in the register in place.
......@@ -186153,7 +186123,7 @@ const Temp = struct {
186153186123 cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
186154186124 const mcv = temp.tracking(cg).short;
186155186125 switch (mcv) {
186156 else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
186126 else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }),
186157186127 .register => |reg| {
186158186128 const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
186159186129 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
......@@ -186227,7 +186197,7 @@ const Temp = struct {
186227186197 const new_temp_index = cg.next_temp_index;
186228186198 cg.temp_type[@intFromEnum(new_temp_index)] = limb_ty;
186229186199 switch (temp.tracking(cg).short) {
186230 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
186200 else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }),
186231186201 .immediate => |imm| {
186232186202 assert(limb_index == 0);
186233186203 new_temp_index.tracking(cg).* = .init(.{ .immediate = imm });
......@@ -186568,7 +186538,7 @@ const Temp = struct {
186568186538 },
186569186539 else => {},
186570186540 }
186571 std.debug.panic("{s}: {} {}\n", .{ @src().fn_name, temp_tracking, overflow_temp_tracking });
186541 std.debug.panic("{s}: {f} {f}\n", .{ @src().fn_name, temp_tracking, overflow_temp_tracking });
186572186542 }
186573186543
186574186544 fn asMask(temp: Temp, info: MaskInfo, cg: *CodeGen) void {
......@@ -186658,7 +186628,7 @@ const Temp = struct {
186658186628 while (try ptr.toLea(cg)) {}
186659186629 const val_mcv = val.tracking(cg).short;
186660186630 switch (val_mcv) {
186661 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
186631 else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }),
186662186632 .register => |val_reg| try ptr.loadReg(val_ty, registerAlias(
186663186633 val_reg,
186664186634 @intCast(val_ty.abiSize(cg.pt.zcu)),
......@@ -186698,7 +186668,7 @@ const Temp = struct {
186698186668 {}) {
186699186669 const val_mcv = val.tracking(cg).short;
186700186670 switch (val_mcv) {
186701 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
186671 else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }),
186702186672 .undef => if (opts.safe) {
186703186673 var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa });
186704186674 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
......@@ -186772,7 +186742,7 @@ const Temp = struct {
186772186742 assert(!val_ty.optionalReprIsPayload(cg.pt.zcu));
186773186743 break :first_ty opt_child;
186774186744 },
186775 else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }),
186745 else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }),
186776186746 });
186777186747 const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu));
186778186748 try ptr.storeRegs(first_ty, &.{registerAlias(val_reg_ov.reg, first_size)}, cg);
......@@ -186804,7 +186774,7 @@ const Temp = struct {
186804186774
186805186775 fn readTo(src: *Temp, val_ty: Type, val_mcv: MCValue, opts: AccessOptions, cg: *CodeGen) InnerError!void {
186806186776 switch (val_mcv) {
186807 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
186777 else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }),
186808186778 .register => |val_reg| try src.readReg(opts.disp, val_ty, registerAlias(
186809186779 val_reg,
186810186780 @intCast(cg.unalignedSize(val_ty)),
......@@ -186844,7 +186814,7 @@ const Temp = struct {
186844186814 {}) {
186845186815 const val_mcv = val.tracking(cg).short;
186846186816 switch (val_mcv) {
186847 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
186817 else => |mcv| std.debug.panic("{s}: {f}\n", .{ @src().fn_name, mcv }),
186848186818 .none => {},
186849186819 .undef => if (opts.safe) {
186850186820 var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp));
......@@ -186905,7 +186875,7 @@ const Temp = struct {
186905186875 assert(!val_ty.optionalReprIsPayload(cg.pt.zcu));
186906186876 break :first_ty opt_child;
186907186877 },
186908 else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }),
186878 else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }),
186909186879 });
186910186880 const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu));
186911186881 try dst.writeReg(opts.disp, first_ty, registerAlias(val_reg_ov.reg, first_size), cg);
......@@ -186960,7 +186930,7 @@ const Temp = struct {
186960186930 assert(src_regs.len == std.math.divCeil(u16, int_info.bits, 64) catch unreachable);
186961186931 break :part_ty .u64;
186962186932 } else part_ty: switch (ip.indexToKey(src_ty.toIntern())) {
186963 else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, src_ty.fmt(cg.pt) }),
186933 else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, src_ty.fmt(cg.pt) }),
186964186934 .ptr_type => |ptr_info| {
186965186935 assert(ptr_info.flags.size == .slice);
186966186936 assert(src_regs.len == 2);
......@@ -186971,7 +186941,7 @@ const Temp = struct {
186971186941 break :part_ty try cg.pt.intType(.unsigned, @as(u16, 8) * @min(src_abi_size, 8));
186972186942 },
186973186943 .opt_type => |opt_child| switch (ip.indexToKey(opt_child)) {
186974 else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, src_ty.fmt(cg.pt) }),
186944 else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, src_ty.fmt(cg.pt) }),
186975186945 .ptr_type => |ptr_info| {
186976186946 assert(ptr_info.flags.size == .slice);
186977186947 assert(src_regs.len == 2);
......@@ -191677,12 +191647,12 @@ const Temp = struct {
191677191647 break :result result;
191678191648 },
191679191649 };
191680 tracking_log.debug("{} => {} (birth)", .{ inst, result });
191650 tracking_log.debug("{f} => {f} (birth)", .{ inst, result });
191681191651 cg.inst_tracking.putAssumeCapacityNoClobber(inst, .init(result));
191682191652 },
191683191653 .temp => |temp_index| {
191684191654 const temp_tracking = temp_index.tracking(cg);
191685 tracking_log.debug("{} => {} (birth)", .{ inst, temp_tracking.short });
191655 tracking_log.debug("{f} => {f} (birth)", .{ inst, temp_tracking.short });
191686191656 cg.inst_tracking.putAssumeCapacityNoClobber(inst, .init(temp_tracking.short));
191687191657 assert(cg.reuseTemp(inst, temp_index.toIndex(), temp_tracking));
191688191658 },
......@@ -191757,7 +191727,7 @@ fn resetTemps(cg: *CodeGen, from_index: Temp.Index) InnerError!void {
191757191727 const temp: Temp.Index = @enumFromInt(temp_index);
191758191728 if (temp.isValid(cg)) {
191759191729 any_valid = true;
191760 tracking_log.err("failed to kill {}: {}", .{
191730 tracking_log.err("failed to kill {f}: {f}", .{
191761191731 temp.toIndex(),
191762191732 cg.temp_type[temp_index].fmt(cg.pt),
191763191733 });
src/arch/x86_64/Emit.zig+8-1
......@@ -707,7 +707,14 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
707707 const comp = emit.bin_file.comp;
708708 const gpa = comp.gpa;
709709 const start_offset: u32 = @intCast(emit.code.items.len);
710 try lowered_inst.encode(emit.code.writer(gpa), .{});
710 {
711 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, emit.code);
712 defer emit.code.* = aw.toArrayList();
713 lowered_inst.encode(&aw.writer, .{}) catch |err| switch (err) {
714 error.WriteFailed => return error.OutOfMemory,
715 else => |e| return e,
716 };
717 }
711718 const end_offset: u32 = @intCast(emit.code.items.len);
712719 for (reloc_info) |reloc| switch (reloc.target.type) {
713720 .inst => {
src/arch/x86_64/Encoding.zig+16-15
......@@ -158,15 +158,7 @@ pub fn modRmExt(encoding: Encoding) u3 {
158158 };
159159}
160160
161pub fn format(
162 encoding: Encoding,
163 comptime fmt: []const u8,
164 options: std.fmt.FormatOptions,
165 writer: anytype,
166) !void {
167 _ = options;
168 _ = fmt;
169
161pub fn format(encoding: Encoding, writer: *std.io.Writer) std.io.Writer.Error!void {
170162 var opc = encoding.opcode();
171163 if (encoding.data.mode.isVex()) {
172164 try writer.writeAll("VEX.");
......@@ -187,7 +179,7 @@ pub fn format(
187179 },
188180 }
189181
190 try writer.print(".{}", .{std.fmt.fmtSliceHexUpper(opc[0 .. opc.len - 1])});
182 try writer.print(".{X}", .{opc[0 .. opc.len - 1]});
191183 opc = opc[opc.len - 1 ..];
192184
193185 try writer.writeAll(".W");
......@@ -1014,19 +1006,28 @@ pub const Feature = enum {
10141006};
10151007
10161008fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Operand) usize {
1017 var inst = Instruction{
1009 var inst: Instruction = .{
10181010 .prefix = prefix,
10191011 .encoding = encoding,
10201012 .ops = @splat(.none),
10211013 };
10221014 @memcpy(inst.ops[0..ops.len], ops);
10231015
1024 var cwriter = std.io.countingWriter(std.io.null_writer);
1025 inst.encode(cwriter.writer(), .{
1016 // By using a buffer with maximum length of encoded instruction, we can use
1017 // the `end` field of the Writer for the count.
1018 var buf: [16]u8 = undefined;
1019 var trash: std.io.Writer.Discarding = .init(&buf);
1020 inst.encode(&trash.writer, .{
10261021 .allow_frame_locs = true,
10271022 .allow_symbols = true,
1028 }) catch unreachable; // Not allowed to fail here unless OOM.
1029 return @as(usize, @intCast(cwriter.bytes_written));
1023 }) catch {
1024 // Since the function signature for encode() does not mention under what
1025 // conditions it can fail, I have changed `unreachable` to `@panic` here.
1026 // This is a TODO item since it indicates this function
1027 // (`estimateInstructionLength`) has the wrong function signature.
1028 @panic("unexpected failure to encode");
1029 };
1030 return trash.writer.end;
10301031}
10311032
10321033const mnemonic_to_encodings_map = init: {
src/arch/x86_64/bits.zig+2-29
......@@ -727,23 +727,6 @@ pub const FrameIndex = enum(u32) {
727727 pub fn isNamed(fi: FrameIndex) bool {
728728 return @intFromEnum(fi) < named_count;
729729 }
730
731 pub fn format(
732 fi: FrameIndex,
733 comptime fmt: []const u8,
734 options: std.fmt.FormatOptions,
735 writer: anytype,
736 ) @TypeOf(writer).Error!void {
737 try writer.writeAll("FrameIndex");
738 if (fi.isNamed()) {
739 try writer.writeByte('.');
740 try writer.writeAll(@tagName(fi));
741 } else {
742 try writer.writeByte('(');
743 try std.fmt.formatType(@intFromEnum(fi), fmt, options, writer, 0);
744 try writer.writeByte(')');
745 }
746 }
747730};
748731
749732pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
......@@ -844,12 +827,7 @@ pub const Memory = struct {
844827 };
845828 }
846829
847 pub fn format(
848 s: Size,
849 comptime _: []const u8,
850 _: std.fmt.FormatOptions,
851 writer: anytype,
852 ) @TypeOf(writer).Error!void {
830 pub fn format(s: Size, writer: *std.io.Writer) std.io.Writer.Error!void {
853831 if (s == .none) return;
854832 try writer.writeAll(@tagName(s));
855833 switch (s) {
......@@ -914,12 +892,7 @@ pub const Immediate = union(enum) {
914892 return .{ .signed = x };
915893 }
916894
917 pub fn format(
918 imm: Immediate,
919 comptime _: []const u8,
920 _: std.fmt.FormatOptions,
921 writer: anytype,
922 ) @TypeOf(writer).Error!void {
895 pub fn format(imm: Immediate, writer: *std.io.Writer) std.io.Writer.Error!void {
923896 switch (imm) {
924897 inline else => |int| try writer.print("{d}", .{int}),
925898 .nav => |nav_off| try writer.print("Nav({d}) + {d}", .{ @intFromEnum(nav_off.nav), nav_off.off }),
src/arch/x86_64/encoder.zig+111-138
......@@ -3,6 +3,7 @@ const assert = std.debug.assert;
33const log = std.log.scoped(.x86_64_encoder);
44const math = std.math;
55const testing = std.testing;
6const Writer = std.io.Writer;
67
78const bits = @import("bits.zig");
89const Encoding = @import("Encoding.zig");
......@@ -226,101 +227,81 @@ pub const Instruction = struct {
226227 };
227228 }
228229
229 fn format(
230 op: Operand,
231 comptime unused_format_string: []const u8,
232 options: std.fmt.FormatOptions,
233 writer: anytype,
234 ) !void {
235 _ = op;
236 _ = unused_format_string;
237 _ = options;
238 _ = writer;
239 @compileError("do not format Operand directly; use fmt() instead");
240 }
241
242 const FormatContext = struct {
230 const Format = struct {
243231 op: Operand,
244232 enc_op: Encoding.Op,
245 };
246233
247 fn fmtContext(
248 ctx: FormatContext,
249 comptime unused_format_string: []const u8,
250 options: std.fmt.FormatOptions,
251 writer: anytype,
252 ) @TypeOf(writer).Error!void {
253 _ = unused_format_string;
254 _ = options;
255 const op = ctx.op;
256 const enc_op = ctx.enc_op;
257 switch (op) {
258 .none => {},
259 .reg => |reg| try writer.writeAll(@tagName(reg)),
260 .mem => |mem| switch (mem) {
261 .rip => |rip| {
262 try writer.print("{} [rip", .{rip.ptr_size});
263 if (rip.disp != 0) try writer.print(" {c} 0x{x}", .{
264 @as(u8, if (rip.disp < 0) '-' else '+'),
265 @abs(rip.disp),
266 });
267 try writer.writeByte(']');
268 },
269 .sib => |sib| {
270 try writer.print("{} ", .{sib.ptr_size});
234 fn default(f: Format, w: *Writer) Writer.Error!void {
235 const op = f.op;
236 const enc_op = f.enc_op;
237 switch (op) {
238 .none => {},
239 .reg => |reg| try w.writeAll(@tagName(reg)),
240 .mem => |mem| switch (mem) {
241 .rip => |rip| {
242 try w.print("{f} [rip", .{rip.ptr_size});
243 if (rip.disp != 0) try w.print(" {c} 0x{x}", .{
244 @as(u8, if (rip.disp < 0) '-' else '+'),
245 @abs(rip.disp),
246 });
247 try w.writeByte(']');
248 },
249 .sib => |sib| {
250 try w.print("{f} ", .{sib.ptr_size});
271251
272 if (mem.isSegmentRegister()) {
273 return writer.print("{s}:0x{x}", .{ @tagName(sib.base.reg), sib.disp });
274 }
252 if (mem.isSegmentRegister()) {
253 return w.print("{s}:0x{x}", .{ @tagName(sib.base.reg), sib.disp });
254 }
275255
276 try writer.writeByte('[');
277
278 var any = true;
279 switch (sib.base) {
280 .none => any = false,
281 .reg => |reg| try writer.print("{s}", .{@tagName(reg)}),
282 .frame => |frame_index| try writer.print("{}", .{frame_index}),
283 .table => try writer.print("Table", .{}),
284 .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),
285 .nav => |nav| try writer.print("Nav({d})", .{@intFromEnum(nav)}),
286 .uav => |uav| try writer.print("Uav({d})", .{@intFromEnum(uav.val)}),
287 .lazy_sym => |lazy_sym| try writer.print("LazySym({s}, {d})", .{
288 @tagName(lazy_sym.kind),
289 @intFromEnum(lazy_sym.ty),
290 }),
291 .extern_func => |extern_func| try writer.print("ExternFunc({d})", .{@intFromEnum(extern_func)}),
292 }
293 if (mem.scaleIndex()) |si| {
294 if (any) try writer.writeAll(" + ");
295 try writer.print("{s} * {d}", .{ @tagName(si.index), si.scale });
296 any = true;
297 }
298 if (sib.disp != 0 or !any) {
299 if (any)
300 try writer.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
301 else if (sib.disp < 0)
302 try writer.writeByte('-');
303 try writer.print("0x{x}", .{@abs(sib.disp)});
304 any = true;
305 }
256 try w.writeByte('[');
257
258 var any = true;
259 switch (sib.base) {
260 .none => any = false,
261 .reg => |reg| try w.print("{s}", .{@tagName(reg)}),
262 .frame => |frame_index| try w.print("{}", .{frame_index}),
263 .table => try w.print("Table", .{}),
264 .rip_inst => |inst_index| try w.print("RipInst({d})", .{inst_index}),
265 .nav => |nav| try w.print("Nav({d})", .{@intFromEnum(nav)}),
266 .uav => |uav| try w.print("Uav({d})", .{@intFromEnum(uav.val)}),
267 .lazy_sym => |lazy_sym| try w.print("LazySym({s}, {d})", .{
268 @tagName(lazy_sym.kind),
269 @intFromEnum(lazy_sym.ty),
270 }),
271 .extern_func => |extern_func| try w.print("ExternFunc({d})", .{@intFromEnum(extern_func)}),
272 }
273 if (mem.scaleIndex()) |si| {
274 if (any) try w.writeAll(" + ");
275 try w.print("{s} * {d}", .{ @tagName(si.index), si.scale });
276 any = true;
277 }
278 if (sib.disp != 0 or !any) {
279 if (any)
280 try w.print(" {c} ", .{@as(u8, if (sib.disp < 0) '-' else '+')})
281 else if (sib.disp < 0)
282 try w.writeByte('-');
283 try w.print("0x{x}", .{@abs(sib.disp)});
284 any = true;
285 }
306286
307 try writer.writeByte(']');
287 try w.writeByte(']');
288 },
289 .moffs => |moffs| try w.print("{s}:0x{x}", .{
290 @tagName(moffs.seg),
291 moffs.offset,
292 }),
308293 },
309 .moffs => |moffs| try writer.print("{s}:0x{x}", .{
310 @tagName(moffs.seg),
311 moffs.offset,
312 }),
313 },
314 .imm => |imm| if (enc_op.isSigned()) {
315 const imms = imm.asSigned(enc_op.immBitSize());
316 if (imms < 0) try writer.writeByte('-');
317 try writer.print("0x{x}", .{@abs(imms)});
318 } else try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
319 .bytes => unreachable,
294 .imm => |imm| if (enc_op.isSigned()) {
295 const imms = imm.asSigned(enc_op.immBitSize());
296 if (imms < 0) try w.writeByte('-');
297 try w.print("0x{x}", .{@abs(imms)});
298 } else try w.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
299 .bytes => unreachable,
300 }
320301 }
321 }
302 };
322303
323 pub fn fmt(op: Operand, enc_op: Encoding.Op) std.fmt.Formatter(fmtContext) {
304 pub fn fmt(op: Operand, enc_op: Encoding.Op) std.fmt.Formatter(Format, Format.default) {
324305 return .{ .data = .{ .op = op, .enc_op = enc_op } };
325306 }
326307 };
......@@ -361,7 +342,7 @@ pub const Instruction = struct {
361342 },
362343 },
363344 };
364 log.debug("selected encoding: {}", .{encoding});
345 log.debug("selected encoding: {f}", .{encoding});
365346
366347 var inst: Instruction = .{
367348 .prefix = prefix,
......@@ -372,30 +353,22 @@ pub const Instruction = struct {
372353 return inst;
373354 }
374355
375 pub fn format(
376 inst: Instruction,
377 comptime unused_format_string: []const u8,
378 options: std.fmt.FormatOptions,
379 writer: anytype,
380 ) @TypeOf(writer).Error!void {
381 _ = unused_format_string;
382 _ = options;
356 pub fn format(inst: Instruction, w: *Writer) Writer.Error!void {
383357 switch (inst.prefix) {
384358 .none, .directive => {},
385 else => try writer.print("{s} ", .{@tagName(inst.prefix)}),
359 else => try w.print("{s} ", .{@tagName(inst.prefix)}),
386360 }
387 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
361 try w.print("{s}", .{@tagName(inst.encoding.mnemonic)});
388362 for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {
389363 if (op == .none) break;
390 if (i > 0) try writer.writeByte(',');
391 try writer.writeByte(' ');
392 try writer.print("{}", .{op.fmt(enc)});
364 if (i > 0) try w.writeByte(',');
365 try w.print(" {f}", .{op.fmt(enc)});
393366 }
394367 }
395368
396 pub fn encode(inst: Instruction, writer: anytype, comptime opts: Options) !void {
369 pub fn encode(inst: Instruction, w: *Writer, comptime opts: Options) !void {
397370 assert(inst.prefix != .directive);
398 const encoder = Encoder(@TypeOf(writer), opts){ .writer = writer };
371 const encoder: Encoder(opts) = .{ .w = w };
399372 const enc = inst.encoding;
400373 const data = enc.data;
401374
......@@ -801,9 +774,9 @@ pub const LegacyPrefixes = packed struct {
801774
802775pub const Options = struct { allow_frame_locs: bool = false, allow_symbols: bool = false };
803776
804fn Encoder(comptime T: type, comptime opts: Options) type {
777fn Encoder(comptime opts: Options) type {
805778 return struct {
806 writer: T,
779 w: *Writer,
807780
808781 const Self = @This();
809782 pub const options = opts;
......@@ -818,31 +791,31 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
818791 // Hopefully this path isn't taken very often, so we'll do it the slow way for now
819792
820793 // LOCK
821 if (prefixes.prefix_f0) try self.writer.writeByte(0xf0);
794 if (prefixes.prefix_f0) try self.w.writeByte(0xf0);
822795 // REPNZ, REPNE, REP, Scalar Double-precision
823 if (prefixes.prefix_f2) try self.writer.writeByte(0xf2);
796 if (prefixes.prefix_f2) try self.w.writeByte(0xf2);
824797 // REPZ, REPE, REP, Scalar Single-precision
825 if (prefixes.prefix_f3) try self.writer.writeByte(0xf3);
798 if (prefixes.prefix_f3) try self.w.writeByte(0xf3);
826799
827800 // CS segment override or Branch not taken
828 if (prefixes.prefix_2e) try self.writer.writeByte(0x2e);
801 if (prefixes.prefix_2e) try self.w.writeByte(0x2e);
829802 // DS segment override
830 if (prefixes.prefix_36) try self.writer.writeByte(0x36);
803 if (prefixes.prefix_36) try self.w.writeByte(0x36);
831804 // ES segment override
832 if (prefixes.prefix_26) try self.writer.writeByte(0x26);
805 if (prefixes.prefix_26) try self.w.writeByte(0x26);
833806 // FS segment override
834 if (prefixes.prefix_64) try self.writer.writeByte(0x64);
807 if (prefixes.prefix_64) try self.w.writeByte(0x64);
835808 // GS segment override
836 if (prefixes.prefix_65) try self.writer.writeByte(0x65);
809 if (prefixes.prefix_65) try self.w.writeByte(0x65);
837810
838811 // Branch taken
839 if (prefixes.prefix_3e) try self.writer.writeByte(0x3e);
812 if (prefixes.prefix_3e) try self.w.writeByte(0x3e);
840813
841814 // Operand size override
842 if (prefixes.prefix_66) try self.writer.writeByte(0x66);
815 if (prefixes.prefix_66) try self.w.writeByte(0x66);
843816
844817 // Address size override
845 if (prefixes.prefix_67) try self.writer.writeByte(0x67);
818 if (prefixes.prefix_67) try self.w.writeByte(0x67);
846819 }
847820 }
848821
......@@ -850,7 +823,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
850823 ///
851824 /// Note that this flag is overridden by REX.W, if both are present.
852825 pub fn prefix16BitMode(self: Self) !void {
853 try self.writer.writeByte(0x66);
826 try self.w.writeByte(0x66);
854827 }
855828
856829 /// Encodes a REX prefix byte given all the fields
......@@ -869,7 +842,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
869842 if (fields.x) byte |= 0b0010;
870843 if (fields.b) byte |= 0b0001;
871844
872 try self.writer.writeByte(byte);
845 try self.w.writeByte(byte);
873846 }
874847
875848 /// Encodes a VEX prefix given all the fields
......@@ -877,24 +850,24 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
877850 /// See struct `Vex` for a description of each field.
878851 pub fn vex(self: Self, fields: Vex) !void {
879852 if (fields.is3Byte()) {
880 try self.writer.writeByte(0b1100_0100);
853 try self.w.writeByte(0b1100_0100);
881854
882 try self.writer.writeByte(
855 try self.w.writeByte(
883856 @as(u8, ~@intFromBool(fields.r)) << 7 |
884857 @as(u8, ~@intFromBool(fields.x)) << 6 |
885858 @as(u8, ~@intFromBool(fields.b)) << 5 |
886859 @as(u8, @intFromEnum(fields.m)) << 0,
887860 );
888861
889 try self.writer.writeByte(
862 try self.w.writeByte(
890863 @as(u8, @intFromBool(fields.w)) << 7 |
891864 @as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 |
892865 @as(u8, @intFromBool(fields.l)) << 2 |
893866 @as(u8, @intFromEnum(fields.p)) << 0,
894867 );
895868 } else {
896 try self.writer.writeByte(0b1100_0101);
897 try self.writer.writeByte(
869 try self.w.writeByte(0b1100_0101);
870 try self.w.writeByte(
898871 @as(u8, ~@intFromBool(fields.r)) << 7 |
899872 @as(u8, ~@as(u4, @intCast(fields.v.enc()))) << 3 |
900873 @as(u8, @intFromBool(fields.l)) << 2 |
......@@ -909,7 +882,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
909882
910883 /// Encodes a 1 byte opcode
911884 pub fn opcode_1byte(self: Self, opcode: u8) !void {
912 try self.writer.writeByte(opcode);
885 try self.w.writeByte(opcode);
913886 }
914887
915888 /// Encodes a 2 byte opcode
......@@ -918,7 +891,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
918891 ///
919892 /// encoder.opcode_2byte(0x0f, 0xaf);
920893 pub fn opcode_2byte(self: Self, prefix: u8, opcode: u8) !void {
921 try self.writer.writeAll(&.{ prefix, opcode });
894 try self.w.writeAll(&.{ prefix, opcode });
922895 }
923896
924897 /// Encodes a 3 byte opcode
......@@ -927,7 +900,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
927900 ///
928901 /// encoder.opcode_3byte(0xf2, 0x0f, 0x10);
929902 pub fn opcode_3byte(self: Self, prefix_1: u8, prefix_2: u8, opcode: u8) !void {
930 try self.writer.writeAll(&.{ prefix_1, prefix_2, opcode });
903 try self.w.writeAll(&.{ prefix_1, prefix_2, opcode });
931904 }
932905
933906 /// Encodes a 1 byte opcode with a reg field
......@@ -935,7 +908,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
935908 /// Remember to add a REX prefix byte if reg is extended!
936909 pub fn opcode_withReg(self: Self, opcode: u8, reg: u3) !void {
937910 assert(opcode & 0b111 == 0);
938 try self.writer.writeByte(opcode | reg);
911 try self.w.writeByte(opcode | reg);
939912 }
940913
941914 // ------
......@@ -946,7 +919,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
946919 ///
947920 /// Remember to add a REX prefix byte if reg or rm are extended!
948921 pub fn modRm(self: Self, mod: u2, reg_or_opx: u3, rm: u3) !void {
949 try self.writer.writeByte(@as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm);
922 try self.w.writeByte(@as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm);
950923 }
951924
952925 /// Construct a ModR/M byte using direct r/m addressing
......@@ -1032,7 +1005,7 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
10321005 ///
10331006 /// Remember to add a REX prefix byte if index or base are extended!
10341007 pub fn sib(self: Self, scale: u2, index: u3, base: u3) !void {
1035 try self.writer.writeByte(@as(u8, scale) << 6 | @as(u8, index) << 3 | base);
1008 try self.w.writeByte(@as(u8, scale) << 6 | @as(u8, index) << 3 | base);
10361009 }
10371010
10381011 /// Construct a SIB byte with scale * index + base, no frills.
......@@ -1124,42 +1097,42 @@ fn Encoder(comptime T: type, comptime opts: Options) type {
11241097 ///
11251098 /// It is sign-extended to 64 bits by the cpu.
11261099 pub fn disp8(self: Self, disp: i8) !void {
1127 try self.writer.writeByte(@as(u8, @bitCast(disp)));
1100 try self.w.writeByte(@as(u8, @bitCast(disp)));
11281101 }
11291102
11301103 /// Encode an 32 bit displacement
11311104 ///
11321105 /// It is sign-extended to 64 bits by the cpu.
11331106 pub fn disp32(self: Self, disp: i32) !void {
1134 try self.writer.writeInt(i32, disp, .little);
1107 try self.w.writeInt(i32, disp, .little);
11351108 }
11361109
11371110 /// Encode an 8 bit immediate
11381111 ///
11391112 /// It is sign-extended to 64 bits by the cpu.
11401113 pub fn imm8(self: Self, imm: u8) !void {
1141 try self.writer.writeByte(imm);
1114 try self.w.writeByte(imm);
11421115 }
11431116
11441117 /// Encode an 16 bit immediate
11451118 ///
11461119 /// It is sign-extended to 64 bits by the cpu.
11471120 pub fn imm16(self: Self, imm: u16) !void {
1148 try self.writer.writeInt(u16, imm, .little);
1121 try self.w.writeInt(u16, imm, .little);
11491122 }
11501123
11511124 /// Encode an 32 bit immediate
11521125 ///
11531126 /// It is sign-extended to 64 bits by the cpu.
11541127 pub fn imm32(self: Self, imm: u32) !void {
1155 try self.writer.writeInt(u32, imm, .little);
1128 try self.w.writeInt(u32, imm, .little);
11561129 }
11571130
11581131 /// Encode an 64 bit immediate
11591132 ///
11601133 /// It is sign-extended to 64 bits by the cpu.
11611134 pub fn imm64(self: Self, imm: u64) !void {
1162 try self.writer.writeInt(u64, imm, .little);
1135 try self.w.writeInt(u64, imm, .little);
11631136 }
11641137 };
11651138}
......@@ -1205,9 +1178,9 @@ pub const Vex = struct {
12051178fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []const u8) !void {
12061179 assert(expected.len > 0);
12071180 if (std.mem.eql(u8, expected, given)) return;
1208 const expected_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{std.fmt.fmtSliceHexLower(expected)});
1181 const expected_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{expected});
12091182 defer testing.allocator.free(expected_fmt);
1210 const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{std.fmt.fmtSliceHexLower(given)});
1183 const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{given});
12111184 defer testing.allocator.free(given_fmt);
12121185 const idx = std.mem.indexOfDiff(u8, expected_fmt, given_fmt).?;
12131186 const padding = try testing.allocator.alloc(u8, idx + 5);
......@@ -2217,10 +2190,10 @@ const Assembler = struct {
22172190 };
22182191 }
22192192
2220 pub fn assemble(as: *Assembler, writer: anytype) !void {
2193 pub fn assemble(as: *Assembler, w: *Writer) !void {
22212194 while (try as.next()) |parsed_inst| {
22222195 const inst: Instruction = try .new(.none, parsed_inst.mnemonic, &parsed_inst.ops);
2223 try inst.encode(writer, .{});
2196 try inst.encode(w, .{});
22242197 }
22252198 }
22262199
src/codegen.zig+6-6
......@@ -237,7 +237,7 @@ pub fn generateLazySymbol(
237237 const target = &comp.root_mod.resolved_target.result;
238238 const endian = target.cpu.arch.endian();
239239
240 log.debug("generateLazySymbol: kind = {s}, ty = {}", .{
240 log.debug("generateLazySymbol: kind = {s}, ty = {f}", .{
241241 @tagName(lazy_sym.kind),
242242 Type.fromInterned(lazy_sym.ty).fmt(pt),
243243 });
......@@ -277,7 +277,7 @@ pub fn generateLazySymbol(
277277 code.appendAssumeCapacity(0);
278278 }
279279 } else {
280 return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {}", .{
280 return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{
281281 @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt),
282282 });
283283 }
......@@ -310,7 +310,7 @@ pub fn generateSymbol(
310310 const target = zcu.getTarget();
311311 const endian = target.cpu.arch.endian();
312312
313 log.debug("generateSymbol: val = {}", .{val.fmtValue(pt)});
313 log.debug("generateSymbol: val = {f}", .{val.fmtValue(pt)});
314314
315315 if (val.isUndefDeep(zcu)) {
316316 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
......@@ -767,7 +767,7 @@ fn lowerUavRef(
767767 const uav_ty = Type.fromInterned(ip.typeOf(uav_val));
768768 const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn";
769769
770 log.debug("lowerUavRef: ty = {}", .{uav_ty.fmt(pt)});
770 log.debug("lowerUavRef: ty = {f}", .{uav_ty.fmt(pt)});
771771 try code.ensureUnusedCapacity(gpa, ptr_width_bytes);
772772
773773 if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) {
......@@ -913,7 +913,7 @@ pub fn genNavRef(
913913 const zcu = pt.zcu;
914914 const ip = &zcu.intern_pool;
915915 const nav = ip.getNav(nav_index);
916 log.debug("genNavRef({})", .{nav.fqn.fmt(ip)});
916 log.debug("genNavRef({f})", .{nav.fqn.fmt(ip)});
917917
918918 const lib_name, const linkage, const is_threadlocal = if (nav.getExtern(ip)) |e|
919919 .{ e.lib_name, e.linkage, e.is_threadlocal and zcu.comp.config.any_non_single_threaded }
......@@ -1065,7 +1065,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
10651065 const ip = &zcu.intern_pool;
10661066 const ty = val.typeOf(zcu);
10671067
1068 log.debug("lowerValue(@as({}, {}))", .{ ty.fmt(pt), val.fmtValue(pt) });
1068 log.debug("lowerValue(@as({f}, {f}))", .{ ty.fmt(pt), val.fmtValue(pt) });
10691069
10701070 if (val.isUndef(zcu)) return .undef;
10711071
src/codegen/c.zig+2215-2164
......@@ -4,6 +4,7 @@ const assert = std.debug.assert;
44const mem = std.mem;
55const log = std.log.scoped(.c);
66const Allocator = mem.Allocator;
7const Writer = std.io.Writer;
78
89const dev = @import("../dev.zig");
910const link = @import("../link.zig");
......@@ -55,6 +56,7 @@ pub const Mir = struct {
5556 /// less than the natural alignment.
5657 uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
5758 // These remaining fields are essentially just an owned version of `link.C.AvBlock`.
59 code_header: []u8,
5860 code: []u8,
5961 fwd_decl: []u8,
6062 ctype_pool: CType.Pool,
......@@ -62,6 +64,7 @@ pub const Mir = struct {
6264
6365 pub fn deinit(mir: *Mir, gpa: Allocator) void {
6466 mir.uavs.deinit(gpa);
67 gpa.free(mir.code_header);
6568 gpa.free(mir.code);
6669 gpa.free(mir.fwd_decl);
6770 mir.ctype_pool.deinit(gpa);
......@@ -69,6 +72,8 @@ pub const Mir = struct {
6972 }
7073};
7174
75pub const Error = Writer.Error || std.mem.Allocator.Error || error{AnalysisFail};
76
7277pub const CType = @import("c/Type.zig");
7378
7479pub const CValue = union(enum) {
......@@ -340,53 +345,61 @@ fn isReservedIdent(ident: []const u8) bool {
340345 } else return reserved_idents.has(ident);
341346}
342347
343fn formatIdent(
344 ident: []const u8,
345 comptime fmt_str: []const u8,
346 _: std.fmt.FormatOptions,
347 writer: anytype,
348) @TypeOf(writer).Error!void {
349 const solo = fmt_str.len != 0 and fmt_str[0] == ' '; // space means solo; not part of a bigger ident.
348fn formatIdentSolo(ident: []const u8, w: *std.io.Writer) std.io.Writer.Error!void {
349 return formatIdentOptions(ident, w, true);
350}
351
352fn formatIdentUnsolo(ident: []const u8, w: *std.io.Writer) std.io.Writer.Error!void {
353 return formatIdentOptions(ident, w, false);
354}
355
356fn formatIdentOptions(ident: []const u8, w: *std.io.Writer, solo: bool) std.io.Writer.Error!void {
350357 if (solo and isReservedIdent(ident)) {
351 try writer.writeAll("zig_e_");
358 try w.writeAll("zig_e_");
352359 }
353360 for (ident, 0..) |c, i| {
354361 switch (c) {
355 'a'...'z', 'A'...'Z', '_' => try writer.writeByte(c),
356 '.' => try writer.writeByte('_'),
362 'a'...'z', 'A'...'Z', '_' => try w.writeByte(c),
363 '.' => try w.writeByte('_'),
357364 '0'...'9' => if (i == 0) {
358 try writer.print("_{x:2}", .{c});
365 try w.print("_{x:2}", .{c});
359366 } else {
360 try writer.writeByte(c);
367 try w.writeByte(c);
361368 },
362 else => try writer.print("_{x:2}", .{c}),
369 else => try w.print("_{x:2}", .{c}),
363370 }
364371 }
365372}
366pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
373
374pub fn fmtIdentSolo(ident: []const u8) std.fmt.Formatter([]const u8, formatIdentSolo) {
375 return .{ .data = ident };
376}
377
378pub fn fmtIdentUnsolo(ident: []const u8) std.fmt.Formatter([]const u8, formatIdentUnsolo) {
367379 return .{ .data = ident };
368380}
369381
370382const CTypePoolStringFormatData = struct {
371383 ctype_pool_string: CType.Pool.String,
372384 ctype_pool: *const CType.Pool,
385 solo: bool,
373386};
374fn formatCTypePoolString(
375 data: CTypePoolStringFormatData,
376 comptime fmt_str: []const u8,
377 fmt_opts: std.fmt.FormatOptions,
378 writer: anytype,
379) @TypeOf(writer).Error!void {
387fn formatCTypePoolString(data: CTypePoolStringFormatData, w: *std.io.Writer) std.io.Writer.Error!void {
380388 if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice|
381 try formatIdent(slice, fmt_str, fmt_opts, writer)
389 try formatIdentOptions(slice, w, data.solo)
382390 else
383 try writer.print("{}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
391 try w.print("{f}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
384392}
385393pub fn fmtCTypePoolString(
386394 ctype_pool_string: CType.Pool.String,
387395 ctype_pool: *const CType.Pool,
388) std.fmt.Formatter(formatCTypePoolString) {
389 return .{ .data = .{ .ctype_pool_string = ctype_pool_string, .ctype_pool = ctype_pool } };
396 solo: bool,
397) std.fmt.Formatter(CTypePoolStringFormatData, formatCTypePoolString) {
398 return .{ .data = .{
399 .ctype_pool_string = ctype_pool_string,
400 .ctype_pool = ctype_pool,
401 .solo = solo,
402 } };
390403}
391404
392405// Returns true if `formatIdent` would make any edits to ident.
......@@ -440,18 +453,18 @@ pub const Function = struct {
440453 const ty = f.typeOf(ref);
441454
442455 const result: CValue = if (lowersToArray(ty, pt)) result: {
443 const writer = f.object.codeHeaderWriter();
456 const ch = &f.object.code_header.writer;
444457 const decl_c_value = try f.allocLocalValue(.{
445458 .ctype = try f.ctypeFromType(ty, .complete),
446459 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)),
447460 });
448461 const gpa = f.object.dg.gpa;
449462 try f.allocs.put(gpa, decl_c_value.new_local, false);
450 try writer.writeAll("static ");
451 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, .none, .complete);
452 try writer.writeAll(" = ");
453 try f.object.dg.renderValue(writer, val, .StaticInitializer);
454 try writer.writeAll(";\n ");
463 try ch.writeAll("static ");
464 try f.object.dg.renderTypeAndName(ch, ty, decl_c_value, Const, .none, .complete);
465 try ch.writeAll(" = ");
466 try f.object.dg.renderValue(ch, val, .StaticInitializer);
467 try ch.writeAll(";\n ");
455468 break :result .{ .local = decl_c_value.new_local };
456469 } else .{ .constant = val };
457470
......@@ -504,7 +517,7 @@ pub const Function = struct {
504517 return result;
505518 }
506519
507 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {
520 fn writeCValue(f: *Function, w: *Writer, c_value: CValue, location: ValueRenderLocation) !void {
508521 switch (c_value) {
509522 .none => unreachable,
510523 .new_local, .local => |i| try w.print("t{d}", .{i}),
......@@ -517,7 +530,7 @@ pub const Function = struct {
517530 }
518531 }
519532
520 fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void {
533 fn writeCValueDeref(f: *Function, w: *Writer, c_value: CValue) !void {
521534 switch (c_value) {
522535 .none => unreachable,
523536 .new_local, .local, .constant => {
......@@ -538,41 +551,41 @@ pub const Function = struct {
538551
539552 fn writeCValueMember(
540553 f: *Function,
541 writer: anytype,
554 w: *Writer,
542555 c_value: CValue,
543556 member: CValue,
544 ) error{ OutOfMemory, AnalysisFail }!void {
557 ) Error!void {
545558 switch (c_value) {
546559 .new_local, .local, .local_ref, .constant, .arg, .arg_array => {
547 try f.writeCValue(writer, c_value, .Other);
548 try writer.writeByte('.');
549 try f.writeCValue(writer, member, .Other);
560 try f.writeCValue(w, c_value, .Other);
561 try w.writeByte('.');
562 try f.writeCValue(w, member, .Other);
550563 },
551 else => return f.object.dg.writeCValueMember(writer, c_value, member),
564 else => return f.object.dg.writeCValueMember(w, c_value, member),
552565 }
553566 }
554567
555 fn writeCValueDerefMember(f: *Function, writer: anytype, c_value: CValue, member: CValue) !void {
568 fn writeCValueDerefMember(f: *Function, w: *Writer, c_value: CValue, member: CValue) !void {
556569 switch (c_value) {
557570 .new_local, .local, .arg, .arg_array => {
558 try f.writeCValue(writer, c_value, .Other);
559 try writer.writeAll("->");
571 try f.writeCValue(w, c_value, .Other);
572 try w.writeAll("->");
560573 },
561574 .constant => {
562 try writer.writeByte('(');
563 try f.writeCValue(writer, c_value, .Other);
564 try writer.writeAll(")->");
575 try w.writeByte('(');
576 try f.writeCValue(w, c_value, .Other);
577 try w.writeAll(")->");
565578 },
566579 .local_ref => {
567 try f.writeCValueDeref(writer, c_value);
568 try writer.writeByte('.');
580 try f.writeCValueDeref(w, c_value);
581 try w.writeByte('.');
569582 },
570 else => return f.object.dg.writeCValueDerefMember(writer, c_value, member),
583 else => return f.object.dg.writeCValueDerefMember(w, c_value, member),
571584 }
572 try f.writeCValue(writer, member, .Other);
585 try f.writeCValue(w, member, .Other);
573586 }
574587
575 fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
588 fn fail(f: *Function, comptime format: []const u8, args: anytype) Error {
576589 return f.object.dg.fail(format, args);
577590 }
578591
......@@ -584,20 +597,24 @@ pub const Function = struct {
584597 return f.object.dg.byteSize(ctype);
585598 }
586599
587 fn renderType(f: *Function, w: anytype, ctype: Type) !void {
600 fn renderType(f: *Function, w: *Writer, ctype: Type) !void {
588601 return f.object.dg.renderType(w, ctype);
589602 }
590603
591 fn renderCType(f: *Function, w: anytype, ctype: CType) !void {
604 fn renderCType(f: *Function, w: *Writer, ctype: CType) !void {
592605 return f.object.dg.renderCType(w, ctype);
593606 }
594607
595 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void {
608 fn renderIntCast(f: *Function, w: *Writer, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void {
596609 return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src, .v = v } }, src_ty, location);
597610 }
598611
599 fn fmtIntLiteral(f: *Function, val: Value) !std.fmt.Formatter(formatIntLiteral) {
600 return f.object.dg.fmtIntLiteral(val, .Other);
612 fn fmtIntLiteralDec(f: *Function, val: Value) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) {
613 return f.object.dg.fmtIntLiteralDec(val, .Other);
614 }
615
616 fn fmtIntLiteralHex(f: *Function, val: Value) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) {
617 return f.object.dg.fmtIntLiteralHex(val, .Other);
601618 }
602619
603620 fn getLazyFnName(f: *Function, key: LazyFnKey) ![]const u8 {
......@@ -614,16 +631,16 @@ pub const Function = struct {
614631 gop.value_ptr.* = .{
615632 .fn_name = switch (key) {
616633 .tag_name,
617 => |enum_ty| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
634 => |enum_ty| try ctype_pool.fmt(gpa, "zig_{s}_{f}__{d}", .{
618635 @tagName(key),
619 fmtIdent(ip.loadEnumType(enum_ty).name.toSlice(ip)),
636 fmtIdentUnsolo(ip.loadEnumType(enum_ty).name.toSlice(ip)),
620637 @intFromEnum(enum_ty),
621638 }),
622639 .never_tail,
623640 .never_inline,
624 => |owner_nav| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
641 => |owner_nav| try ctype_pool.fmt(gpa, "zig_{s}_{f}__{d}", .{
625642 @tagName(key),
626 fmtIdent(ip.getNav(owner_nav).name.toSlice(ip)),
643 fmtIdentUnsolo(ip.getNav(owner_nav).name.toSlice(ip)),
627644 @intFromEnum(owner_nav),
628645 }),
629646 },
......@@ -659,12 +676,12 @@ pub const Function = struct {
659676 },
660677 else => {},
661678 }
662 const writer = f.object.writer();
663 const a = try Assignment.start(f, writer, ctype);
664 try f.writeCValue(writer, dst, .Other);
665 try a.assign(f, writer);
666 try f.writeCValue(writer, src, .Other);
667 try a.end(f, writer);
679 const w = &f.object.code.writer;
680 const a = try Assignment.start(f, w, ctype);
681 try f.writeCValue(w, dst, .Other);
682 try a.assign(f, w);
683 try f.writeCValue(w, src, .Other);
684 try a.end(f, w);
668685 }
669686
670687 fn moveCValue(f: *Function, inst: Air.Inst.Index, ty: Type, src: CValue) !CValue {
......@@ -693,18 +710,32 @@ pub const Function = struct {
693710/// It is not available when generating .h file.
694711pub const Object = struct {
695712 dg: DeclGen,
696 /// This is a borrowed reference from `link.C`.
697 code: std.ArrayList(u8),
698 /// Goes before code. Initialized and deinitialized in `genFunc`.
699 code_header: std.ArrayList(u8) = undefined,
700 indent_writer: IndentWriter(std.ArrayList(u8).Writer),
701
702 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {
703 return o.indent_writer.writer();
704 }
705
706 fn codeHeaderWriter(o: *Object) ArrayListWriter {
707 return arrayListWriter(&o.code_header);
713 code_header: std.io.Writer.Allocating,
714 code: std.io.Writer.Allocating,
715 indent_counter: usize,
716
717 const indent_width = 1;
718 const indent_char = ' ';
719
720 fn newline(o: *Object) !void {
721 const w = &o.code.writer;
722 try w.writeByte('\n');
723 try w.splatByteAll(indent_char, o.indent_counter);
724 }
725 fn indent(o: *Object) void {
726 o.indent_counter += indent_width;
727 }
728 fn outdent(o: *Object) !void {
729 o.indent_counter -= indent_width;
730 const written = o.code.getWritten();
731 switch (written[written.len - 1]) {
732 indent_char => o.code.shrinkRetainingCapacity(written.len - indent_width),
733 '\n' => try o.code.writer.splatByteAll(indent_char, o.indent_counter),
734 else => {
735 std.debug.print("\"{f}\"\n", .{std.zig.fmtString(written[written.len -| 100..])});
736 unreachable;
737 },
738 }
708739 }
709740};
710741
......@@ -716,8 +747,7 @@ pub const DeclGen = struct {
716747 pass: Pass,
717748 is_naked_fn: bool,
718749 expected_block: ?u32,
719 /// This is a borrowed reference from `link.C`.
720 fwd_decl: std.ArrayList(u8),
750 fwd_decl: std.io.Writer.Allocating,
721751 error_msg: ?*Zcu.ErrorMsg,
722752 ctype_pool: CType.Pool,
723753 scratch: std.ArrayListUnmanaged(u32),
......@@ -734,11 +764,7 @@ pub const DeclGen = struct {
734764 flush,
735765 };
736766
737 fn fwdDeclWriter(dg: *DeclGen) ArrayListWriter {
738 return arrayListWriter(&dg.fwd_decl);
739 }
740
741 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
767 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) Error {
742768 @branchHint(.cold);
743769 const zcu = dg.pt.zcu;
744770 const src_loc = zcu.navSrcLoc(dg.pass.nav);
......@@ -748,10 +774,10 @@ pub const DeclGen = struct {
748774
749775 fn renderUav(
750776 dg: *DeclGen,
751 writer: anytype,
777 w: *Writer,
752778 uav: InternPool.Key.Ptr.BaseAddr.Uav,
753779 location: ValueRenderLocation,
754 ) error{ OutOfMemory, AnalysisFail }!void {
780 ) Error!void {
755781 const pt = dg.pt;
756782 const zcu = pt.zcu;
757783 const ip = &zcu.intern_pool;
......@@ -762,14 +788,14 @@ pub const DeclGen = struct {
762788 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
763789 const ptr_ty: Type = .fromInterned(uav.orig_ty);
764790 if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isFnOrHasRuntimeBits(zcu)) {
765 return dg.writeCValue(writer, .{ .undef = ptr_ty });
791 return dg.writeCValue(w, .{ .undef = ptr_ty });
766792 }
767793
768794 // Chase function values in order to be able to reference the original function.
769795 switch (ip.indexToKey(uav.val)) {
770796 .variable => unreachable,
771 .func => |func| return dg.renderNav(writer, func.owner_nav, location),
772 .@"extern" => |@"extern"| return dg.renderNav(writer, @"extern".owner_nav, location),
797 .func => |func| return dg.renderNav(w, func.owner_nav, location),
798 .@"extern" => |@"extern"| return dg.renderNav(w, @"extern".owner_nav, location),
773799 else => {},
774800 }
775801
......@@ -783,13 +809,13 @@ pub const DeclGen = struct {
783809 const need_cast = !elem_ctype.eql(uav_ctype) and
784810 (elem_ctype.info(ctype_pool) != .function or uav_ctype.info(ctype_pool) != .function);
785811 if (need_cast) {
786 try writer.writeAll("((");
787 try dg.renderCType(writer, ptr_ctype);
788 try writer.writeByte(')');
812 try w.writeAll("((");
813 try dg.renderCType(w, ptr_ctype);
814 try w.writeByte(')');
789815 }
790 try writer.writeByte('&');
791 try renderUavName(writer, uav_val);
792 if (need_cast) try writer.writeByte(')');
816 try w.writeByte('&');
817 try renderUavName(w, uav_val);
818 if (need_cast) try w.writeByte(')');
793819
794820 // Indicate that the anon decl should be rendered to the output so that
795821 // our reference above is not undefined.
......@@ -810,10 +836,10 @@ pub const DeclGen = struct {
810836
811837 fn renderNav(
812838 dg: *DeclGen,
813 writer: anytype,
839 w: *Writer,
814840 nav_index: InternPool.Nav.Index,
815841 location: ValueRenderLocation,
816 ) error{ OutOfMemory, AnalysisFail }!void {
842 ) Error!void {
817843 _ = location;
818844 const pt = dg.pt;
819845 const zcu = pt.zcu;
......@@ -835,7 +861,7 @@ pub const DeclGen = struct {
835861 const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip));
836862 const ptr_ty = try pt.navPtrType(owner_nav);
837863 if (!nav_ty.isFnOrHasRuntimeBits(zcu)) {
838 return dg.writeCValue(writer, .{ .undef = ptr_ty });
864 return dg.writeCValue(w, .{ .undef = ptr_ty });
839865 }
840866
841867 // We shouldn't cast C function pointers as this is UB (when you call
......@@ -848,21 +874,21 @@ pub const DeclGen = struct {
848874 const need_cast = !elem_ctype.eql(nav_ctype) and
849875 (elem_ctype.info(ctype_pool) != .function or nav_ctype.info(ctype_pool) != .function);
850876 if (need_cast) {
851 try writer.writeAll("((");
852 try dg.renderCType(writer, ctype);
853 try writer.writeByte(')');
877 try w.writeAll("((");
878 try dg.renderCType(w, ctype);
879 try w.writeByte(')');
854880 }
855 try writer.writeByte('&');
856 try dg.renderNavName(writer, owner_nav);
857 if (need_cast) try writer.writeByte(')');
881 try w.writeByte('&');
882 try dg.renderNavName(w, owner_nav);
883 if (need_cast) try w.writeByte(')');
858884 }
859885
860886 fn renderPointer(
861887 dg: *DeclGen,
862 writer: anytype,
888 w: *Writer,
863889 derivation: Value.PointerDeriveStep,
864890 location: ValueRenderLocation,
865 ) error{ OutOfMemory, AnalysisFail }!void {
891 ) Error!void {
866892 const pt = dg.pt;
867893 const zcu = pt.zcu;
868894 switch (derivation) {
......@@ -870,18 +896,18 @@ pub const DeclGen = struct {
870896 .int => |int| {
871897 const ptr_ctype = try dg.ctypeFromType(int.ptr_ty, .complete);
872898 const addr_val = try pt.intValue(.usize, int.addr);
873 try writer.writeByte('(');
874 try dg.renderCType(writer, ptr_ctype);
875 try writer.print("){x}", .{try dg.fmtIntLiteral(addr_val, .Other)});
899 try w.writeByte('(');
900 try dg.renderCType(w, ptr_ctype);
901 try w.print("){f}", .{try dg.fmtIntLiteralHex(addr_val, .Other)});
876902 },
877903
878 .nav_ptr => |nav| try dg.renderNav(writer, nav, location),
879 .uav_ptr => |uav| try dg.renderUav(writer, uav, location),
904 .nav_ptr => |nav| try dg.renderNav(w, nav, location),
905 .uav_ptr => |uav| try dg.renderUav(w, uav, location),
880906
881907 inline .eu_payload_ptr, .opt_payload_ptr => |info| {
882 try writer.writeAll("&(");
883 try dg.renderPointer(writer, info.parent.*, location);
884 try writer.writeAll(")->payload");
908 try w.writeAll("&(");
909 try dg.renderPointer(w, info.parent.*, location);
910 try w.writeAll(")->payload");
885911 },
886912
887913 .field_ptr => |field| {
......@@ -893,26 +919,26 @@ pub const DeclGen = struct {
893919 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, pt)) {
894920 .begin => {
895921 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
896 try writer.writeByte('(');
897 try dg.renderCType(writer, ptr_ctype);
898 try writer.writeByte(')');
899 try dg.renderPointer(writer, field.parent.*, location);
922 try w.writeByte('(');
923 try dg.renderCType(w, ptr_ctype);
924 try w.writeByte(')');
925 try dg.renderPointer(w, field.parent.*, location);
900926 },
901927 .field => |name| {
902 try writer.writeAll("&(");
903 try dg.renderPointer(writer, field.parent.*, location);
904 try writer.writeAll(")->");
905 try dg.writeCValue(writer, name);
928 try w.writeAll("&(");
929 try dg.renderPointer(w, field.parent.*, location);
930 try w.writeAll(")->");
931 try dg.writeCValue(w, name);
906932 },
907933 .byte_offset => |byte_offset| {
908934 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
909 try writer.writeByte('(');
910 try dg.renderCType(writer, ptr_ctype);
911 try writer.writeByte(')');
935 try w.writeByte('(');
936 try dg.renderCType(w, ptr_ctype);
937 try w.writeByte(')');
912938 const offset_val = try pt.intValue(.usize, byte_offset);
913 try writer.writeAll("((char *)");
914 try dg.renderPointer(writer, field.parent.*, location);
915 try writer.print(" + {})", .{try dg.fmtIntLiteral(offset_val, .Other)});
939 try w.writeAll("((char *)");
940 try dg.renderPointer(w, field.parent.*, location);
941 try w.print(" + {f})", .{try dg.fmtIntLiteralDec(offset_val, .Other)});
916942 },
917943 }
918944 },
......@@ -920,10 +946,10 @@ pub const DeclGen = struct {
920946 .elem_ptr => |elem| if (!(try elem.parent.ptrType(pt)).childType(zcu).hasRuntimeBits(zcu)) {
921947 // Element type is zero-bit, so lowers to `void`. The index is irrelevant; just cast the pointer.
922948 const ptr_ctype = try dg.ctypeFromType(elem.result_ptr_ty, .complete);
923 try writer.writeByte('(');
924 try dg.renderCType(writer, ptr_ctype);
925 try writer.writeByte(')');
926 try dg.renderPointer(writer, elem.parent.*, location);
949 try w.writeByte('(');
950 try dg.renderCType(w, ptr_ctype);
951 try w.writeByte(')');
952 try dg.renderPointer(w, elem.parent.*, location);
927953 } else {
928954 const index_val = try pt.intValue(.usize, elem.elem_idx);
929955 // We want to do pointer arithmetic on a pointer to the element type.
......@@ -932,48 +958,47 @@ pub const DeclGen = struct {
932958 const parent_ctype = try dg.ctypeFromType(try elem.parent.ptrType(pt), .complete);
933959 if (result_ctype.eql(parent_ctype)) {
934960 // The pointer already has an appropriate type - just do the arithmetic.
935 try writer.writeByte('(');
936 try dg.renderPointer(writer, elem.parent.*, location);
937 try writer.print(" + {})", .{try dg.fmtIntLiteral(index_val, .Other)});
961 try w.writeByte('(');
962 try dg.renderPointer(w, elem.parent.*, location);
963 try w.print(" + {f})", .{try dg.fmtIntLiteralDec(index_val, .Other)});
938964 } else {
939965 // We probably have an array pointer `T (*)[n]`. Cast to an element pointer,
940966 // and *then* apply the index.
941 try writer.writeAll("((");
942 try dg.renderCType(writer, result_ctype);
943 try writer.writeByte(')');
944 try dg.renderPointer(writer, elem.parent.*, location);
945 try writer.print(" + {})", .{try dg.fmtIntLiteral(index_val, .Other)});
967 try w.writeAll("((");
968 try dg.renderCType(w, result_ctype);
969 try w.writeByte(')');
970 try dg.renderPointer(w, elem.parent.*, location);
971 try w.print(" + {f})", .{try dg.fmtIntLiteralDec(index_val, .Other)});
946972 }
947973 },
948974
949975 .offset_and_cast => |oac| {
950976 const ptr_ctype = try dg.ctypeFromType(oac.new_ptr_ty, .complete);
951 try writer.writeByte('(');
952 try dg.renderCType(writer, ptr_ctype);
953 try writer.writeByte(')');
977 try w.writeByte('(');
978 try dg.renderCType(w, ptr_ctype);
979 try w.writeByte(')');
954980 if (oac.byte_offset == 0) {
955 try dg.renderPointer(writer, oac.parent.*, location);
981 try dg.renderPointer(w, oac.parent.*, location);
956982 } else {
957983 const offset_val = try pt.intValue(.usize, oac.byte_offset);
958 try writer.writeAll("((char *)");
959 try dg.renderPointer(writer, oac.parent.*, location);
960 try writer.print(" + {})", .{try dg.fmtIntLiteral(offset_val, .Other)});
984 try w.writeAll("((char *)");
985 try dg.renderPointer(w, oac.parent.*, location);
986 try w.print(" + {f})", .{try dg.fmtIntLiteralDec(offset_val, .Other)});
961987 }
962988 },
963989 }
964990 }
965991
966 fn renderErrorName(dg: *DeclGen, writer: anytype, err_name: InternPool.NullTerminatedString) !void {
967 const ip = &dg.pt.zcu.intern_pool;
968 try writer.print("zig_error_{}", .{fmtIdent(err_name.toSlice(ip))});
992 fn renderErrorName(dg: *DeclGen, w: *Writer, err_name: InternPool.NullTerminatedString) !void {
993 try w.print("zig_error_{f}", .{fmtIdentUnsolo(err_name.toSlice(&dg.pt.zcu.intern_pool))});
969994 }
970995
971996 fn renderValue(
972997 dg: *DeclGen,
973 writer: anytype,
998 w: *Writer,
974999 val: Value,
9751000 location: ValueRenderLocation,
976 ) error{ OutOfMemory, AnalysisFail }!void {
1001 ) Error!void {
9771002 const pt = dg.pt;
9781003 const zcu = pt.zcu;
9791004 const ip = &zcu.intern_pool;
......@@ -986,7 +1011,7 @@ pub const DeclGen = struct {
9861011 };
9871012
9881013 const ty = val.typeOf(zcu);
989 if (val.isUndefDeep(zcu)) return dg.renderUndefValue(writer, ty, location);
1014 if (val.isUndefDeep(zcu)) return dg.renderUndefValue(w, ty, location);
9901015 const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
9911016 switch (ip.indexToKey(val.toIntern())) {
9921017 // types, not values
......@@ -1019,8 +1044,8 @@ pub const DeclGen = struct {
10191044 .empty_tuple => unreachable,
10201045 .@"unreachable" => unreachable,
10211046
1022 .false => try writer.writeAll("false"),
1023 .true => try writer.writeAll("true"),
1047 .false => try w.writeAll("false"),
1048 .true => try w.writeAll("true"),
10241049 },
10251050 .variable,
10261051 .@"extern",
......@@ -1029,45 +1054,45 @@ pub const DeclGen = struct {
10291054 .empty_enum_value,
10301055 => unreachable, // non-runtime values
10311056 .int => |int| switch (int.storage) {
1032 .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(val, location)}),
1057 .u64, .i64, .big_int => try w.print("{f}", .{try dg.fmtIntLiteralDec(val, location)}),
10331058 .lazy_align, .lazy_size => {
1034 try writer.writeAll("((");
1035 try dg.renderCType(writer, ctype);
1036 try writer.print("){x})", .{try dg.fmtIntLiteral(
1059 try w.writeAll("((");
1060 try dg.renderCType(w, ctype);
1061 try w.print("){f})", .{try dg.fmtIntLiteralHex(
10371062 try pt.intValue(.usize, val.toUnsignedInt(zcu)),
10381063 .Other,
10391064 )});
10401065 },
10411066 },
1042 .err => |err| try dg.renderErrorName(writer, err.name),
1067 .err => |err| try dg.renderErrorName(w, err.name),
10431068 .error_union => |error_union| switch (ctype.info(ctype_pool)) {
10441069 .basic => switch (error_union.val) {
1045 .err_name => |err_name| try dg.renderErrorName(writer, err_name),
1046 .payload => try writer.writeAll("0"),
1070 .err_name => |err_name| try dg.renderErrorName(w, err_name),
1071 .payload => try w.writeByte('0'),
10471072 },
10481073 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
10491074 .aggregate => |aggregate| {
10501075 if (!location.isInitializer()) {
1051 try writer.writeByte('(');
1052 try dg.renderCType(writer, ctype);
1053 try writer.writeByte(')');
1076 try w.writeByte('(');
1077 try dg.renderCType(w, ctype);
1078 try w.writeByte(')');
10541079 }
1055 try writer.writeByte('{');
1080 try w.writeByte('{');
10561081 for (0..aggregate.fields.len) |field_index| {
1057 if (field_index > 0) try writer.writeByte(',');
1082 if (field_index > 0) try w.writeByte(',');
10581083 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
10591084 .@"error" => switch (error_union.val) {
1060 .err_name => |err_name| try dg.renderErrorName(writer, err_name),
1061 .payload => try writer.writeByte('0'),
1085 .err_name => |err_name| try dg.renderErrorName(w, err_name),
1086 .payload => try w.writeByte('0'),
10621087 },
10631088 .payload => switch (error_union.val) {
10641089 .err_name => try dg.renderUndefValue(
1065 writer,
1090 w,
10661091 ty.errorUnionPayload(zcu),
10671092 initializer_type,
10681093 ),
10691094 .payload => |payload| try dg.renderValue(
1070 writer,
1095 w,
10711096 Value.fromInterned(payload),
10721097 initializer_type,
10731098 ),
......@@ -1075,10 +1100,10 @@ pub const DeclGen = struct {
10751100 else => unreachable,
10761101 }
10771102 }
1078 try writer.writeByte('}');
1103 try w.writeByte('}');
10791104 },
10801105 },
1081 .enum_tag => |enum_tag| try dg.renderValue(writer, Value.fromInterned(enum_tag.int), location),
1106 .enum_tag => |enum_tag| try dg.renderValue(w, Value.fromInterned(enum_tag.int), location),
10821107 .float => {
10831108 const bits = ty.floatBits(target);
10841109 const f128_val = val.toFloat(f128, zcu);
......@@ -1105,18 +1130,18 @@ pub const DeclGen = struct {
11051130
11061131 var empty = true;
11071132 if (std.math.isFinite(f128_val)) {
1108 try writer.writeAll("zig_make_");
1109 try dg.renderTypeForBuiltinFnName(writer, ty);
1110 try writer.writeByte('(');
1133 try w.writeAll("zig_make_");
1134 try dg.renderTypeForBuiltinFnName(w, ty);
1135 try w.writeByte('(');
11111136 switch (bits) {
1112 16 => try writer.print("{x}", .{val.toFloat(f16, zcu)}),
1113 32 => try writer.print("{x}", .{val.toFloat(f32, zcu)}),
1114 64 => try writer.print("{x}", .{val.toFloat(f64, zcu)}),
1115 80 => try writer.print("{x}", .{val.toFloat(f80, zcu)}),
1116 128 => try writer.print("{x}", .{f128_val}),
1137 16 => try w.print("{x}", .{val.toFloat(f16, zcu)}),
1138 32 => try w.print("{x}", .{val.toFloat(f32, zcu)}),
1139 64 => try w.print("{x}", .{val.toFloat(f64, zcu)}),
1140 80 => try w.print("{x}", .{val.toFloat(f80, zcu)}),
1141 128 => try w.print("{x}", .{f128_val}),
11171142 else => unreachable,
11181143 }
1119 try writer.writeAll(", ");
1144 try w.writeAll(", ");
11201145 empty = false;
11211146 } else {
11221147 // isSignalNan is equivalent to isNan currently, and MSVC doesn't have nans, so prefer nan
......@@ -1140,45 +1165,45 @@ pub const DeclGen = struct {
11401165 // return dg.fail("Only quiet nans are supported in global variable initializers", .{});
11411166 }
11421167
1143 try writer.writeAll("zig_");
1144 try writer.writeAll(if (location == .StaticInitializer) "init" else "make");
1145 try writer.writeAll("_special_");
1146 try dg.renderTypeForBuiltinFnName(writer, ty);
1147 try writer.writeByte('(');
1148 if (std.math.signbit(f128_val)) try writer.writeByte('-');
1149 try writer.writeAll(", ");
1150 try writer.writeAll(operation);
1151 try writer.writeAll(", ");
1168 try w.writeAll("zig_");
1169 try w.writeAll(if (location == .StaticInitializer) "init" else "make");
1170 try w.writeAll("_special_");
1171 try dg.renderTypeForBuiltinFnName(w, ty);
1172 try w.writeByte('(');
1173 if (std.math.signbit(f128_val)) try w.writeByte('-');
1174 try w.writeAll(", ");
1175 try w.writeAll(operation);
1176 try w.writeAll(", ");
11521177 if (std.math.isNan(f128_val)) switch (bits) {
11531178 // We only actually need to pass the significand, but it will get
11541179 // properly masked anyway, so just pass the whole value.
1155 16 => try writer.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}),
1156 32 => try writer.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}),
1157 64 => try writer.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}),
1158 80 => try writer.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}),
1159 128 => try writer.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}),
1180 16 => try w.print("\"0x{x}\"", .{@as(u16, @bitCast(val.toFloat(f16, zcu)))}),
1181 32 => try w.print("\"0x{x}\"", .{@as(u32, @bitCast(val.toFloat(f32, zcu)))}),
1182 64 => try w.print("\"0x{x}\"", .{@as(u64, @bitCast(val.toFloat(f64, zcu)))}),
1183 80 => try w.print("\"0x{x}\"", .{@as(u80, @bitCast(val.toFloat(f80, zcu)))}),
1184 128 => try w.print("\"0x{x}\"", .{@as(u128, @bitCast(f128_val))}),
11601185 else => unreachable,
11611186 };
1162 try writer.writeAll(", ");
1187 try w.writeAll(", ");
11631188 empty = false;
11641189 }
1165 try writer.print("{x}", .{try dg.fmtIntLiteral(
1190 try w.print("{f}", .{try dg.fmtIntLiteralHex(
11661191 try pt.intValue_big(repr_ty, repr_val_big.toConst()),
11671192 location,
11681193 )});
1169 if (!empty) try writer.writeByte(')');
1194 if (!empty) try w.writeByte(')');
11701195 },
11711196 .slice => |slice| {
11721197 const aggregate = ctype.info(ctype_pool).aggregate;
11731198 if (!location.isInitializer()) {
1174 try writer.writeByte('(');
1175 try dg.renderCType(writer, ctype);
1176 try writer.writeByte(')');
1199 try w.writeByte('(');
1200 try dg.renderCType(w, ctype);
1201 try w.writeByte(')');
11771202 }
1178 try writer.writeByte('{');
1203 try w.writeByte('{');
11791204 for (0..aggregate.fields.len) |field_index| {
1180 if (field_index > 0) try writer.writeByte(',');
1181 try dg.renderValue(writer, Value.fromInterned(
1205 if (field_index > 0) try w.writeByte(',');
1206 try dg.renderValue(w, Value.fromInterned(
11821207 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
11831208 .ptr => slice.ptr,
11841209 .len => slice.len,
......@@ -1186,33 +1211,33 @@ pub const DeclGen = struct {
11861211 },
11871212 ), initializer_type);
11881213 }
1189 try writer.writeByte('}');
1214 try w.writeByte('}');
11901215 },
11911216 .ptr => {
11921217 var arena = std.heap.ArenaAllocator.init(zcu.gpa);
11931218 defer arena.deinit();
11941219 const derivation = try val.pointerDerivation(arena.allocator(), pt);
1195 try dg.renderPointer(writer, derivation, location);
1220 try dg.renderPointer(w, derivation, location);
11961221 },
11971222 .opt => |opt| switch (ctype.info(ctype_pool)) {
1198 .basic => if (ctype.isBool()) try writer.writeAll(switch (opt.val) {
1223 .basic => if (ctype.isBool()) try w.writeAll(switch (opt.val) {
11991224 .none => "true",
12001225 else => "false",
12011226 }) else switch (opt.val) {
1202 .none => try writer.writeAll("0"),
1227 .none => try w.writeByte('0'),
12031228 else => |payload| switch (ip.indexToKey(payload)) {
12041229 .undef => |err_ty| try dg.renderUndefValue(
1205 writer,
1230 w,
12061231 .fromInterned(err_ty),
12071232 location,
12081233 ),
1209 .err => |err| try dg.renderErrorName(writer, err.name),
1234 .err => |err| try dg.renderErrorName(w, err.name),
12101235 else => unreachable,
12111236 },
12121237 },
12131238 .pointer => switch (opt.val) {
1214 .none => try writer.writeAll("NULL"),
1215 else => |payload| try dg.renderValue(writer, Value.fromInterned(payload), location),
1239 .none => try w.writeAll("NULL"),
1240 else => |payload| try dg.renderValue(w, Value.fromInterned(payload), location),
12161241 },
12171242 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
12181243 .aggregate => |aggregate| {
......@@ -1221,7 +1246,7 @@ pub const DeclGen = struct {
12211246 else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) {
12221247 .is_null, .payload => {},
12231248 .ptr, .len => return dg.renderValue(
1224 writer,
1249 w,
12251250 Value.fromInterned(payload),
12261251 location,
12271252 ),
......@@ -1229,48 +1254,48 @@ pub const DeclGen = struct {
12291254 },
12301255 }
12311256 if (!location.isInitializer()) {
1232 try writer.writeByte('(');
1233 try dg.renderCType(writer, ctype);
1234 try writer.writeByte(')');
1257 try w.writeByte('(');
1258 try dg.renderCType(w, ctype);
1259 try w.writeByte(')');
12351260 }
1236 try writer.writeByte('{');
1261 try w.writeByte('{');
12371262 for (0..aggregate.fields.len) |field_index| {
1238 if (field_index > 0) try writer.writeByte(',');
1263 if (field_index > 0) try w.writeByte(',');
12391264 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
1240 .is_null => try writer.writeAll(switch (opt.val) {
1265 .is_null => try w.writeAll(switch (opt.val) {
12411266 .none => "true",
12421267 else => "false",
12431268 }),
12441269 .payload => switch (opt.val) {
12451270 .none => try dg.renderUndefValue(
1246 writer,
1271 w,
12471272 ty.optionalChild(zcu),
12481273 initializer_type,
12491274 ),
12501275 else => |payload| try dg.renderValue(
1251 writer,
1276 w,
12521277 Value.fromInterned(payload),
12531278 initializer_type,
12541279 ),
12551280 },
1256 .ptr => try writer.writeAll("NULL"),
1257 .len => try dg.renderUndefValue(writer, .usize, initializer_type),
1281 .ptr => try w.writeAll("NULL"),
1282 .len => try dg.renderUndefValue(w, .usize, initializer_type),
12581283 else => unreachable,
12591284 }
12601285 }
1261 try writer.writeByte('}');
1286 try w.writeByte('}');
12621287 },
12631288 },
12641289 .aggregate => switch (ip.indexToKey(ty.toIntern())) {
12651290 .array_type, .vector_type => {
12661291 if (location == .FunctionArgument) {
1267 try writer.writeByte('(');
1268 try dg.renderCType(writer, ctype);
1269 try writer.writeByte(')');
1292 try w.writeByte('(');
1293 try dg.renderCType(w, ctype);
1294 try w.writeByte(')');
12701295 }
12711296 const ai = ty.arrayInfo(zcu);
12721297 if (ai.elem_type.eql(.u8, zcu)) {
1273 var literal = stringLiteral(writer, ty.arrayLenIncludingSentinel(zcu));
1298 var literal: StringLiteral = .init(w, @intCast(ty.arrayLenIncludingSentinel(zcu)));
12741299 try literal.start();
12751300 var index: usize = 0;
12761301 while (index < ai.len) : (index += 1) {
......@@ -1287,28 +1312,28 @@ pub const DeclGen = struct {
12871312 }
12881313 try literal.end();
12891314 } else {
1290 try writer.writeByte('{');
1315 try w.writeByte('{');
12911316 var index: usize = 0;
12921317 while (index < ai.len) : (index += 1) {
1293 if (index != 0) try writer.writeByte(',');
1318 if (index != 0) try w.writeByte(',');
12941319 const elem_val = try val.elemValue(pt, index);
1295 try dg.renderValue(writer, elem_val, initializer_type);
1320 try dg.renderValue(w, elem_val, initializer_type);
12961321 }
12971322 if (ai.sentinel) |s| {
1298 if (index != 0) try writer.writeByte(',');
1299 try dg.renderValue(writer, s, initializer_type);
1323 if (index != 0) try w.writeByte(',');
1324 try dg.renderValue(w, s, initializer_type);
13001325 }
1301 try writer.writeByte('}');
1326 try w.writeByte('}');
13021327 }
13031328 },
13041329 .tuple_type => |tuple| {
13051330 if (!location.isInitializer()) {
1306 try writer.writeByte('(');
1307 try dg.renderCType(writer, ctype);
1308 try writer.writeByte(')');
1331 try w.writeByte('(');
1332 try dg.renderCType(w, ctype);
1333 try w.writeByte(')');
13091334 }
13101335
1311 try writer.writeByte('{');
1336 try w.writeByte('{');
13121337 var empty = true;
13131338 for (0..tuple.types.len) |field_index| {
13141339 const comptime_val = tuple.values.get(ip)[field_index];
......@@ -1316,7 +1341,7 @@ pub const DeclGen = struct {
13161341 const field_ty: Type = .fromInterned(tuple.types.get(ip)[field_index]);
13171342 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
13181343
1319 if (!empty) try writer.writeByte(',');
1344 if (!empty) try w.writeByte(',');
13201345
13211346 const field_val = Value.fromInterned(
13221347 switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
......@@ -1328,30 +1353,30 @@ pub const DeclGen = struct {
13281353 .repeated_elem => |elem| elem,
13291354 },
13301355 );
1331 try dg.renderValue(writer, field_val, initializer_type);
1356 try dg.renderValue(w, field_val, initializer_type);
13321357
13331358 empty = false;
13341359 }
1335 try writer.writeByte('}');
1360 try w.writeByte('}');
13361361 },
13371362 .struct_type => {
13381363 const loaded_struct = ip.loadStructType(ty.toIntern());
13391364 switch (loaded_struct.layout) {
13401365 .auto, .@"extern" => {
13411366 if (!location.isInitializer()) {
1342 try writer.writeByte('(');
1343 try dg.renderCType(writer, ctype);
1344 try writer.writeByte(')');
1367 try w.writeByte('(');
1368 try dg.renderCType(w, ctype);
1369 try w.writeByte(')');
13451370 }
13461371
1347 try writer.writeByte('{');
1372 try w.writeByte('{');
13481373 var field_it = loaded_struct.iterateRuntimeOrder(ip);
13491374 var need_comma = false;
13501375 while (field_it.next()) |field_index| {
13511376 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
13521377 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
13531378
1354 if (need_comma) try writer.writeByte(',');
1379 if (need_comma) try w.writeByte(',');
13551380 need_comma = true;
13561381 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
13571382 .bytes => |bytes| try pt.intern(.{ .int = .{
......@@ -1361,9 +1386,9 @@ pub const DeclGen = struct {
13611386 .elems => |elems| elems[field_index],
13621387 .repeated_elem => |elem| elem,
13631388 };
1364 try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type);
1389 try dg.renderValue(w, Value.fromInterned(field_val), initializer_type);
13651390 }
1366 try writer.writeByte('}');
1391 try w.writeByte('}');
13671392 },
13681393 .@"packed" => {
13691394 const int_info = ty.intInfo(zcu);
......@@ -1381,16 +1406,16 @@ pub const DeclGen = struct {
13811406 }
13821407
13831408 if (eff_num_fields == 0) {
1384 try writer.writeByte('(');
1385 try dg.renderUndefValue(writer, ty, location);
1386 try writer.writeByte(')');
1409 try w.writeByte('(');
1410 try dg.renderUndefValue(w, ty, location);
1411 try w.writeByte(')');
13871412 } else if (ty.bitSize(zcu) > 64) {
13881413 // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off))
13891414 var num_or = eff_num_fields - 1;
13901415 while (num_or > 0) : (num_or -= 1) {
1391 try writer.writeAll("zig_or_");
1392 try dg.renderTypeForBuiltinFnName(writer, ty);
1393 try writer.writeByte('(');
1416 try w.writeAll("zig_or_");
1417 try dg.renderTypeForBuiltinFnName(w, ty);
1418 try w.writeByte('(');
13941419 }
13951420
13961421 var eff_index: usize = 0;
......@@ -1409,36 +1434,36 @@ pub const DeclGen = struct {
14091434 };
14101435 const cast_context = IntCastContext{ .value = .{ .value = Value.fromInterned(field_val) } };
14111436 if (bit_offset != 0) {
1412 try writer.writeAll("zig_shl_");
1413 try dg.renderTypeForBuiltinFnName(writer, ty);
1414 try writer.writeByte('(');
1415 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1416 try writer.writeAll(", ");
1417 try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
1418 try writer.writeByte(')');
1437 try w.writeAll("zig_shl_");
1438 try dg.renderTypeForBuiltinFnName(w, ty);
1439 try w.writeByte('(');
1440 try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument);
1441 try w.writeAll(", ");
1442 try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
1443 try w.writeByte(')');
14191444 } else {
1420 try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument);
1445 try dg.renderIntCast(w, ty, cast_context, field_ty, .FunctionArgument);
14211446 }
14221447
1423 if (needs_closing_paren) try writer.writeByte(')');
1424 if (eff_index != eff_num_fields - 1) try writer.writeAll(", ");
1448 if (needs_closing_paren) try w.writeByte(')');
1449 if (eff_index != eff_num_fields - 1) try w.writeAll(", ");
14251450
14261451 bit_offset += field_ty.bitSize(zcu);
14271452 needs_closing_paren = true;
14281453 eff_index += 1;
14291454 }
14301455 } else {
1431 try writer.writeByte('(');
1456 try w.writeByte('(');
14321457 // a << a_off | b << b_off | c << c_off
14331458 var empty = true;
14341459 for (0..loaded_struct.field_types.len) |field_index| {
14351460 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
14361461 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
14371462
1438 if (!empty) try writer.writeAll(" | ");
1439 try writer.writeByte('(');
1440 try dg.renderCType(writer, ctype);
1441 try writer.writeByte(')');
1463 if (!empty) try w.writeAll(" | ");
1464 try w.writeByte('(');
1465 try dg.renderCType(w, ctype);
1466 try w.writeByte(')');
14421467
14431468 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
14441469 .bytes => |bytes| try pt.intern(.{ .int = .{
......@@ -1455,24 +1480,24 @@ pub const DeclGen = struct {
14551480 .{ .signedness = .unsigned, .bits = undefined };
14561481 switch (field_int_info.signedness) {
14571482 .signed => {
1458 try writer.writeByte('(');
1459 try dg.renderValue(writer, Value.fromInterned(field_val), .Other);
1460 try writer.writeAll(" & ");
1483 try w.writeByte('(');
1484 try dg.renderValue(w, Value.fromInterned(field_val), .Other);
1485 try w.writeAll(" & ");
14611486 const field_uint_ty = try pt.intType(.unsigned, field_int_info.bits);
1462 try dg.renderValue(writer, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other);
1463 try writer.writeByte(')');
1487 try dg.renderValue(w, try field_uint_ty.maxIntScalar(pt, field_uint_ty), .Other);
1488 try w.writeByte(')');
14641489 },
1465 .unsigned => try dg.renderValue(writer, Value.fromInterned(field_val), .Other),
1490 .unsigned => try dg.renderValue(w, Value.fromInterned(field_val), .Other),
14661491 }
14671492 if (bit_offset != 0) {
1468 try writer.writeAll(" << ");
1469 try dg.renderValue(writer, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
1493 try w.writeAll(" << ");
1494 try dg.renderValue(w, try pt.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
14701495 }
14711496
14721497 bit_offset += field_ty.bitSize(zcu);
14731498 empty = false;
14741499 }
1475 try writer.writeByte(')');
1500 try w.writeByte(')');
14761501 }
14771502 },
14781503 }
......@@ -1486,11 +1511,11 @@ pub const DeclGen = struct {
14861511 switch (loaded_union.flagsUnordered(ip).layout) {
14871512 .@"packed" => {
14881513 if (!location.isInitializer()) {
1489 try writer.writeByte('(');
1490 try dg.renderType(writer, backing_ty);
1491 try writer.writeByte(')');
1514 try w.writeByte('(');
1515 try dg.renderType(w, backing_ty);
1516 try w.writeByte(')');
14921517 }
1493 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1518 try dg.renderValue(w, Value.fromInterned(un.val), location);
14941519 },
14951520 .@"extern" => {
14961521 if (location == .StaticInitializer) {
......@@ -1498,21 +1523,21 @@ pub const DeclGen = struct {
14981523 }
14991524
15001525 const ptr_ty = try pt.singleConstPtrType(ty);
1501 try writer.writeAll("*((");
1502 try dg.renderType(writer, ptr_ty);
1503 try writer.writeAll(")(");
1504 try dg.renderType(writer, backing_ty);
1505 try writer.writeAll("){");
1506 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1507 try writer.writeAll("})");
1526 try w.writeAll("*((");
1527 try dg.renderType(w, ptr_ty);
1528 try w.writeAll(")(");
1529 try dg.renderType(w, backing_ty);
1530 try w.writeAll("){");
1531 try dg.renderValue(w, Value.fromInterned(un.val), location);
1532 try w.writeAll("})");
15081533 },
15091534 else => unreachable,
15101535 }
15111536 } else {
15121537 if (!location.isInitializer()) {
1513 try writer.writeByte('(');
1514 try dg.renderCType(writer, ctype);
1515 try writer.writeByte(')');
1538 try w.writeByte('(');
1539 try dg.renderCType(w, ctype);
1540 try w.writeByte(')');
15161541 }
15171542
15181543 const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;
......@@ -1521,57 +1546,57 @@ pub const DeclGen = struct {
15211546 if (loaded_union.flagsUnordered(ip).layout == .@"packed") {
15221547 if (field_ty.hasRuntimeBits(zcu)) {
15231548 if (field_ty.isPtrAtRuntime(zcu)) {
1524 try writer.writeByte('(');
1525 try dg.renderCType(writer, ctype);
1526 try writer.writeByte(')');
1549 try w.writeByte('(');
1550 try dg.renderCType(w, ctype);
1551 try w.writeByte(')');
15271552 } else if (field_ty.zigTypeTag(zcu) == .float) {
1528 try writer.writeByte('(');
1529 try dg.renderCType(writer, ctype);
1530 try writer.writeByte(')');
1553 try w.writeByte('(');
1554 try dg.renderCType(w, ctype);
1555 try w.writeByte(')');
15311556 }
1532 try dg.renderValue(writer, Value.fromInterned(un.val), location);
1533 } else try writer.writeAll("0");
1557 try dg.renderValue(w, Value.fromInterned(un.val), location);
1558 } else try w.writeByte('0');
15341559 return;
15351560 }
15361561
15371562 const has_tag = loaded_union.hasTag(ip);
1538 if (has_tag) try writer.writeByte('{');
1563 if (has_tag) try w.writeByte('{');
15391564 const aggregate = ctype.info(ctype_pool).aggregate;
15401565 for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {
1541 if (outer_field_index > 0) try writer.writeByte(',');
1566 if (outer_field_index > 0) try w.writeByte(',');
15421567 switch (if (has_tag)
15431568 aggregate.fields.at(outer_field_index, ctype_pool).name.index
15441569 else
15451570 .payload) {
15461571 .tag => try dg.renderValue(
1547 writer,
1572 w,
15481573 Value.fromInterned(un.tag),
15491574 initializer_type,
15501575 ),
15511576 .payload => {
1552 try writer.writeByte('{');
1577 try w.writeByte('{');
15531578 if (field_ty.hasRuntimeBits(zcu)) {
1554 try writer.print(" .{ } = ", .{fmtIdent(field_name.toSlice(ip))});
1579 try w.print(" .{f} = ", .{fmtIdentSolo(field_name.toSlice(ip))});
15551580 try dg.renderValue(
1556 writer,
1581 w,
15571582 Value.fromInterned(un.val),
15581583 initializer_type,
15591584 );
1560 try writer.writeByte(' ');
1585 try w.writeByte(' ');
15611586 } else for (0..loaded_union.field_types.len) |inner_field_index| {
15621587 const inner_field_ty: Type = .fromInterned(
15631588 loaded_union.field_types.get(ip)[inner_field_index],
15641589 );
15651590 if (!inner_field_ty.hasRuntimeBits(zcu)) continue;
1566 try dg.renderUndefValue(writer, inner_field_ty, initializer_type);
1591 try dg.renderUndefValue(w, inner_field_ty, initializer_type);
15671592 break;
15681593 }
1569 try writer.writeByte('}');
1594 try w.writeByte('}');
15701595 },
15711596 else => unreachable,
15721597 }
15731598 }
1574 if (has_tag) try writer.writeByte('}');
1599 if (has_tag) try w.writeByte('}');
15751600 }
15761601 },
15771602 }
......@@ -1579,10 +1604,10 @@ pub const DeclGen = struct {
15791604
15801605 fn renderUndefValue(
15811606 dg: *DeclGen,
1582 writer: anytype,
1607 w: *Writer,
15831608 ty: Type,
15841609 location: ValueRenderLocation,
1585 ) error{ OutOfMemory, AnalysisFail }!void {
1610 ) Error!void {
15861611 const pt = dg.pt;
15871612 const zcu = pt.zcu;
15881613 const ip = &zcu.intern_pool;
......@@ -1612,57 +1637,57 @@ pub const DeclGen = struct {
16121637 // All unsigned ints matching float types are pre-allocated.
16131638 const repr_ty = dg.pt.intType(.unsigned, bits) catch unreachable;
16141639
1615 try writer.writeAll("zig_make_");
1616 try dg.renderTypeForBuiltinFnName(writer, ty);
1617 try writer.writeByte('(');
1640 try w.writeAll("zig_make_");
1641 try dg.renderTypeForBuiltinFnName(w, ty);
1642 try w.writeByte('(');
16181643 switch (bits) {
1619 16 => try writer.print("{x}", .{@as(f16, @bitCast(undefPattern(i16)))}),
1620 32 => try writer.print("{x}", .{@as(f32, @bitCast(undefPattern(i32)))}),
1621 64 => try writer.print("{x}", .{@as(f64, @bitCast(undefPattern(i64)))}),
1622 80 => try writer.print("{x}", .{@as(f80, @bitCast(undefPattern(i80)))}),
1623 128 => try writer.print("{x}", .{@as(f128, @bitCast(undefPattern(i128)))}),
1644 16 => try w.print("{x}", .{@as(f16, @bitCast(undefPattern(i16)))}),
1645 32 => try w.print("{x}", .{@as(f32, @bitCast(undefPattern(i32)))}),
1646 64 => try w.print("{x}", .{@as(f64, @bitCast(undefPattern(i64)))}),
1647 80 => try w.print("{x}", .{@as(f80, @bitCast(undefPattern(i80)))}),
1648 128 => try w.print("{x}", .{@as(f128, @bitCast(undefPattern(i128)))}),
16241649 else => unreachable,
16251650 }
1626 try writer.writeAll(", ");
1627 try dg.renderUndefValue(writer, repr_ty, .FunctionArgument);
1628 return writer.writeByte(')');
1651 try w.writeAll(", ");
1652 try dg.renderUndefValue(w, repr_ty, .FunctionArgument);
1653 return w.writeByte(')');
16291654 },
1630 .bool_type => try writer.writeAll(if (safety_on) "0xaa" else "false"),
1655 .bool_type => try w.writeAll(if (safety_on) "0xaa" else "false"),
16311656 else => switch (ip.indexToKey(ty.toIntern())) {
16321657 .simple_type,
16331658 .int_type,
16341659 .enum_type,
16351660 .error_set_type,
16361661 .inferred_error_set_type,
1637 => return writer.print("{x}", .{
1638 try dg.fmtIntLiteral(try pt.undefValue(ty), location),
1662 => return w.print("{f}", .{
1663 try dg.fmtIntLiteralHex(try pt.undefValue(ty), location),
16391664 }),
16401665 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
16411666 .one, .many, .c => {
1642 try writer.writeAll("((");
1643 try dg.renderCType(writer, ctype);
1644 return writer.print("){x})", .{
1645 try dg.fmtIntLiteral(.undef_usize, .Other),
1667 try w.writeAll("((");
1668 try dg.renderCType(w, ctype);
1669 return w.print("){f})", .{
1670 try dg.fmtIntLiteralHex(.undef_usize, .Other),
16461671 });
16471672 },
16481673 .slice => {
16491674 if (!location.isInitializer()) {
1650 try writer.writeByte('(');
1651 try dg.renderCType(writer, ctype);
1652 try writer.writeByte(')');
1675 try w.writeByte('(');
1676 try dg.renderCType(w, ctype);
1677 try w.writeByte(')');
16531678 }
16541679
1655 try writer.writeAll("{(");
1680 try w.writeAll("{(");
16561681 const ptr_ty = ty.slicePtrFieldType(zcu);
1657 try dg.renderType(writer, ptr_ty);
1658 return writer.print("){x}, {0x}}}", .{
1659 try dg.fmtIntLiteral(.undef_usize, .Other),
1682 try dg.renderType(w, ptr_ty);
1683 return w.print("){f}, {0f}}}", .{
1684 try dg.fmtIntLiteralHex(.undef_usize, .Other),
16601685 });
16611686 },
16621687 },
16631688 .opt_type => |child_type| switch (ctype.info(ctype_pool)) {
16641689 .basic, .pointer => try dg.renderUndefValue(
1665 writer,
1690 w,
16661691 .fromInterned(if (ctype.isBool()) .bool_type else child_type),
16671692 location,
16681693 ),
......@@ -1671,21 +1696,21 @@ pub const DeclGen = struct {
16711696 switch (aggregate.fields.at(0, ctype_pool).name.index) {
16721697 .is_null, .payload => {},
16731698 .ptr, .len => return dg.renderUndefValue(
1674 writer,
1699 w,
16751700 .fromInterned(child_type),
16761701 location,
16771702 ),
16781703 else => unreachable,
16791704 }
16801705 if (!location.isInitializer()) {
1681 try writer.writeByte('(');
1682 try dg.renderCType(writer, ctype);
1683 try writer.writeByte(')');
1706 try w.writeByte('(');
1707 try dg.renderCType(w, ctype);
1708 try w.writeByte(')');
16841709 }
1685 try writer.writeByte('{');
1710 try w.writeByte('{');
16861711 for (0..aggregate.fields.len) |field_index| {
1687 if (field_index > 0) try writer.writeByte(',');
1688 try dg.renderUndefValue(writer, .fromInterned(
1712 if (field_index > 0) try w.writeByte(',');
1713 try dg.renderUndefValue(w, .fromInterned(
16891714 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
16901715 .is_null => .bool_type,
16911716 .payload => child_type,
......@@ -1693,7 +1718,7 @@ pub const DeclGen = struct {
16931718 },
16941719 ), initializer_type);
16951720 }
1696 try writer.writeByte('}');
1721 try w.writeByte('}');
16971722 },
16981723 },
16991724 .struct_type => {
......@@ -1701,117 +1726,117 @@ pub const DeclGen = struct {
17011726 switch (loaded_struct.layout) {
17021727 .auto, .@"extern" => {
17031728 if (!location.isInitializer()) {
1704 try writer.writeByte('(');
1705 try dg.renderCType(writer, ctype);
1706 try writer.writeByte(')');
1729 try w.writeByte('(');
1730 try dg.renderCType(w, ctype);
1731 try w.writeByte(')');
17071732 }
17081733
1709 try writer.writeByte('{');
1734 try w.writeByte('{');
17101735 var field_it = loaded_struct.iterateRuntimeOrder(ip);
17111736 var need_comma = false;
17121737 while (field_it.next()) |field_index| {
17131738 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
17141739 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
17151740
1716 if (need_comma) try writer.writeByte(',');
1741 if (need_comma) try w.writeByte(',');
17171742 need_comma = true;
1718 try dg.renderUndefValue(writer, field_ty, initializer_type);
1743 try dg.renderUndefValue(w, field_ty, initializer_type);
17191744 }
1720 return writer.writeByte('}');
1745 return w.writeByte('}');
17211746 },
1722 .@"packed" => return writer.print("{x}", .{
1723 try dg.fmtIntLiteral(try pt.undefValue(ty), .Other),
1747 .@"packed" => return w.print("{f}", .{
1748 try dg.fmtIntLiteralHex(try pt.undefValue(ty), .Other),
17241749 }),
17251750 }
17261751 },
17271752 .tuple_type => |tuple_info| {
17281753 if (!location.isInitializer()) {
1729 try writer.writeByte('(');
1730 try dg.renderCType(writer, ctype);
1731 try writer.writeByte(')');
1754 try w.writeByte('(');
1755 try dg.renderCType(w, ctype);
1756 try w.writeByte(')');
17321757 }
17331758
1734 try writer.writeByte('{');
1759 try w.writeByte('{');
17351760 var need_comma = false;
17361761 for (0..tuple_info.types.len) |field_index| {
17371762 if (tuple_info.values.get(ip)[field_index] != .none) continue;
17381763 const field_ty: Type = .fromInterned(tuple_info.types.get(ip)[field_index]);
17391764 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
17401765
1741 if (need_comma) try writer.writeByte(',');
1766 if (need_comma) try w.writeByte(',');
17421767 need_comma = true;
1743 try dg.renderUndefValue(writer, field_ty, initializer_type);
1768 try dg.renderUndefValue(w, field_ty, initializer_type);
17441769 }
1745 return writer.writeByte('}');
1770 return w.writeByte('}');
17461771 },
17471772 .union_type => {
17481773 const loaded_union = ip.loadUnionType(ty.toIntern());
17491774 switch (loaded_union.flagsUnordered(ip).layout) {
17501775 .auto, .@"extern" => {
17511776 if (!location.isInitializer()) {
1752 try writer.writeByte('(');
1753 try dg.renderCType(writer, ctype);
1754 try writer.writeByte(')');
1777 try w.writeByte('(');
1778 try dg.renderCType(w, ctype);
1779 try w.writeByte(')');
17551780 }
17561781
17571782 const has_tag = loaded_union.hasTag(ip);
1758 if (has_tag) try writer.writeByte('{');
1783 if (has_tag) try w.writeByte('{');
17591784 const aggregate = ctype.info(ctype_pool).aggregate;
17601785 for (0..if (has_tag) aggregate.fields.len else 1) |outer_field_index| {
1761 if (outer_field_index > 0) try writer.writeByte(',');
1786 if (outer_field_index > 0) try w.writeByte(',');
17621787 switch (if (has_tag)
17631788 aggregate.fields.at(outer_field_index, ctype_pool).name.index
17641789 else
17651790 .payload) {
17661791 .tag => try dg.renderUndefValue(
1767 writer,
1792 w,
17681793 .fromInterned(loaded_union.enum_tag_ty),
17691794 initializer_type,
17701795 ),
17711796 .payload => {
1772 try writer.writeByte('{');
1797 try w.writeByte('{');
17731798 for (0..loaded_union.field_types.len) |inner_field_index| {
17741799 const inner_field_ty: Type = .fromInterned(
17751800 loaded_union.field_types.get(ip)[inner_field_index],
17761801 );
17771802 if (!inner_field_ty.hasRuntimeBits(pt.zcu)) continue;
17781803 try dg.renderUndefValue(
1779 writer,
1804 w,
17801805 inner_field_ty,
17811806 initializer_type,
17821807 );
17831808 break;
17841809 }
1785 try writer.writeByte('}');
1810 try w.writeByte('}');
17861811 },
17871812 else => unreachable,
17881813 }
17891814 }
1790 if (has_tag) try writer.writeByte('}');
1815 if (has_tag) try w.writeByte('}');
17911816 },
1792 .@"packed" => return writer.print("{x}", .{
1793 try dg.fmtIntLiteral(try pt.undefValue(ty), .Other),
1817 .@"packed" => return w.print("{f}", .{
1818 try dg.fmtIntLiteralHex(try pt.undefValue(ty), .Other),
17941819 }),
17951820 }
17961821 },
17971822 .error_union_type => |error_union_type| switch (ctype.info(ctype_pool)) {
17981823 .basic => try dg.renderUndefValue(
1799 writer,
1824 w,
18001825 .fromInterned(error_union_type.error_set_type),
18011826 location,
18021827 ),
18031828 .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
18041829 .aggregate => |aggregate| {
18051830 if (!location.isInitializer()) {
1806 try writer.writeByte('(');
1807 try dg.renderCType(writer, ctype);
1808 try writer.writeByte(')');
1831 try w.writeByte('(');
1832 try dg.renderCType(w, ctype);
1833 try w.writeByte(')');
18091834 }
1810 try writer.writeByte('{');
1835 try w.writeByte('{');
18111836 for (0..aggregate.fields.len) |field_index| {
1812 if (field_index > 0) try writer.writeByte(',');
1837 if (field_index > 0) try w.writeByte(',');
18131838 try dg.renderUndefValue(
1814 writer,
1839 w,
18151840 .fromInterned(
18161841 switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
18171842 .@"error" => error_union_type.error_set_type,
......@@ -1822,14 +1847,14 @@ pub const DeclGen = struct {
18221847 initializer_type,
18231848 );
18241849 }
1825 try writer.writeByte('}');
1850 try w.writeByte('}');
18261851 },
18271852 },
18281853 .array_type, .vector_type => {
18291854 const ai = ty.arrayInfo(zcu);
18301855 if (ai.elem_type.eql(.u8, zcu)) {
18311856 const c_len = ty.arrayLenIncludingSentinel(zcu);
1832 var literal = stringLiteral(writer, c_len);
1857 var literal: StringLiteral = .init(w, @intCast(c_len));
18331858 try literal.start();
18341859 var index: u64 = 0;
18351860 while (index < c_len) : (index += 1)
......@@ -1837,19 +1862,19 @@ pub const DeclGen = struct {
18371862 return literal.end();
18381863 } else {
18391864 if (!location.isInitializer()) {
1840 try writer.writeByte('(');
1841 try dg.renderCType(writer, ctype);
1842 try writer.writeByte(')');
1865 try w.writeByte('(');
1866 try dg.renderCType(w, ctype);
1867 try w.writeByte(')');
18431868 }
18441869
1845 try writer.writeByte('{');
1870 try w.writeByte('{');
18461871 const c_len = ty.arrayLenIncludingSentinel(zcu);
18471872 var index: u64 = 0;
18481873 while (index < c_len) : (index += 1) {
1849 if (index > 0) try writer.writeAll(", ");
1850 try dg.renderUndefValue(writer, ty.childType(zcu), initializer_type);
1874 if (index > 0) try w.writeAll(", ");
1875 try dg.renderUndefValue(w, ty.childType(zcu), initializer_type);
18511876 }
1852 return writer.writeByte('}');
1877 return w.writeByte('}');
18531878 }
18541879 },
18551880 .anyframe_type,
......@@ -1882,13 +1907,13 @@ pub const DeclGen = struct {
18821907
18831908 fn renderFunctionSignature(
18841909 dg: *DeclGen,
1885 w: anytype,
1910 w: *Writer,
18861911 fn_val: Value,
18871912 fn_align: InternPool.Alignment,
18881913 kind: CType.Kind,
18891914 name: union(enum) {
18901915 nav: InternPool.Nav.Index,
1891 fmt_ctype_pool_string: std.fmt.Formatter(formatCTypePoolString),
1916 fmt_ctype_pool_string: std.fmt.Formatter(CTypePoolStringFormatData, formatCTypePoolString),
18921917 @"export": struct {
18931918 main_name: InternPool.NullTerminatedString,
18941919 extern_name: InternPool.NullTerminatedString,
......@@ -1925,15 +1950,15 @@ pub const DeclGen = struct {
19251950 var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{});
19261951
19271952 if (toCallingConvention(fn_info.cc, zcu)) |call_conv| {
1928 try w.print("{}zig_callconv({s})", .{ trailing, call_conv });
1953 try w.print("{f}zig_callconv({s})", .{ trailing, call_conv });
19291954 trailing = .maybe_space;
19301955 }
19311956
1932 try w.print("{}", .{trailing});
1957 try w.print("{f}", .{trailing});
19331958 switch (name) {
19341959 .nav => |nav| try dg.renderNavName(w, nav),
1935 .fmt_ctype_pool_string => |fmt| try w.print("{ }", .{fmt}),
1936 .@"export" => |@"export"| try w.print("{ }", .{fmtIdent(@"export".extern_name.toSlice(ip))}),
1960 .fmt_ctype_pool_string => |fmt| try w.print("{f}", .{fmt}),
1961 .@"export" => |@"export"| try w.print("{f}", .{fmtIdentSolo(@"export".extern_name.toSlice(ip))}),
19371962 }
19381963
19391964 try renderTypeSuffix(
......@@ -1960,17 +1985,17 @@ pub const DeclGen = struct {
19601985 const is_mangled = isMangledIdent(extern_name, true);
19611986 const is_export = @"export".extern_name != @"export".main_name;
19621987 if (is_mangled and is_export) {
1963 try w.print(" zig_mangled_export({ }, {s}, {s})", .{
1964 fmtIdent(extern_name),
1988 try w.print(" zig_mangled_export({f}, {f}, {f})", .{
1989 fmtIdentSolo(extern_name),
19651990 fmtStringLiteral(extern_name, null),
19661991 fmtStringLiteral(@"export".main_name.toSlice(ip), null),
19671992 });
19681993 } else if (is_mangled) {
1969 try w.print(" zig_mangled({ }, {s})", .{
1970 fmtIdent(extern_name), fmtStringLiteral(extern_name, null),
1994 try w.print(" zig_mangled({f}, {f})", .{
1995 fmtIdentSolo(extern_name), fmtStringLiteral(extern_name, null),
19711996 });
19721997 } else if (is_export) {
1973 try w.print(" zig_export({s}, {s})", .{
1998 try w.print(" zig_export({f}, {f})", .{
19741999 fmtStringLiteral(@"export".main_name.toSlice(ip), null),
19752000 fmtStringLiteral(extern_name, null),
19762001 });
......@@ -2003,11 +2028,11 @@ pub const DeclGen = struct {
20032028 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
20042029 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
20052030 ///
2006 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{OutOfMemory}!void {
2031 fn renderType(dg: *DeclGen, w: *Writer, t: Type) Error!void {
20072032 try dg.renderCType(w, try dg.ctypeFromType(t, .complete));
20082033 }
20092034
2010 fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{OutOfMemory}!void {
2035 fn renderCType(dg: *DeclGen, w: *Writer, ctype: CType) Error!void {
20112036 _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.pt.zcu, w, ctype, .suffix, .{});
20122037 try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.pt.zcu, w, ctype, .suffix, .{});
20132038 }
......@@ -2022,7 +2047,7 @@ pub const DeclGen = struct {
20222047 value: Value,
20232048 },
20242049
2025 pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: anytype, location: ValueRenderLocation) !void {
2050 pub fn writeValue(self: *const IntCastContext, dg: *DeclGen, w: *Writer, location: ValueRenderLocation) !void {
20262051 switch (self.*) {
20272052 .c_value => |v| {
20282053 try v.f.writeCValue(w, v.value, location);
......@@ -2068,7 +2093,7 @@ pub const DeclGen = struct {
20682093 /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))
20692094 fn renderIntCast(
20702095 dg: *DeclGen,
2071 w: anytype,
2096 w: *Writer,
20722097 dest_ty: Type,
20732098 context: IntCastContext,
20742099 src_ty: Type,
......@@ -2118,7 +2143,7 @@ pub const DeclGen = struct {
21182143 } else if (dest_bits > 64 and src_bits <= 64) {
21192144 try w.writeAll("zig_make_");
21202145 try dg.renderTypeForBuiltinFnName(w, dest_ty);
2121 try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
2146 try w.writeAll("(0, ");
21222147 if (src_is_ptr) {
21232148 try w.writeByte('(');
21242149 try dg.renderType(w, src_eff_ty);
......@@ -2152,13 +2177,13 @@ pub const DeclGen = struct {
21522177 ///
21532178 fn renderTypeAndName(
21542179 dg: *DeclGen,
2155 w: anytype,
2180 w: *Writer,
21562181 ty: Type,
21572182 name: CValue,
21582183 qualifiers: CQualifiers,
21592184 alignment: Alignment,
21602185 kind: CType.Kind,
2161 ) error{ OutOfMemory, AnalysisFail }!void {
2186 ) !void {
21622187 try dg.renderCTypeAndName(
21632188 w,
21642189 try dg.ctypeFromType(ty, kind),
......@@ -2173,12 +2198,12 @@ pub const DeclGen = struct {
21732198
21742199 fn renderCTypeAndName(
21752200 dg: *DeclGen,
2176 w: anytype,
2201 w: *Writer,
21772202 ctype: CType,
21782203 name: CValue,
21792204 qualifiers: CQualifiers,
21802205 alignas: CType.AlignAs,
2181 ) error{ OutOfMemory, AnalysisFail }!void {
2206 ) !void {
21822207 const zcu = dg.pt.zcu;
21832208 switch (alignas.abiOrder()) {
21842209 .lt => try w.print("zig_under_align({}) ", .{alignas.toByteUnits()}),
......@@ -2186,24 +2211,24 @@ pub const DeclGen = struct {
21862211 .gt => try w.print("zig_align({}) ", .{alignas.toByteUnits()}),
21872212 }
21882213
2189 try w.print("{}", .{
2214 try w.print("{f}", .{
21902215 try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, ctype, .suffix, qualifiers),
21912216 });
21922217 try dg.writeName(w, name);
21932218 try renderTypeSuffix(dg.pass, &dg.ctype_pool, zcu, w, ctype, .suffix, .{});
21942219 }
21952220
2196 fn writeName(dg: *DeclGen, w: anytype, c_value: CValue) !void {
2221 fn writeName(dg: *DeclGen, w: *Writer, c_value: CValue) !void {
21972222 switch (c_value) {
21982223 .new_local, .local => |i| try w.print("t{d}", .{i}),
21992224 .constant => |uav| try renderUavName(w, uav),
22002225 .nav => |nav| try dg.renderNavName(w, nav),
2201 .identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}),
2226 .identifier => |ident| try w.print("{f}", .{fmtIdentSolo(ident)}),
22022227 else => unreachable,
22032228 }
22042229 }
22052230
2206 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {
2231 fn writeCValue(dg: *DeclGen, w: *Writer, c_value: CValue) Error!void {
22072232 switch (c_value) {
22082233 .none, .new_local, .local, .local_ref => unreachable,
22092234 .constant => |uav| try renderUavName(w, uav),
......@@ -2215,18 +2240,18 @@ pub const DeclGen = struct {
22152240 try dg.renderNavName(w, nav);
22162241 },
22172242 .undef => |ty| try dg.renderUndefValue(w, ty, .Other),
2218 .identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}),
2219 .payload_identifier => |ident| try w.print("{ }.{ }", .{
2220 fmtIdent("payload"),
2221 fmtIdent(ident),
2243 .identifier => |ident| try w.print("{f}", .{fmtIdentSolo(ident)}),
2244 .payload_identifier => |ident| try w.print("{f}.{f}", .{
2245 fmtIdentSolo("payload"),
2246 fmtIdentSolo(ident),
22222247 }),
2223 .ctype_pool_string => |string| try w.print("{ }", .{
2224 fmtCTypePoolString(string, &dg.ctype_pool),
2248 .ctype_pool_string => |string| try w.print("{f}", .{
2249 fmtCTypePoolString(string, &dg.ctype_pool, true),
22252250 }),
22262251 }
22272252 }
22282253
2229 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
2254 fn writeCValueDeref(dg: *DeclGen, w: *Writer, c_value: CValue) !void {
22302255 switch (c_value) {
22312256 .none,
22322257 .new_local,
......@@ -2245,26 +2270,31 @@ pub const DeclGen = struct {
22452270 },
22462271 .nav_ref => |nav| try dg.renderNavName(w, nav),
22472272 .undef => unreachable,
2248 .identifier => |ident| try w.print("(*{ })", .{fmtIdent(ident)}),
2249 .payload_identifier => |ident| try w.print("(*{ }.{ })", .{
2250 fmtIdent("payload"),
2251 fmtIdent(ident),
2273 .identifier => |ident| try w.print("(*{f})", .{fmtIdentSolo(ident)}),
2274 .payload_identifier => |ident| try w.print("(*{f}.{f})", .{
2275 fmtIdentSolo("payload"),
2276 fmtIdentSolo(ident),
22522277 }),
22532278 }
22542279 }
22552280
22562281 fn writeCValueMember(
22572282 dg: *DeclGen,
2258 writer: anytype,
2283 w: *Writer,
22592284 c_value: CValue,
22602285 member: CValue,
2261 ) error{ OutOfMemory, AnalysisFail }!void {
2262 try dg.writeCValue(writer, c_value);
2263 try writer.writeByte('.');
2264 try dg.writeCValue(writer, member);
2286 ) Error!void {
2287 try dg.writeCValue(w, c_value);
2288 try w.writeByte('.');
2289 try dg.writeCValue(w, member);
22652290 }
22662291
2267 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
2292 fn writeCValueDerefMember(
2293 dg: *DeclGen,
2294 w: *Writer,
2295 c_value: CValue,
2296 member: CValue,
2297 ) !void {
22682298 switch (c_value) {
22692299 .none,
22702300 .new_local,
......@@ -2278,15 +2308,15 @@ pub const DeclGen = struct {
22782308 .ctype_pool_string,
22792309 => unreachable,
22802310 .nav, .identifier, .payload_identifier => {
2281 try dg.writeCValue(writer, c_value);
2282 try writer.writeAll("->");
2311 try dg.writeCValue(w, c_value);
2312 try w.writeAll("->");
22832313 },
22842314 .nav_ref => {
2285 try dg.writeCValueDeref(writer, c_value);
2286 try writer.writeByte('.');
2315 try dg.writeCValueDeref(w, c_value);
2316 try w.writeByte('.');
22872317 },
22882318 }
2289 try dg.writeCValue(writer, member);
2319 try dg.writeCValue(w, member);
22902320 }
22912321
22922322 fn renderFwdDecl(
......@@ -2302,7 +2332,7 @@ pub const DeclGen = struct {
23022332 const zcu = dg.pt.zcu;
23032333 const ip = &zcu.intern_pool;
23042334 const nav = ip.getNav(nav_index);
2305 const fwd = dg.fwdDeclWriter();
2335 const fwd = &dg.fwd_decl.writer;
23062336 try fwd.writeAll(switch (flags.linkage) {
23072337 .internal => "static ",
23082338 .strong, .weak, .link_once => "zig_extern ",
......@@ -2328,36 +2358,36 @@ pub const DeclGen = struct {
23282358 try fwd.writeAll(";\n");
23292359 }
23302360
2331 fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void {
2361 fn renderNavName(dg: *DeclGen, w: *Writer, nav_index: InternPool.Nav.Index) !void {
23322362 const zcu = dg.pt.zcu;
23332363 const ip = &zcu.intern_pool;
23342364 const nav = ip.getNav(nav_index);
23352365 if (nav.getExtern(ip)) |@"extern"| {
2336 try writer.print("{ }", .{
2337 fmtIdent(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
2366 try w.print("{f}", .{
2367 fmtIdentSolo(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
23382368 });
23392369 } else {
23402370 // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
23412371 // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
23422372 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
2343 try writer.print("{}__{d}", .{
2344 fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
2373 try w.print("{f}__{d}", .{
2374 fmtIdentUnsolo(fqn_slice[0..@min(fqn_slice.len, 100)]),
23452375 @intFromEnum(nav_index),
23462376 });
23472377 }
23482378 }
23492379
2350 fn renderUavName(writer: anytype, uav: Value) !void {
2351 try writer.print("__anon_{d}", .{@intFromEnum(uav.toIntern())});
2380 fn renderUavName(w: *Writer, uav: Value) !void {
2381 try w.print("__anon_{d}", .{@intFromEnum(uav.toIntern())});
23522382 }
23532383
2354 fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {
2355 try dg.renderCTypeForBuiltinFnName(writer, try dg.ctypeFromType(ty, .complete));
2384 fn renderTypeForBuiltinFnName(dg: *DeclGen, w: *Writer, ty: Type) !void {
2385 try dg.renderCTypeForBuiltinFnName(w, try dg.ctypeFromType(ty, .complete));
23562386 }
23572387
2358 fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ctype: CType) !void {
2388 fn renderCTypeForBuiltinFnName(dg: *DeclGen, w: *Writer, ctype: CType) !void {
23592389 switch (ctype.info(&dg.ctype_pool)) {
2360 else => |ctype_info| try writer.print("{c}{d}", .{
2390 else => |ctype_info| try w.print("{c}{d}", .{
23612391 if (ctype.isBool())
23622392 signAbbrev(.unsigned)
23632393 else if (ctype.isInteger())
......@@ -2370,11 +2400,11 @@ pub const DeclGen = struct {
23702400 return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for {s} type", .{@tagName(ctype_info)}),
23712401 if (ctype.isFloat()) ctype.floatActiveBits(dg.mod) else dg.byteSize(ctype) * 8,
23722402 }),
2373 .array => try writer.writeAll("big"),
2403 .array => try w.writeAll("big"),
23742404 }
23752405 }
23762406
2377 fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {
2407 fn renderBuiltinInfo(dg: *DeclGen, w: *Writer, ty: Type, info: BuiltinInfo) !void {
23782408 const ctype = try dg.ctypeFromType(ty, .complete);
23792409 const is_big = ctype.info(&dg.ctype_pool) == .array;
23802410 switch (info) {
......@@ -2389,8 +2419,8 @@ pub const DeclGen = struct {
23892419 .bits = @intCast(ty.bitSize(zcu)),
23902420 };
23912421
2392 if (is_big) try writer.print(", {}", .{int_info.signedness == .signed});
2393 try writer.print(", {}", .{try dg.fmtIntLiteral(
2422 if (is_big) try w.print(", {}", .{int_info.signedness == .signed});
2423 try w.print(", {f}", .{try dg.fmtIntLiteralDec(
23942424 try pt.intValue(if (is_big) .u16 else .u8, int_info.bits),
23952425 .FunctionArgument,
23962426 )});
......@@ -2400,18 +2430,38 @@ pub const DeclGen = struct {
24002430 dg: *DeclGen,
24012431 val: Value,
24022432 loc: ValueRenderLocation,
2403 ) !std.fmt.Formatter(formatIntLiteral) {
2433 base: u8,
2434 case: std.fmt.Case,
2435 ) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) {
24042436 const zcu = dg.pt.zcu;
24052437 const kind = loc.toCTypeKind();
24062438 const ty = val.typeOf(zcu);
2407 return std.fmt.Formatter(formatIntLiteral){ .data = .{
2439 return .{ .data = .{
24082440 .dg = dg,
24092441 .int_info = ty.intInfo(zcu),
24102442 .kind = kind,
24112443 .ctype = try dg.ctypeFromType(ty, kind),
24122444 .val = val,
2445 .base = base,
2446 .case = case,
24132447 } };
24142448 }
2449
2450 fn fmtIntLiteralDec(
2451 dg: *DeclGen,
2452 val: Value,
2453 loc: ValueRenderLocation,
2454 ) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) {
2455 return fmtIntLiteral(dg, val, loc, 10, .lower);
2456 }
2457
2458 fn fmtIntLiteralHex(
2459 dg: *DeclGen,
2460 val: Value,
2461 loc: ValueRenderLocation,
2462 ) !std.fmt.Formatter(FormatIntLiteralContext, formatIntLiteral) {
2463 return fmtIntLiteral(dg, val, loc, 16, .lower);
2464 }
24152465};
24162466
24172467const CTypeFix = enum { prefix, suffix };
......@@ -2421,28 +2471,19 @@ const RenderCTypeTrailing = enum {
24212471 no_space,
24222472 maybe_space,
24232473
2424 pub fn format(
2425 self: @This(),
2426 comptime fmt: []const u8,
2427 _: std.fmt.FormatOptions,
2428 w: anytype,
2429 ) @TypeOf(w).Error!void {
2430 if (fmt.len != 0)
2431 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++
2432 @typeName(@This()) ++ "'");
2433 comptime assert(fmt.len == 0);
2474 pub fn format(self: @This(), w: *Writer) Writer.Error!void {
24342475 switch (self) {
24352476 .no_space => {},
24362477 .maybe_space => try w.writeByte(' '),
24372478 }
24382479 }
24392480};
2440fn renderAlignedTypeName(w: anytype, ctype: CType) !void {
2481fn renderAlignedTypeName(w: *Writer, ctype: CType) !void {
24412482 try w.print("anon__aligned_{d}", .{@intFromEnum(ctype.index)});
24422483}
24432484fn renderFwdDeclTypeName(
24442485 zcu: *Zcu,
2445 w: anytype,
2486 w: *Writer,
24462487 ctype: CType,
24472488 fwd_decl: CType.Info.FwdDecl,
24482489 attributes: []const u8,
......@@ -2451,8 +2492,8 @@ fn renderFwdDeclTypeName(
24512492 try w.print("{s} {s}", .{ @tagName(fwd_decl.tag), attributes });
24522493 switch (fwd_decl.name) {
24532494 .anon => try w.print("anon__lazy_{d}", .{@intFromEnum(ctype.index)}),
2454 .index => |index| try w.print("{}__{d}", .{
2455 fmtIdent(Type.fromInterned(index).containerTypeName(ip).toSlice(&zcu.intern_pool)),
2495 .index => |index| try w.print("{f}__{d}", .{
2496 fmtIdentUnsolo(Type.fromInterned(index).containerTypeName(ip).toSlice(&zcu.intern_pool)),
24562497 @intFromEnum(index),
24572498 }),
24582499 }
......@@ -2461,17 +2502,17 @@ fn renderTypePrefix(
24612502 pass: DeclGen.Pass,
24622503 ctype_pool: *const CType.Pool,
24632504 zcu: *Zcu,
2464 w: anytype,
2505 w: *Writer,
24652506 ctype: CType,
24662507 parent_fix: CTypeFix,
24672508 qualifiers: CQualifiers,
2468) @TypeOf(w).Error!RenderCTypeTrailing {
2509) Writer.Error!RenderCTypeTrailing {
24692510 var trailing = RenderCTypeTrailing.maybe_space;
24702511 switch (ctype.info(ctype_pool)) {
24712512 .basic => |basic_info| try w.writeAll(@tagName(basic_info)),
24722513
24732514 .pointer => |pointer_info| {
2474 try w.print("{}*", .{try renderTypePrefix(
2515 try w.print("{f}*", .{try renderTypePrefix(
24752516 pass,
24762517 ctype_pool,
24772518 zcu,
......@@ -2508,7 +2549,7 @@ fn renderTypePrefix(
25082549 );
25092550 switch (parent_fix) {
25102551 .prefix => {
2511 try w.print("{}(", .{child_trailing});
2552 try w.print("{f}(", .{child_trailing});
25122553 return .no_space;
25132554 },
25142555 .suffix => return child_trailing,
......@@ -2560,7 +2601,7 @@ fn renderTypePrefix(
25602601 );
25612602 switch (parent_fix) {
25622603 .prefix => {
2563 try w.print("{}(", .{child_trailing});
2604 try w.print("{f}(", .{child_trailing});
25642605 return .no_space;
25652606 },
25662607 .suffix => return child_trailing,
......@@ -2569,7 +2610,7 @@ fn renderTypePrefix(
25692610 }
25702611 var qualifier_it = qualifiers.iterator();
25712612 while (qualifier_it.next()) |qualifier| {
2572 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
2613 try w.print("{f}{s}", .{ trailing, @tagName(qualifier) });
25732614 trailing = .maybe_space;
25742615 }
25752616 return trailing;
......@@ -2578,11 +2619,11 @@ fn renderTypeSuffix(
25782619 pass: DeclGen.Pass,
25792620 ctype_pool: *const CType.Pool,
25802621 zcu: *Zcu,
2581 w: anytype,
2622 w: *Writer,
25822623 ctype: CType,
25832624 parent_fix: CTypeFix,
25842625 qualifiers: CQualifiers,
2585) @TypeOf(w).Error!void {
2626) Writer.Error!void {
25862627 switch (ctype.info(ctype_pool)) {
25872628 .basic, .aligned, .fwd_decl, .aggregate => {},
25882629 .pointer => |pointer_info| try renderTypeSuffix(
......@@ -2617,7 +2658,7 @@ fn renderTypeSuffix(
26172658 need_comma = true;
26182659 const trailing =
26192660 try renderTypePrefix(pass, ctype_pool, zcu, w, param_type, .suffix, qualifiers);
2620 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_index });
2661 if (qualifiers.contains(.@"const")) try w.print("{f}a{d}", .{ trailing, param_index });
26212662 try renderTypeSuffix(pass, ctype_pool, zcu, w, param_type, .suffix, .{});
26222663 }
26232664 if (function_info.varargs) {
......@@ -2634,49 +2675,49 @@ fn renderTypeSuffix(
26342675}
26352676fn renderFields(
26362677 zcu: *Zcu,
2637 writer: anytype,
2678 w: *Writer,
26382679 ctype_pool: *const CType.Pool,
26392680 aggregate_info: CType.Info.Aggregate,
26402681 indent: usize,
26412682) !void {
2642 try writer.writeAll("{\n");
2683 try w.writeAll("{\n");
26432684 for (0..aggregate_info.fields.len) |field_index| {
26442685 const field_info = aggregate_info.fields.at(field_index, ctype_pool);
2645 try writer.writeByteNTimes(' ', indent + 1);
2686 try w.splatByteAll(' ', indent + 1);
26462687 switch (field_info.alignas.abiOrder()) {
26472688 .lt => {
26482689 std.debug.assert(aggregate_info.@"packed");
2649 if (field_info.alignas.@"align" != .@"1") try writer.print("zig_under_align({}) ", .{
2690 if (field_info.alignas.@"align" != .@"1") try w.print("zig_under_align({}) ", .{
26502691 field_info.alignas.toByteUnits(),
26512692 });
26522693 },
26532694 .eq => if (aggregate_info.@"packed" and field_info.alignas.@"align" != .@"1")
2654 try writer.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}),
2695 try w.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}),
26552696 .gt => {
26562697 std.debug.assert(field_info.alignas.@"align" != .@"1");
2657 try writer.print("zig_align({}) ", .{field_info.alignas.toByteUnits()});
2698 try w.print("zig_align({}) ", .{field_info.alignas.toByteUnits()});
26582699 },
26592700 }
26602701 const trailing = try renderTypePrefix(
26612702 .flush,
26622703 ctype_pool,
26632704 zcu,
2664 writer,
2705 w,
26652706 field_info.ctype,
26662707 .suffix,
26672708 .{},
26682709 );
2669 try writer.print("{}{ }", .{ trailing, fmtCTypePoolString(field_info.name, ctype_pool) });
2670 try renderTypeSuffix(.flush, ctype_pool, zcu, writer, field_info.ctype, .suffix, .{});
2671 try writer.writeAll(";\n");
2710 try w.print("{f}{f}", .{ trailing, fmtCTypePoolString(field_info.name, ctype_pool, true) });
2711 try renderTypeSuffix(.flush, ctype_pool, zcu, w, field_info.ctype, .suffix, .{});
2712 try w.writeAll(";\n");
26722713 }
2673 try writer.writeByteNTimes(' ', indent);
2674 try writer.writeByte('}');
2714 try w.splatByteAll(' ', indent);
2715 try w.writeByte('}');
26752716}
26762717
26772718pub fn genTypeDecl(
26782719 zcu: *Zcu,
2679 writer: anytype,
2720 w: *Writer,
26802721 global_ctype_pool: *const CType.Pool,
26812722 global_ctype: CType,
26822723 pass: DeclGen.Pass,
......@@ -2689,27 +2730,27 @@ pub fn genTypeDecl(
26892730 .aligned => |aligned_info| {
26902731 if (!found_existing) {
26912732 std.debug.assert(aligned_info.alignas.abiOrder().compare(.lt));
2692 try writer.print("typedef zig_under_align({d}) ", .{aligned_info.alignas.toByteUnits()});
2693 try writer.print("{}", .{try renderTypePrefix(
2733 try w.print("typedef zig_under_align({d}) ", .{aligned_info.alignas.toByteUnits()});
2734 try w.print("{f}", .{try renderTypePrefix(
26942735 .flush,
26952736 global_ctype_pool,
26962737 zcu,
2697 writer,
2738 w,
26982739 aligned_info.ctype,
26992740 .suffix,
27002741 .{},
27012742 )});
2702 try renderAlignedTypeName(writer, global_ctype);
2703 try renderTypeSuffix(.flush, global_ctype_pool, zcu, writer, aligned_info.ctype, .suffix, .{});
2704 try writer.writeAll(";\n");
2743 try renderAlignedTypeName(w, global_ctype);
2744 try renderTypeSuffix(.flush, global_ctype_pool, zcu, w, aligned_info.ctype, .suffix, .{});
2745 try w.writeAll(";\n");
27052746 }
27062747 switch (pass) {
27072748 .nav, .uav => {
2708 try writer.writeAll("typedef ");
2709 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
2710 try writer.writeByte(' ');
2711 _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{});
2712 try writer.writeAll(";\n");
2749 try w.writeAll("typedef ");
2750 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{});
2751 try w.writeByte(' ');
2752 _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, w, decl_ctype, .suffix, .{});
2753 try w.writeAll(";\n");
27132754 },
27142755 .flush => {},
27152756 }
......@@ -2717,24 +2758,24 @@ pub fn genTypeDecl(
27172758 .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
27182759 .anon => switch (pass) {
27192760 .nav, .uav => {
2720 try writer.writeAll("typedef ");
2721 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
2722 try writer.writeByte(' ');
2723 _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{});
2724 try writer.writeAll(";\n");
2761 try w.writeAll("typedef ");
2762 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{});
2763 try w.writeByte(' ');
2764 _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, w, decl_ctype, .suffix, .{});
2765 try w.writeAll(";\n");
27252766 },
27262767 .flush => {},
27272768 },
27282769 .index => |index| if (!found_existing) {
27292770 const ip = &zcu.intern_pool;
27302771 const ty: Type = .fromInterned(index);
2731 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
2732 try writer.writeByte(';');
2772 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{});
2773 try w.writeByte(';');
27332774 const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip);
2734 if (!zcu.fileByIndex(file_scope).mod.?.strip) try writer.print(" /* {} */", .{
2775 if (!zcu.fileByIndex(file_scope).mod.?.strip) try w.print(" /* {f} */", .{
27352776 ty.containerTypeName(ip).fmt(ip),
27362777 });
2737 try writer.writeByte('\n');
2778 try w.writeByte('\n');
27382779 },
27392780 },
27402781 .aggregate => |aggregate_info| switch (aggregate_info.name) {
......@@ -2742,38 +2783,39 @@ pub fn genTypeDecl(
27422783 .fwd_decl => |fwd_decl| if (!found_existing) {
27432784 try renderFwdDeclTypeName(
27442785 zcu,
2745 writer,
2786 w,
27462787 fwd_decl,
27472788 fwd_decl.info(global_ctype_pool).fwd_decl,
27482789 if (aggregate_info.@"packed") "zig_packed(" else "",
27492790 );
2750 try writer.writeByte(' ');
2751 try renderFields(zcu, writer, global_ctype_pool, aggregate_info, 0);
2752 if (aggregate_info.@"packed") try writer.writeByte(')');
2753 try writer.writeAll(";\n");
2791 try w.writeByte(' ');
2792 try renderFields(zcu, w, global_ctype_pool, aggregate_info, 0);
2793 if (aggregate_info.@"packed") try w.writeByte(')');
2794 try w.writeAll(";\n");
27542795 },
27552796 },
27562797 }
27572798}
27582799
2759pub fn genGlobalAsm(zcu: *Zcu, writer: anytype) !void {
2800pub fn genGlobalAsm(zcu: *Zcu, w: *Writer) !void {
27602801 for (zcu.global_assembly.values()) |asm_source| {
2761 try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source, null)});
2802 try w.print("__asm({f});\n", .{fmtStringLiteral(asm_source, null)});
27622803 }
27632804}
27642805
2765pub fn genErrDecls(o: *Object) !void {
2806pub fn genErrDecls(o: *Object) Error!void {
27662807 const pt = o.dg.pt;
27672808 const zcu = pt.zcu;
27682809 const ip = &zcu.intern_pool;
2769 const writer = o.writer();
2810 const w = &o.code.writer;
27702811
27712812 var max_name_len: usize = 0;
27722813 // do not generate an invalid empty enum when the global error set is empty
27732814 const names = ip.global_error_set.getNamesFromMainThread();
27742815 if (names.len > 0) {
2775 try writer.writeAll("enum {\n");
2776 o.indent_writer.pushIndent();
2816 try w.writeAll("enum {");
2817 o.indent();
2818 try o.newline();
27772819 for (names, 1..) |name_nts, value| {
27782820 const name = name_nts.toSlice(ip);
27792821 max_name_len = @max(name.len, max_name_len);
......@@ -2781,11 +2823,13 @@ pub fn genErrDecls(o: *Object) !void {
27812823 .ty = .anyerror_type,
27822824 .name = name_nts,
27832825 } });
2784 try o.dg.renderValue(writer, Value.fromInterned(err_val), .Other);
2785 try writer.print(" = {d}u,\n", .{value});
2826 try o.dg.renderValue(w, Value.fromInterned(err_val), .Other);
2827 try w.print(" = {d}u,", .{value});
2828 try o.newline();
27862829 }
2787 o.indent_writer.popIndent();
2788 try writer.writeAll("};\n");
2830 try o.outdent();
2831 try w.writeAll("};");
2832 try o.newline();
27892833 }
27902834 const array_identifier = "zig_errorName";
27912835 const name_prefix = array_identifier ++ "_";
......@@ -2808,18 +2852,19 @@ pub fn genErrDecls(o: *Object) !void {
28082852 .storage = .{ .bytes = name.toString() },
28092853 } });
28102854
2811 try writer.writeAll("static ");
2855 try w.writeAll("static ");
28122856 try o.dg.renderTypeAndName(
2813 writer,
2857 w,
28142858 name_ty,
28152859 .{ .identifier = identifier },
28162860 Const,
28172861 .none,
28182862 .complete,
28192863 );
2820 try writer.writeAll(" = ");
2821 try o.dg.renderValue(writer, Value.fromInterned(name_val), .StaticInitializer);
2822 try writer.writeAll(";\n");
2864 try w.writeAll(" = ");
2865 try o.dg.renderValue(w, Value.fromInterned(name_val), .StaticInitializer);
2866 try w.writeByte(';');
2867 try o.newline();
28232868 }
28242869
28252870 const name_array_ty = try pt.arrayType(.{
......@@ -2827,33 +2872,34 @@ pub fn genErrDecls(o: *Object) !void {
28272872 .child = .slice_const_u8_sentinel_0_type,
28282873 });
28292874
2830 try writer.writeAll("static ");
2875 try w.writeAll("static ");
28312876 try o.dg.renderTypeAndName(
2832 writer,
2877 w,
28332878 name_array_ty,
28342879 .{ .identifier = array_identifier },
28352880 Const,
28362881 .none,
28372882 .complete,
28382883 );
2839 try writer.writeAll(" = {");
2884 try w.writeAll(" = {");
28402885 for (names, 1..) |name_nts, val| {
28412886 const name = name_nts.toSlice(ip);
2842 if (val > 1) try writer.writeAll(", ");
2843 try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{
2844 fmtIdent(name),
2845 try o.dg.fmtIntLiteral(try pt.intValue(.usize, name.len), .StaticInitializer),
2887 if (val > 1) try w.writeAll(", ");
2888 try w.print("{{" ++ name_prefix ++ "{f}, {f}}}", .{
2889 fmtIdentUnsolo(name),
2890 try o.dg.fmtIntLiteralDec(try pt.intValue(.usize, name.len), .StaticInitializer),
28462891 });
28472892 }
2848 try writer.writeAll("};\n");
2893 try w.writeAll("};");
2894 try o.newline();
28492895}
28502896
2851pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) !void {
2897pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) Error!void {
28522898 const pt = o.dg.pt;
28532899 const zcu = pt.zcu;
28542900 const ip = &zcu.intern_pool;
28552901 const ctype_pool = &o.dg.ctype_pool;
2856 const w = o.writer();
2902 const w = &o.code.writer;
28572903 const key = lazy_fn.key_ptr.*;
28582904 const val = lazy_fn.value_ptr;
28592905 switch (key) {
......@@ -2863,9 +2909,14 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
28632909
28642910 try w.writeAll("static ");
28652911 try o.dg.renderType(w, name_slice_ty);
2866 try w.print(" {}(", .{val.fn_name.fmt(lazy_ctype_pool)});
2912 try w.print(" {f}(", .{val.fn_name.fmt(lazy_ctype_pool)});
28672913 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
2868 try w.writeAll(") {\n switch (tag) {\n");
2914 try w.writeAll(") {");
2915 o.indent();
2916 try o.newline();
2917 try w.writeAll("switch (tag) {");
2918 o.indent();
2919 try o.newline();
28692920 const tag_names = enum_ty.enumFields(zcu);
28702921 for (0..tag_names.len) |tag_index| {
28712922 const tag_name = tag_names.get(ip)[tag_index];
......@@ -2882,34 +2933,43 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
28822933 .storage = .{ .bytes = tag_name.toString() },
28832934 } });
28842935
2885 try w.print(" case {}: {{\n static ", .{
2886 try o.dg.fmtIntLiteral(try tag_val.intFromEnum(enum_ty, pt), .Other),
2936 try w.print("case {f}: {{", .{
2937 try o.dg.fmtIntLiteralDec(try tag_val.intFromEnum(enum_ty, pt), .Other),
28872938 });
2939 o.indent();
2940 try o.newline();
2941 try w.writeAll("static ");
28882942 try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete);
28892943 try w.writeAll(" = ");
28902944 try o.dg.renderValue(w, Value.fromInterned(name_val), .StaticInitializer);
2891 try w.writeAll(";\n return (");
2945 try w.writeByte(';');
2946 try o.newline();
2947 try w.writeAll("return (");
28922948 try o.dg.renderType(w, name_slice_ty);
2893 try w.print("){{{}, {}}};\n", .{
2894 fmtIdent("name"),
2895 try o.dg.fmtIntLiteral(try pt.intValue(.usize, tag_name_len), .Other),
2949 try w.print("){{{f}, {f}}};", .{
2950 fmtIdentUnsolo("name"),
2951 try o.dg.fmtIntLiteralDec(try pt.intValue(.usize, tag_name_len), .Other),
28962952 });
2897
2898 try w.writeAll(" }\n");
2953 try o.newline();
2954 try o.outdent();
2955 try w.writeByte('}');
2956 try o.newline();
28992957 }
2900 try w.writeAll(" }\n while (");
2901 try o.dg.renderValue(w, Value.true, .Other);
2902 try w.writeAll(") ");
2903 _ = try airBreakpoint(w);
2904 try w.writeAll("}\n");
2958 try o.outdent();
2959 try w.writeByte('}');
2960 try o.newline();
2961 try airUnreach(o);
2962 try o.outdent();
2963 try w.writeByte('}');
2964 try o.newline();
29052965 },
29062966 .never_tail, .never_inline => |fn_nav_index| {
29072967 const fn_val = zcu.navValue(fn_nav_index);
29082968 const fn_ctype = try o.dg.ctypeFromType(fn_val.typeOf(zcu), .complete);
29092969 const fn_info = fn_ctype.info(ctype_pool).function;
2910 const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool);
2970 const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool, true);
29112971
2912 const fwd = o.dg.fwdDeclWriter();
2972 const fwd = &o.dg.fwd_decl.writer;
29132973 try fwd.print("static zig_{s} ", .{@tagName(key)});
29142974 try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).getAlignment(), .forward, .{
29152975 .fmt_ctype_pool_string = fn_name,
......@@ -2920,14 +2980,21 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
29202980 try o.dg.renderFunctionSignature(w, fn_val, .none, .complete, .{
29212981 .fmt_ctype_pool_string = fn_name,
29222982 });
2923 try w.writeAll(" {\n return ");
2983 try w.writeAll(" {");
2984 o.indent();
2985 try o.newline();
2986 try w.writeAll("return ");
29242987 try o.dg.renderNavName(w, fn_nav_index);
29252988 try w.writeByte('(');
29262989 for (0..fn_info.param_ctypes.len) |arg| {
29272990 if (arg > 0) try w.writeAll(", ");
29282991 try w.print("a{d}", .{arg});
29292992 }
2930 try w.writeAll(");\n}\n");
2993 try w.writeAll(");");
2994 try o.newline();
2995 try o.outdent();
2996 try w.writeByte('}');
2997 try o.newline();
29312998 },
29322999 }
29333000}
......@@ -2967,12 +3034,14 @@ pub fn generate(
29673034 .scratch = .empty,
29683035 .uavs = .empty,
29693036 },
3037 .code_header = .init(gpa),
29703038 .code = .init(gpa),
2971 .indent_writer = undefined, // set later so we can get a pointer to object.code
3039 .indent_counter = 0,
29723040 },
29733041 .lazy_fns = .empty,
29743042 };
29753043 defer {
3044 function.object.code_header.deinit();
29763045 function.object.code.deinit();
29773046 function.object.dg.fwd_decl.deinit();
29783047 function.object.dg.ctype_pool.deinit(gpa);
......@@ -2981,22 +3050,24 @@ pub fn generate(
29813050 function.deinit();
29823051 }
29833052 try function.object.dg.ctype_pool.init(gpa);
2984 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
29853053
29863054 genFunc(&function) catch |err| switch (err) {
29873055 error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.object.dg.error_msg.?),
2988 error.OutOfMemory => |e| return e,
3056 error.OutOfMemory => return error.OutOfMemory,
3057 error.WriteFailed => return error.OutOfMemory,
29893058 };
29903059
29913060 var mir: Mir = .{
29923061 .uavs = .empty,
29933062 .code = &.{},
3063 .code_header = &.{},
29943064 .fwd_decl = &.{},
29953065 .ctype_pool = .empty,
29963066 .lazy_fns = .empty,
29973067 };
29983068 errdefer mir.deinit(gpa);
29993069 mir.uavs = function.object.dg.uavs.move();
3070 mir.code_header = try function.object.code_header.toOwnedSlice();
30003071 mir.code = try function.object.code.toOwnedSlice();
30013072 mir.fwd_decl = try function.object.dg.fwd_decl.toOwnedSlice();
30023073 mir.ctype_pool = function.object.dg.ctype_pool.move();
......@@ -3004,7 +3075,7 @@ pub fn generate(
30043075 return mir;
30053076}
30063077
3007fn genFunc(f: *Function) !void {
3078pub fn genFunc(f: *Function) Error!void {
30083079 const tracy = trace(@src());
30093080 defer tracy.end();
30103081
......@@ -3016,10 +3087,7 @@ fn genFunc(f: *Function) !void {
30163087 const nav_val = zcu.navValue(nav_index);
30173088 const nav = ip.getNav(nav_index);
30183089
3019 o.code_header = std.ArrayList(u8).init(gpa);
3020 defer o.code_header.deinit();
3021
3022 const fwd = o.dg.fwdDeclWriter();
3090 const fwd = &o.dg.fwd_decl.writer;
30233091 try fwd.writeAll("static ");
30243092 try o.dg.renderFunctionSignature(
30253093 fwd,
......@@ -3030,29 +3098,26 @@ fn genFunc(f: *Function) !void {
30303098 );
30313099 try fwd.writeAll(";\n");
30323100
3101 const ch = &o.code_header.writer;
30333102 if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s|
3034 try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
3103 try ch.print("zig_linksection_fn({f}) ", .{fmtStringLiteral(s, null)});
30353104 try o.dg.renderFunctionSignature(
3036 o.writer(),
3105 ch,
30373106 nav_val,
30383107 .none,
30393108 .complete,
30403109 .{ .nav = nav_index },
30413110 );
3042 try o.writer().writeByte(' ');
3043
3044 // In case we need to use the header, populate it with a copy of the function
3045 // signature here. We anticipate a brace, newline, and space.
3046 try o.code_header.ensureUnusedCapacity(o.code.items.len + 3);
3047 o.code_header.appendSliceAssumeCapacity(o.code.items);
3048 o.code_header.appendSliceAssumeCapacity("{\n ");
3049 const empty_header_len = o.code_header.items.len;
3111 try ch.writeAll(" {\n ");
30503112
30513113 f.free_locals_map.clearRetainingCapacity();
30523114
30533115 const main_body = f.air.getMainBody();
3054 try genBodyResolveState(f, undefined, &.{}, main_body, false);
3055 try o.indent_writer.insertNewline();
3116 o.indent();
3117 try genBodyResolveState(f, undefined, &.{}, main_body, true);
3118 try o.outdent();
3119 try o.code.writer.writeByte('}');
3120 try o.newline();
30563121 if (o.dg.expected_block) |_|
30573122 return f.fail("runtime code not allowed in naked function", .{});
30583123
......@@ -3083,24 +3148,16 @@ fn genFunc(f: *Function) !void {
30833148 };
30843149 free_locals.sort(SortContext{ .keys = free_locals.keys() });
30853150
3086 const w = o.codeHeaderWriter();
30873151 for (free_locals.values()) |list| {
30883152 for (list.keys()) |local_index| {
30893153 const local = f.locals.items[local_index];
3090 try o.dg.renderCTypeAndName(w, local.ctype, .{ .local = local_index }, .{}, local.flags.alignas);
3091 try w.writeAll(";\n ");
3154 try o.dg.renderCTypeAndName(ch, local.ctype, .{ .local = local_index }, .{}, local.flags.alignas);
3155 try ch.writeAll(";\n ");
30923156 }
30933157 }
3094
3095 // If we have a header to insert, append the body to the header
3096 // and then return the result, freeing the body.
3097 if (o.code_header.items.len > empty_header_len) {
3098 try o.code_header.appendSlice(o.code.items[empty_header_len..]);
3099 mem.swap(std.ArrayList(u8), &o.code, &o.code_header);
3100 }
31013158}
31023159
3103pub fn genDecl(o: *Object) !void {
3160pub fn genDecl(o: *Object) Error!void {
31043161 const tracy = trace(@src());
31053162 defer tracy.end();
31063163
......@@ -3120,7 +3177,7 @@ pub fn genDecl(o: *Object) !void {
31203177 .visibility = @"extern".visibility,
31213178 });
31223179
3123 const fwd = o.dg.fwdDeclWriter();
3180 const fwd = &o.dg.fwd_decl.writer;
31243181 try fwd.writeAll("zig_extern ");
31253182 try o.dg.renderFunctionSignature(
31263183 fwd,
......@@ -3141,10 +3198,10 @@ pub fn genDecl(o: *Object) !void {
31413198 .linkage = .internal,
31423199 .visibility = .default,
31433200 });
3144 const w = o.writer();
3201 const w = &o.code.writer;
31453202 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
31463203 if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
3147 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
3204 try w.print("zig_linksection({f}) ", .{fmtStringLiteral(s, null)});
31483205 try o.dg.renderTypeAndName(
31493206 w,
31503207 nav_ty,
......@@ -3156,7 +3213,7 @@ pub fn genDecl(o: *Object) !void {
31563213 try w.writeAll(" = ");
31573214 try o.dg.renderValue(w, Value.fromInterned(variable.init), .StaticInitializer);
31583215 try w.writeByte(';');
3159 try o.indent_writer.insertNewline();
3216 try o.newline();
31603217 },
31613218 else => try genDeclValue(
31623219 o,
......@@ -3174,28 +3231,29 @@ pub fn genDeclValue(
31743231 decl_c_value: CValue,
31753232 alignment: Alignment,
31763233 @"linksection": InternPool.OptionalNullTerminatedString,
3177) !void {
3234) Error!void {
31783235 const zcu = o.dg.pt.zcu;
31793236 const ty = val.typeOf(zcu);
31803237
3181 const fwd = o.dg.fwdDeclWriter();
3238 const fwd = &o.dg.fwd_decl.writer;
31823239 try fwd.writeAll("static ");
31833240 try o.dg.renderTypeAndName(fwd, ty, decl_c_value, Const, alignment, .complete);
31843241 try fwd.writeAll(";\n");
31853242
3186 const w = o.writer();
3243 const w = &o.code.writer;
31873244 if (@"linksection".toSlice(&zcu.intern_pool)) |s|
3188 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
3245 try w.print("zig_linksection({f}) ", .{fmtStringLiteral(s, null)});
31893246 try o.dg.renderTypeAndName(w, ty, decl_c_value, Const, alignment, .complete);
31903247 try w.writeAll(" = ");
31913248 try o.dg.renderValue(w, val, .StaticInitializer);
3192 try w.writeAll(";\n");
3249 try w.writeByte(';');
3250 try o.newline();
31933251}
31943252
31953253pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index) !void {
31963254 const zcu = dg.pt.zcu;
31973255 const ip = &zcu.intern_pool;
3198 const fwd = dg.fwdDeclWriter();
3256 const fwd = &dg.fwd_decl.writer;
31993257
32003258 const main_name = export_indices[0].ptr(zcu).opts.name;
32013259 try fwd.writeAll("#define ");
......@@ -3204,7 +3262,7 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
32043262 .uav => |uav| try DeclGen.renderUavName(fwd, Value.fromInterned(uav)),
32053263 }
32063264 try fwd.writeByte(' ');
3207 try fwd.print("{ }", .{fmtIdent(main_name.toSlice(ip))});
3265 try fwd.print("{f}", .{fmtIdentSolo(main_name.toSlice(ip))});
32083266 try fwd.writeByte('\n');
32093267
32103268 const exported_val = exported.getValue(zcu);
......@@ -3234,7 +3292,7 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
32343292 const @"export" = export_index.ptr(zcu);
32353293 try fwd.writeAll("zig_extern ");
32363294 if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
3237 if (@"export".opts.section.toSlice(ip)) |s| try fwd.print("zig_linksection({s}) ", .{
3295 if (@"export".opts.section.toSlice(ip)) |s| try fwd.print("zig_linksection({f}) ", .{
32383296 fmtStringLiteral(s, null),
32393297 });
32403298 const extern_name = @"export".opts.name.toSlice(ip);
......@@ -3249,17 +3307,17 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
32493307 .complete,
32503308 );
32513309 if (is_mangled and is_export) {
3252 try fwd.print(" zig_mangled_export({ }, {s}, {s})", .{
3253 fmtIdent(extern_name),
3310 try fwd.print(" zig_mangled_export({f}, {f}, {f})", .{
3311 fmtIdentSolo(extern_name),
32543312 fmtStringLiteral(extern_name, null),
32553313 fmtStringLiteral(main_name.toSlice(ip), null),
32563314 });
32573315 } else if (is_mangled) {
3258 try fwd.print(" zig_mangled({ }, {s})", .{
3259 fmtIdent(extern_name), fmtStringLiteral(extern_name, null),
3316 try fwd.print(" zig_mangled({f}, {f})", .{
3317 fmtIdentSolo(extern_name), fmtStringLiteral(extern_name, null),
32603318 });
32613319 } else if (is_export) {
3262 try fwd.print(" zig_export({s}, {s})", .{
3320 try fwd.print(" zig_export({f}, {f})", .{
32633321 fmtStringLiteral(main_name.toSlice(ip), null),
32643322 fmtStringLiteral(extern_name, null),
32653323 });
......@@ -3272,16 +3330,17 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
32723330/// `value_map` and `free_locals_map` are undefined after the generation, and new locals may not
32733331/// have been added to `free_locals_map`. For a version of this function that restores this state,
32743332/// see `genBodyResolveState`.
3275fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
3276 const writer = f.object.writer();
3333fn genBody(f: *Function, body: []const Air.Inst.Index) Error!void {
3334 const w = &f.object.code.writer;
32773335 if (body.len == 0) {
3278 try writer.writeAll("{}");
3336 try w.writeAll("{}");
32793337 } else {
3280 try writer.writeAll("{\n");
3281 f.object.indent_writer.pushIndent();
3338 try w.writeByte('{');
3339 f.object.indent();
3340 try f.object.newline();
32823341 try genBodyInner(f, body);
3283 f.object.indent_writer.popIndent();
3284 try writer.writeByte('}');
3342 try f.object.outdent();
3343 try w.writeByte('}');
32853344 }
32863345}
32873346
......@@ -3291,10 +3350,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
32913350/// `leading_deaths` have their deaths processed before the body is generated.
32923351/// A scope is introduced (using braces) only if `inner` is `false`.
32933352/// If `leading_deaths` is empty, `inst` may be `undefined`.
3294fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []const Air.Inst.Index, body: []const Air.Inst.Index, inner: bool) error{ AnalysisFail, OutOfMemory }!void {
3353fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []const Air.Inst.Index, body: []const Air.Inst.Index, inner: bool) Error!void {
32953354 if (body.len == 0) {
32963355 // Don't go to the expense of cloning everything!
3297 if (!inner) try f.object.writer().writeAll("{}");
3356 if (!inner) try f.object.code.writer.writeAll("{}");
32983357 return;
32993358 }
33003359
......@@ -3340,7 +3399,7 @@ fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []con
33403399 }
33413400}
33423401
3343fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
3402fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {
33443403 const zcu = f.object.dg.pt.zcu;
33453404 const ip = &zcu.intern_pool;
33463405 const air_tags = f.air.instructions.items(.tag);
......@@ -3358,7 +3417,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
33583417
33593418 .arg => try airArg(f, inst),
33603419
3361 .breakpoint => try airBreakpoint(f.object.writer()),
3420 .breakpoint => try airBreakpoint(f),
33623421 .ret_addr => try airRetAddr(f, inst),
33633422 .frame_addr => try airFrameAddress(f, inst),
33643423
......@@ -3611,8 +3670,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
36113670 .ret => return airRet(f, inst, false),
36123671 .ret_safe => return airRet(f, inst, false), // TODO
36133672 .ret_load => return airRet(f, inst, true),
3614 .trap => return airTrap(f, f.object.writer()),
3615 .unreach => return airUnreach(f),
3673 .trap => return airTrap(f, &f.object.code.writer),
3674 .unreach => return airUnreach(&f.object),
36163675
36173676 // Instructions which may be `noreturn`.
36183677 .block => res: {
......@@ -3655,16 +3714,16 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
36553714 const operand = try f.resolveInst(ty_op.operand);
36563715 try reap(f, inst, &.{ty_op.operand});
36573716
3658 const writer = f.object.writer();
3717 const w = &f.object.code.writer;
36593718 const local = try f.allocLocal(inst, inst_ty);
3660 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3661 try f.writeCValue(writer, local, .Other);
3662 try a.assign(f, writer);
3719 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
3720 try f.writeCValue(w, local, .Other);
3721 try a.assign(f, w);
36633722 if (is_ptr) {
3664 try writer.writeByte('&');
3665 try f.writeCValueDerefMember(writer, operand, .{ .identifier = field_name });
3666 } else try f.writeCValueMember(writer, operand, .{ .identifier = field_name });
3667 try a.end(f, writer);
3723 try w.writeByte('&');
3724 try f.writeCValueDerefMember(w, operand, .{ .identifier = field_name });
3725 } else try f.writeCValueMember(w, operand, .{ .identifier = field_name });
3726 try a.end(f, w);
36683727 return local;
36693728}
36703729
......@@ -3681,16 +3740,16 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
36813740 const index = try f.resolveInst(bin_op.rhs);
36823741 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
36833742
3684 const writer = f.object.writer();
3743 const w = &f.object.code.writer;
36853744 const local = try f.allocLocal(inst, inst_ty);
3686 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3687 try f.writeCValue(writer, local, .Other);
3688 try a.assign(f, writer);
3689 try f.writeCValue(writer, ptr, .Other);
3690 try writer.writeByte('[');
3691 try f.writeCValue(writer, index, .Other);
3692 try writer.writeByte(']');
3693 try a.end(f, writer);
3745 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
3746 try f.writeCValue(w, local, .Other);
3747 try a.assign(f, w);
3748 try f.writeCValue(w, ptr, .Other);
3749 try w.writeByte('[');
3750 try f.writeCValue(w, index, .Other);
3751 try w.writeByte(']');
3752 try a.end(f, w);
36943753 return local;
36953754}
36963755
......@@ -3708,25 +3767,25 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
37083767 const index = try f.resolveInst(bin_op.rhs);
37093768 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
37103769
3711 const writer = f.object.writer();
3770 const w = &f.object.code.writer;
37123771 const local = try f.allocLocal(inst, inst_ty);
3713 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3714 try f.writeCValue(writer, local, .Other);
3715 try a.assign(f, writer);
3716 try writer.writeByte('(');
3717 try f.renderType(writer, inst_ty);
3718 try writer.writeByte(')');
3719 if (elem_has_bits) try writer.writeByte('&');
3772 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
3773 try f.writeCValue(w, local, .Other);
3774 try a.assign(f, w);
3775 try w.writeByte('(');
3776 try f.renderType(w, inst_ty);
3777 try w.writeByte(')');
3778 if (elem_has_bits) try w.writeByte('&');
37203779 if (elem_has_bits and ptr_ty.ptrSize(zcu) == .one) {
37213780 // It's a pointer to an array, so we need to de-reference.
3722 try f.writeCValueDeref(writer, ptr);
3723 } else try f.writeCValue(writer, ptr, .Other);
3781 try f.writeCValueDeref(w, ptr);
3782 } else try f.writeCValue(w, ptr, .Other);
37243783 if (elem_has_bits) {
3725 try writer.writeByte('[');
3726 try f.writeCValue(writer, index, .Other);
3727 try writer.writeByte(']');
3784 try w.writeByte('[');
3785 try f.writeCValue(w, index, .Other);
3786 try w.writeByte(']');
37283787 }
3729 try a.end(f, writer);
3788 try a.end(f, w);
37303789 return local;
37313790}
37323791
......@@ -3743,16 +3802,16 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
37433802 const index = try f.resolveInst(bin_op.rhs);
37443803 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
37453804
3746 const writer = f.object.writer();
3805 const w = &f.object.code.writer;
37473806 const local = try f.allocLocal(inst, inst_ty);
3748 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3749 try f.writeCValue(writer, local, .Other);
3750 try a.assign(f, writer);
3751 try f.writeCValueMember(writer, slice, .{ .identifier = "ptr" });
3752 try writer.writeByte('[');
3753 try f.writeCValue(writer, index, .Other);
3754 try writer.writeByte(']');
3755 try a.end(f, writer);
3807 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
3808 try f.writeCValue(w, local, .Other);
3809 try a.assign(f, w);
3810 try f.writeCValueMember(w, slice, .{ .identifier = "ptr" });
3811 try w.writeByte('[');
3812 try f.writeCValue(w, index, .Other);
3813 try w.writeByte(']');
3814 try a.end(f, w);
37563815 return local;
37573816}
37583817
......@@ -3771,19 +3830,19 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
37713830 const index = try f.resolveInst(bin_op.rhs);
37723831 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
37733832
3774 const writer = f.object.writer();
3833 const w = &f.object.code.writer;
37753834 const local = try f.allocLocal(inst, inst_ty);
3776 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3777 try f.writeCValue(writer, local, .Other);
3778 try a.assign(f, writer);
3779 if (elem_has_bits) try writer.writeByte('&');
3780 try f.writeCValueMember(writer, slice, .{ .identifier = "ptr" });
3835 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
3836 try f.writeCValue(w, local, .Other);
3837 try a.assign(f, w);
3838 if (elem_has_bits) try w.writeByte('&');
3839 try f.writeCValueMember(w, slice, .{ .identifier = "ptr" });
37813840 if (elem_has_bits) {
3782 try writer.writeByte('[');
3783 try f.writeCValue(writer, index, .Other);
3784 try writer.writeByte(']');
3841 try w.writeByte('[');
3842 try f.writeCValue(w, index, .Other);
3843 try w.writeByte(']');
37853844 }
3786 try a.end(f, writer);
3845 try a.end(f, w);
37873846 return local;
37883847}
37893848
......@@ -3800,16 +3859,16 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
38003859 const index = try f.resolveInst(bin_op.rhs);
38013860 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
38023861
3803 const writer = f.object.writer();
3862 const w = &f.object.code.writer;
38043863 const local = try f.allocLocal(inst, inst_ty);
3805 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
3806 try f.writeCValue(writer, local, .Other);
3807 try a.assign(f, writer);
3808 try f.writeCValue(writer, array, .Other);
3809 try writer.writeByte('[');
3810 try f.writeCValue(writer, index, .Other);
3811 try writer.writeByte(']');
3812 try a.end(f, writer);
3864 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
3865 try f.writeCValue(w, local, .Other);
3866 try a.assign(f, w);
3867 try f.writeCValue(w, array, .Other);
3868 try w.writeByte('[');
3869 try f.writeCValue(w, index, .Other);
3870 try w.writeByte(']');
3871 try a.end(f, w);
38133872 return local;
38143873}
38153874
......@@ -3863,12 +3922,13 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
38633922 .{ .arg_array = i };
38643923
38653924 if (f.liveness.isUnused(inst)) {
3866 const writer = f.object.writer();
3867 try writer.writeByte('(');
3868 try f.renderType(writer, .void);
3869 try writer.writeByte(')');
3870 try f.writeCValue(writer, result, .Other);
3871 try writer.writeAll(";\n");
3925 const w = &f.object.code.writer;
3926 try w.writeByte('(');
3927 try f.renderType(w, .void);
3928 try w.writeByte(')');
3929 try f.writeCValue(w, result, .Other);
3930 try w.writeByte(';');
3931 try f.object.newline();
38723932 return .none;
38733933 }
38743934
......@@ -3901,21 +3961,21 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
39013961 const is_array = lowersToArray(src_ty, pt);
39023962 const need_memcpy = !is_aligned or is_array;
39033963
3904 const writer = f.object.writer();
3964 const w = &f.object.code.writer;
39053965 const local = try f.allocLocal(inst, src_ty);
3906 const v = try Vectorize.start(f, inst, writer, ptr_ty);
3966 const v = try Vectorize.start(f, inst, w, ptr_ty);
39073967
39083968 if (need_memcpy) {
3909 try writer.writeAll("memcpy(");
3910 if (!is_array) try writer.writeByte('&');
3911 try f.writeCValue(writer, local, .Other);
3912 try v.elem(f, writer);
3913 try writer.writeAll(", (const char *)");
3914 try f.writeCValue(writer, operand, .Other);
3915 try v.elem(f, writer);
3916 try writer.writeAll(", sizeof(");
3917 try f.renderType(writer, src_ty);
3918 try writer.writeAll("))");
3969 try w.writeAll("memcpy(");
3970 if (!is_array) try w.writeByte('&');
3971 try f.writeCValue(w, local, .Other);
3972 try v.elem(f, w);
3973 try w.writeAll(", (const char *)");
3974 try f.writeCValue(w, operand, .Other);
3975 try v.elem(f, w);
3976 try w.writeAll(", sizeof(");
3977 try f.renderType(w, src_ty);
3978 try w.writeAll("))");
39193979 } else if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) {
39203980 const host_bits: u16 = ptr_info.packed_offset.host_size * 8;
39213981 const host_ty = try pt.intType(.unsigned, host_bits);
......@@ -3925,40 +3985,41 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
39253985
39263986 const field_ty = try pt.intType(.unsigned, @as(u16, @intCast(src_ty.bitSize(zcu))));
39273987
3928 try f.writeCValue(writer, local, .Other);
3929 try v.elem(f, writer);
3930 try writer.writeAll(" = (");
3931 try f.renderType(writer, src_ty);
3932 try writer.writeAll(")zig_wrap_");
3933 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);
3934 try writer.writeAll("((");
3935 try f.renderType(writer, field_ty);
3936 try writer.writeByte(')');
3988 try f.writeCValue(w, local, .Other);
3989 try v.elem(f, w);
3990 try w.writeAll(" = (");
3991 try f.renderType(w, src_ty);
3992 try w.writeAll(")zig_wrap_");
3993 try f.object.dg.renderTypeForBuiltinFnName(w, field_ty);
3994 try w.writeAll("((");
3995 try f.renderType(w, field_ty);
3996 try w.writeByte(')');
39373997 const cant_cast = host_ty.isInt(zcu) and host_ty.bitSize(zcu) > 64;
39383998 if (cant_cast) {
39393999 if (field_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
3940 try writer.writeAll("zig_lo_");
3941 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
3942 try writer.writeByte('(');
4000 try w.writeAll("zig_lo_");
4001 try f.object.dg.renderTypeForBuiltinFnName(w, host_ty);
4002 try w.writeByte('(');
39434003 }
3944 try writer.writeAll("zig_shr_");
3945 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
3946 try writer.writeByte('(');
3947 try f.writeCValueDeref(writer, operand);
3948 try v.elem(f, writer);
3949 try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_val)});
3950 if (cant_cast) try writer.writeByte(')');
3951 try f.object.dg.renderBuiltinInfo(writer, field_ty, .bits);
3952 try writer.writeByte(')');
4004 try w.writeAll("zig_shr_");
4005 try f.object.dg.renderTypeForBuiltinFnName(w, host_ty);
4006 try w.writeByte('(');
4007 try f.writeCValueDeref(w, operand);
4008 try v.elem(f, w);
4009 try w.print(", {f})", .{try f.fmtIntLiteralDec(bit_offset_val)});
4010 if (cant_cast) try w.writeByte(')');
4011 try f.object.dg.renderBuiltinInfo(w, field_ty, .bits);
4012 try w.writeByte(')');
39534013 } else {
3954 try f.writeCValue(writer, local, .Other);
3955 try v.elem(f, writer);
3956 try writer.writeAll(" = ");
3957 try f.writeCValueDeref(writer, operand);
3958 try v.elem(f, writer);
3959 }
3960 try writer.writeAll(";\n");
3961 try v.end(f, inst, writer);
4014 try f.writeCValue(w, local, .Other);
4015 try v.elem(f, w);
4016 try w.writeAll(" = ");
4017 try f.writeCValueDeref(w, operand);
4018 try v.elem(f, w);
4019 }
4020 try w.writeByte(';');
4021 try f.object.newline();
4022 try v.end(f, inst, w);
39624023
39634024 return local;
39644025}
......@@ -3967,7 +4028,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
39674028 const pt = f.object.dg.pt;
39684029 const zcu = pt.zcu;
39694030 const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3970 const writer = f.object.writer();
4031 const w = &f.object.code.writer;
39714032 const op_inst = un_op.toIndex();
39724033 const op_ty = f.typeOf(un_op);
39734034 const ret_ty = if (is_ptr) op_ty.childType(zcu) else op_ty;
......@@ -3986,33 +4047,34 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
39864047 .ctype = ret_ctype,
39874048 .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(zcu)),
39884049 });
3989 try writer.writeAll("memcpy(");
3990 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
3991 try writer.writeAll(", ");
4050 try w.writeAll("memcpy(");
4051 try f.writeCValueMember(w, array_local, .{ .identifier = "array" });
4052 try w.writeAll(", ");
39924053 if (deref)
3993 try f.writeCValueDeref(writer, operand)
4054 try f.writeCValueDeref(w, operand)
39944055 else
3995 try f.writeCValue(writer, operand, .FunctionArgument);
4056 try f.writeCValue(w, operand, .FunctionArgument);
39964057 deref = false;
3997 try writer.writeAll(", sizeof(");
3998 try f.renderType(writer, ret_ty);
3999 try writer.writeAll("));\n");
4058 try w.writeAll(", sizeof(");
4059 try f.renderType(w, ret_ty);
4060 try w.writeAll("));");
4061 try f.object.newline();
40004062 break :ret_val array_local;
40014063 } else operand;
40024064
4003 try writer.writeAll("return ");
4065 try w.writeAll("return ");
40044066 if (deref)
4005 try f.writeCValueDeref(writer, ret_val)
4067 try f.writeCValueDeref(w, ret_val)
40064068 else
4007 try f.writeCValue(writer, ret_val, .Other);
4008 try writer.writeAll(";\n");
4069 try f.writeCValue(w, ret_val, .Other);
4070 try w.writeAll(";\n");
40094071 if (is_array) {
40104072 try freeLocal(f, inst, ret_val.new_local, null);
40114073 }
40124074 } else {
40134075 try reap(f, inst, &.{un_op});
40144076 // Not even allowed to return void in a naked function.
4015 if (!f.object.dg.is_naked_fn) try writer.writeAll("return;\n");
4077 if (!f.object.dg.is_naked_fn) try w.writeAll("return;\n");
40164078 }
40174079}
40184080
......@@ -4031,16 +4093,16 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
40314093
40324094 if (f.object.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) return f.moveCValue(inst, inst_ty, operand);
40334095
4034 const writer = f.object.writer();
4096 const w = &f.object.code.writer;
40354097 const local = try f.allocLocal(inst, inst_ty);
4036 const v = try Vectorize.start(f, inst, writer, operand_ty);
4037 const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete));
4038 try f.writeCValue(writer, local, .Other);
4039 try v.elem(f, writer);
4040 try a.assign(f, writer);
4041 try f.renderIntCast(writer, inst_scalar_ty, operand, v, scalar_ty, .Other);
4042 try a.end(f, writer);
4043 try v.end(f, inst, writer);
4098 const v = try Vectorize.start(f, inst, w, operand_ty);
4099 const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete));
4100 try f.writeCValue(w, local, .Other);
4101 try v.elem(f, w);
4102 try a.assign(f, w);
4103 try f.renderIntCast(w, inst_scalar_ty, operand, v, scalar_ty, .Other);
4104 try a.end(f, w);
4105 try v.end(f, inst, w);
40444106 return local;
40454107}
40464108
......@@ -4067,35 +4129,35 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
40674129 const need_mask = dest_bits < 8 or !std.math.isPowerOfTwo(dest_bits);
40684130 if (!need_cast and !need_lo and !need_mask) return f.moveCValue(inst, inst_ty, operand);
40694131
4070 const writer = f.object.writer();
4132 const w = &f.object.code.writer;
40714133 const local = try f.allocLocal(inst, inst_ty);
4072 const v = try Vectorize.start(f, inst, writer, operand_ty);
4073 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete));
4074 try f.writeCValue(writer, local, .Other);
4075 try v.elem(f, writer);
4076 try a.assign(f, writer);
4134 const v = try Vectorize.start(f, inst, w, operand_ty);
4135 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_scalar_ty, .complete));
4136 try f.writeCValue(w, local, .Other);
4137 try v.elem(f, w);
4138 try a.assign(f, w);
40774139 if (need_cast) {
4078 try writer.writeByte('(');
4079 try f.renderType(writer, inst_scalar_ty);
4080 try writer.writeByte(')');
4140 try w.writeByte('(');
4141 try f.renderType(w, inst_scalar_ty);
4142 try w.writeByte(')');
40814143 }
40824144 if (need_lo) {
4083 try writer.writeAll("zig_lo_");
4084 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
4085 try writer.writeByte('(');
4145 try w.writeAll("zig_lo_");
4146 try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
4147 try w.writeByte('(');
40864148 }
40874149 if (!need_mask) {
4088 try f.writeCValue(writer, operand, .Other);
4089 try v.elem(f, writer);
4150 try f.writeCValue(w, operand, .Other);
4151 try v.elem(f, w);
40904152 } else switch (dest_int_info.signedness) {
40914153 .unsigned => {
4092 try writer.writeAll("zig_and_");
4093 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
4094 try writer.writeByte('(');
4095 try f.writeCValue(writer, operand, .FunctionArgument);
4096 try v.elem(f, writer);
4097 try writer.print(", {x})", .{
4098 try f.fmtIntLiteral(try inst_scalar_ty.maxIntScalar(pt, scalar_ty)),
4154 try w.writeAll("zig_and_");
4155 try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
4156 try w.writeByte('(');
4157 try f.writeCValue(w, operand, .FunctionArgument);
4158 try v.elem(f, w);
4159 try w.print(", {f})", .{
4160 try f.fmtIntLiteralHex(try inst_scalar_ty.maxIntScalar(pt, scalar_ty)),
40994161 });
41004162 },
41014163 .signed => {
......@@ -4103,30 +4165,30 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
41034165 return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{});
41044166 const shift_val = try pt.intValue(.u8, c_bits - dest_bits);
41054167
4106 try writer.writeAll("zig_shr_");
4107 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
4168 try w.writeAll("zig_shr_");
4169 try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
41084170 if (c_bits == 128) {
4109 try writer.print("(zig_bitCast_i{d}(", .{c_bits});
4171 try w.print("(zig_bitCast_i{d}(", .{c_bits});
41104172 } else {
4111 try writer.print("((int{d}_t)", .{c_bits});
4173 try w.print("((int{d}_t)", .{c_bits});
41124174 }
4113 try writer.print("zig_shl_u{d}(", .{c_bits});
4175 try w.print("zig_shl_u{d}(", .{c_bits});
41144176 if (c_bits == 128) {
4115 try writer.print("zig_bitCast_u{d}(", .{c_bits});
4177 try w.print("zig_bitCast_u{d}(", .{c_bits});
41164178 } else {
4117 try writer.print("(uint{d}_t)", .{c_bits});
4179 try w.print("(uint{d}_t)", .{c_bits});
41184180 }
4119 try f.writeCValue(writer, operand, .FunctionArgument);
4120 try v.elem(f, writer);
4121 if (c_bits == 128) try writer.writeByte(')');
4122 try writer.print(", {})", .{try f.fmtIntLiteral(shift_val)});
4123 if (c_bits == 128) try writer.writeByte(')');
4124 try writer.print(", {})", .{try f.fmtIntLiteral(shift_val)});
4181 try f.writeCValue(w, operand, .FunctionArgument);
4182 try v.elem(f, w);
4183 if (c_bits == 128) try w.writeByte(')');
4184 try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)});
4185 if (c_bits == 128) try w.writeByte(')');
4186 try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)});
41254187 },
41264188 }
4127 if (need_lo) try writer.writeByte(')');
4128 try a.end(f, writer);
4129 try v.end(f, inst, writer);
4189 if (need_lo) try w.writeByte(')');
4190 try a.end(f, w);
4191 try v.end(f, inst, w);
41304192 return local;
41314193}
41324194
......@@ -4145,15 +4207,16 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
41454207
41464208 const val_is_undef = if (try f.air.value(bin_op.rhs, pt)) |v| v.isUndefDeep(zcu) else false;
41474209
4210 const w = &f.object.code.writer;
41484211 if (val_is_undef) {
41494212 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
41504213 if (safety and ptr_info.packed_offset.host_size == 0) {
4151 const writer = f.object.writer();
4152 try writer.writeAll("memset(");
4153 try f.writeCValue(writer, ptr_val, .FunctionArgument);
4154 try writer.writeAll(", 0xaa, sizeof(");
4155 try f.renderType(writer, .fromInterned(ptr_info.child));
4156 try writer.writeAll("));\n");
4214 try w.writeAll("memset(");
4215 try f.writeCValue(w, ptr_val, .FunctionArgument);
4216 try w.writeAll(", 0xaa, sizeof(");
4217 try f.renderType(w, .fromInterned(ptr_info.child));
4218 try w.writeAll("));");
4219 try f.object.newline();
41574220 }
41584221 return .none;
41594222 }
......@@ -4169,7 +4232,6 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
41694232 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
41704233
41714234 const src_scalar_ctype = try f.ctypeFromType(src_ty.scalarType(zcu), .complete);
4172 const writer = f.object.writer();
41734235 if (need_memcpy) {
41744236 // For this memcpy to safely work we need the rhs to have the same
41754237 // underlying type as the lhs (i.e. they must both be arrays of the same underlying type).
......@@ -4180,28 +4242,30 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
41804242 // TODO this should be done by manually initializing elements of the dest array
41814243 const array_src = if (src_val == .constant) blk: {
41824244 const new_local = try f.allocLocal(inst, src_ty);
4183 try f.writeCValue(writer, new_local, .Other);
4184 try writer.writeAll(" = ");
4185 try f.writeCValue(writer, src_val, .Other);
4186 try writer.writeAll(";\n");
4245 try f.writeCValue(w, new_local, .Other);
4246 try w.writeAll(" = ");
4247 try f.writeCValue(w, src_val, .Other);
4248 try w.writeByte(';');
4249 try f.object.newline();
41874250
41884251 break :blk new_local;
41894252 } else src_val;
41904253
4191 const v = try Vectorize.start(f, inst, writer, ptr_ty);
4192 try writer.writeAll("memcpy((char *)");
4193 try f.writeCValue(writer, ptr_val, .FunctionArgument);
4194 try v.elem(f, writer);
4195 try writer.writeAll(", ");
4196 if (!is_array) try writer.writeByte('&');
4197 try f.writeCValue(writer, array_src, .FunctionArgument);
4198 try v.elem(f, writer);
4199 try writer.writeAll(", sizeof(");
4200 try f.renderType(writer, src_ty);
4201 try writer.writeAll("))");
4254 const v = try Vectorize.start(f, inst, w, ptr_ty);
4255 try w.writeAll("memcpy((char *)");
4256 try f.writeCValue(w, ptr_val, .FunctionArgument);
4257 try v.elem(f, w);
4258 try w.writeAll(", ");
4259 if (!is_array) try w.writeByte('&');
4260 try f.writeCValue(w, array_src, .FunctionArgument);
4261 try v.elem(f, w);
4262 try w.writeAll(", sizeof(");
4263 try f.renderType(w, src_ty);
4264 try w.writeAll("))");
42024265 try f.freeCValue(inst, array_src);
4203 try writer.writeAll(";\n");
4204 try v.end(f, inst, writer);
4266 try w.writeByte(';');
4267 try f.object.newline();
4268 try v.end(f, inst, w);
42054269 } else if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) {
42064270 const host_bits = ptr_info.packed_offset.host_size * 8;
42074271 const host_ty = try pt.intType(.unsigned, host_bits);
......@@ -4218,50 +4282,50 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
42184282 var mask = try BigInt.Managed.initCapacity(stack.get(), BigInt.calcTwosCompLimbCount(host_bits));
42194283 defer mask.deinit();
42204284
4221 try mask.setTwosCompIntLimit(.max, .unsigned, @as(usize, @intCast(src_bits)));
4285 try mask.setTwosCompIntLimit(.max, .unsigned, @intCast(src_bits));
42224286 try mask.shiftLeft(&mask, ptr_info.packed_offset.bit_offset);
42234287 try mask.bitNotWrap(&mask, .unsigned, host_bits);
42244288
42254289 const mask_val = try pt.intValue_big(host_ty, mask.toConst());
42264290
4227 const v = try Vectorize.start(f, inst, writer, ptr_ty);
4228 const a = try Assignment.start(f, writer, src_scalar_ctype);
4229 try f.writeCValueDeref(writer, ptr_val);
4230 try v.elem(f, writer);
4231 try a.assign(f, writer);
4232 try writer.writeAll("zig_or_");
4233 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
4234 try writer.writeAll("(zig_and_");
4235 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
4236 try writer.writeByte('(');
4237 try f.writeCValueDeref(writer, ptr_val);
4238 try v.elem(f, writer);
4239 try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(mask_val)});
4240 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
4241 try writer.writeByte('(');
4291 const v = try Vectorize.start(f, inst, w, ptr_ty);
4292 const a = try Assignment.start(f, w, src_scalar_ctype);
4293 try f.writeCValueDeref(w, ptr_val);
4294 try v.elem(f, w);
4295 try a.assign(f, w);
4296 try w.writeAll("zig_or_");
4297 try f.object.dg.renderTypeForBuiltinFnName(w, host_ty);
4298 try w.writeAll("(zig_and_");
4299 try f.object.dg.renderTypeForBuiltinFnName(w, host_ty);
4300 try w.writeByte('(');
4301 try f.writeCValueDeref(w, ptr_val);
4302 try v.elem(f, w);
4303 try w.print(", {f}), zig_shl_", .{try f.fmtIntLiteralHex(mask_val)});
4304 try f.object.dg.renderTypeForBuiltinFnName(w, host_ty);
4305 try w.writeByte('(');
42424306 const cant_cast = host_ty.isInt(zcu) and host_ty.bitSize(zcu) > 64;
42434307 if (cant_cast) {
42444308 if (src_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
4245 try writer.writeAll("zig_make_");
4246 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
4247 try writer.writeAll("(0, ");
4309 try w.writeAll("zig_make_");
4310 try f.object.dg.renderTypeForBuiltinFnName(w, host_ty);
4311 try w.writeAll("(0, ");
42484312 } else {
4249 try writer.writeByte('(');
4250 try f.renderType(writer, host_ty);
4251 try writer.writeByte(')');
4313 try w.writeByte('(');
4314 try f.renderType(w, host_ty);
4315 try w.writeByte(')');
42524316 }
42534317
42544318 if (src_ty.isPtrAtRuntime(zcu)) {
4255 try writer.writeByte('(');
4256 try f.renderType(writer, .usize);
4257 try writer.writeByte(')');
4319 try w.writeByte('(');
4320 try f.renderType(w, .usize);
4321 try w.writeByte(')');
42584322 }
4259 try f.writeCValue(writer, src_val, .Other);
4260 try v.elem(f, writer);
4261 if (cant_cast) try writer.writeByte(')');
4262 try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_val)});
4263 try a.end(f, writer);
4264 try v.end(f, inst, writer);
4323 try f.writeCValue(w, src_val, .Other);
4324 try v.elem(f, w);
4325 if (cant_cast) try w.writeByte(')');
4326 try w.print(", {f}))", .{try f.fmtIntLiteralDec(bit_offset_val)});
4327 try a.end(f, w);
4328 try v.end(f, inst, w);
42654329 } else {
42664330 switch (ptr_val) {
42674331 .local_ref => |ptr_local_index| switch (src_val) {
......@@ -4271,15 +4335,15 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
42714335 },
42724336 else => {},
42734337 }
4274 const v = try Vectorize.start(f, inst, writer, ptr_ty);
4275 const a = try Assignment.start(f, writer, src_scalar_ctype);
4276 try f.writeCValueDeref(writer, ptr_val);
4277 try v.elem(f, writer);
4278 try a.assign(f, writer);
4279 try f.writeCValue(writer, src_val, .Other);
4280 try v.elem(f, writer);
4281 try a.end(f, writer);
4282 try v.end(f, inst, writer);
4338 const v = try Vectorize.start(f, inst, w, ptr_ty);
4339 const a = try Assignment.start(f, w, src_scalar_ctype);
4340 try f.writeCValueDeref(w, ptr_val);
4341 try v.elem(f, w);
4342 try a.assign(f, w);
4343 try f.writeCValue(w, src_val, .Other);
4344 try v.elem(f, w);
4345 try a.end(f, w);
4346 try v.end(f, inst, w);
42834347 }
42844348 return .none;
42854349}
......@@ -4298,7 +4362,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
42984362 const operand_ty = f.typeOf(bin_op.lhs);
42994363 const scalar_ty = operand_ty.scalarType(zcu);
43004364
4301 const w = f.object.writer();
4365 const w = &f.object.code.writer;
43024366 const local = try f.allocLocal(inst, inst_ty);
43034367 const v = try Vectorize.start(f, inst, w, operand_ty);
43044368 try f.writeCValueMember(w, local, .{ .field = 1 });
......@@ -4317,7 +4381,8 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
43174381 try f.writeCValue(w, rhs, .FunctionArgument);
43184382 if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w);
43194383 try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
4320 try w.writeAll(");\n");
4384 try w.writeAll(");");
4385 try f.object.newline();
43214386 try v.end(f, inst, w);
43224387
43234388 return local;
......@@ -4336,17 +4401,18 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
43364401
43374402 const inst_ty = f.typeOfIndex(inst);
43384403
4339 const writer = f.object.writer();
4404 const w = &f.object.code.writer;
43404405 const local = try f.allocLocal(inst, inst_ty);
4341 const v = try Vectorize.start(f, inst, writer, operand_ty);
4342 try f.writeCValue(writer, local, .Other);
4343 try v.elem(f, writer);
4344 try writer.writeAll(" = ");
4345 try writer.writeByte('!');
4346 try f.writeCValue(writer, op, .Other);
4347 try v.elem(f, writer);
4348 try writer.writeAll(";\n");
4349 try v.end(f, inst, writer);
4406 const v = try Vectorize.start(f, inst, w, operand_ty);
4407 try f.writeCValue(w, local, .Other);
4408 try v.elem(f, w);
4409 try w.writeAll(" = ");
4410 try w.writeByte('!');
4411 try f.writeCValue(w, op, .Other);
4412 try v.elem(f, w);
4413 try w.writeByte(';');
4414 try f.object.newline();
4415 try v.end(f, inst, w);
43504416
43514417 return local;
43524418}
......@@ -4372,21 +4438,22 @@ fn airBinOp(
43724438
43734439 const inst_ty = f.typeOfIndex(inst);
43744440
4375 const writer = f.object.writer();
4441 const w = &f.object.code.writer;
43764442 const local = try f.allocLocal(inst, inst_ty);
4377 const v = try Vectorize.start(f, inst, writer, operand_ty);
4378 try f.writeCValue(writer, local, .Other);
4379 try v.elem(f, writer);
4380 try writer.writeAll(" = ");
4381 try f.writeCValue(writer, lhs, .Other);
4382 try v.elem(f, writer);
4383 try writer.writeByte(' ');
4384 try writer.writeAll(operator);
4385 try writer.writeByte(' ');
4386 try f.writeCValue(writer, rhs, .Other);
4387 try v.elem(f, writer);
4388 try writer.writeAll(";\n");
4389 try v.end(f, inst, writer);
4443 const v = try Vectorize.start(f, inst, w, operand_ty);
4444 try f.writeCValue(w, local, .Other);
4445 try v.elem(f, w);
4446 try w.writeAll(" = ");
4447 try f.writeCValue(w, lhs, .Other);
4448 try v.elem(f, w);
4449 try w.writeByte(' ');
4450 try w.writeAll(operator);
4451 try w.writeByte(' ');
4452 try f.writeCValue(w, rhs, .Other);
4453 try v.elem(f, w);
4454 try w.writeByte(';');
4455 try f.object.newline();
4456 try v.end(f, inst, w);
43904457
43914458 return local;
43924459}
......@@ -4422,27 +4489,27 @@ fn airCmpOp(
44224489
44234490 const rhs_ty = f.typeOf(data.rhs);
44244491 const need_cast = lhs_ty.isSinglePointer(zcu) or rhs_ty.isSinglePointer(zcu);
4425 const writer = f.object.writer();
4492 const w = &f.object.code.writer;
44264493 const local = try f.allocLocal(inst, inst_ty);
4427 const v = try Vectorize.start(f, inst, writer, lhs_ty);
4428 const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete));
4429 try f.writeCValue(writer, local, .Other);
4430 try v.elem(f, writer);
4431 try a.assign(f, writer);
4432 if (lhs != .undef and lhs.eql(rhs)) try writer.writeAll(switch (operator) {
4494 const v = try Vectorize.start(f, inst, w, lhs_ty);
4495 const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete));
4496 try f.writeCValue(w, local, .Other);
4497 try v.elem(f, w);
4498 try a.assign(f, w);
4499 if (lhs != .undef and lhs.eql(rhs)) try w.writeAll(switch (operator) {
44334500 .lt, .neq, .gt => "false",
44344501 .lte, .eq, .gte => "true",
44354502 }) else {
4436 if (need_cast) try writer.writeAll("(void*)");
4437 try f.writeCValue(writer, lhs, .Other);
4438 try v.elem(f, writer);
4439 try writer.writeAll(compareOperatorC(operator));
4440 if (need_cast) try writer.writeAll("(void*)");
4441 try f.writeCValue(writer, rhs, .Other);
4442 try v.elem(f, writer);
4443 }
4444 try a.end(f, writer);
4445 try v.end(f, inst, writer);
4503 if (need_cast) try w.writeAll("(void*)");
4504 try f.writeCValue(w, lhs, .Other);
4505 try v.elem(f, w);
4506 try w.writeAll(compareOperatorC(operator));
4507 if (need_cast) try w.writeAll("(void*)");
4508 try f.writeCValue(w, rhs, .Other);
4509 try v.elem(f, w);
4510 }
4511 try a.end(f, w);
4512 try v.end(f, inst, w);
44464513
44474514 return local;
44484515}
......@@ -4475,41 +4542,41 @@ fn airEquality(
44754542 const rhs = try f.resolveInst(bin_op.rhs);
44764543 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
44774544
4478 const writer = f.object.writer();
4545 const w = &f.object.code.writer;
44794546 const local = try f.allocLocal(inst, .bool);
4480 const a = try Assignment.start(f, writer, .bool);
4481 try f.writeCValue(writer, local, .Other);
4482 try a.assign(f, writer);
4547 const a = try Assignment.start(f, w, .bool);
4548 try f.writeCValue(w, local, .Other);
4549 try a.assign(f, w);
44834550
44844551 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
4485 if (lhs != .undef and lhs.eql(rhs)) try writer.writeAll(switch (operator) {
4552 if (lhs != .undef and lhs.eql(rhs)) try w.writeAll(switch (operator) {
44864553 .lt, .lte, .gte, .gt => unreachable,
44874554 .neq => "false",
44884555 .eq => "true",
44894556 }) else switch (operand_ctype.info(ctype_pool)) {
44904557 .basic, .pointer => {
4491 try f.writeCValue(writer, lhs, .Other);
4492 try writer.writeAll(compareOperatorC(operator));
4493 try f.writeCValue(writer, rhs, .Other);
4558 try f.writeCValue(w, lhs, .Other);
4559 try w.writeAll(compareOperatorC(operator));
4560 try f.writeCValue(w, rhs, .Other);
44944561 },
44954562 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
44964563 .aggregate => |aggregate| if (aggregate.fields.len == 2 and
44974564 (aggregate.fields.at(0, ctype_pool).name.index == .is_null or
44984565 aggregate.fields.at(1, ctype_pool).name.index == .is_null))
44994566 {
4500 try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });
4501 try writer.writeAll(" || ");
4502 try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });
4503 try writer.writeAll(" ? ");
4504 try f.writeCValueMember(writer, lhs, .{ .identifier = "is_null" });
4505 try writer.writeAll(compareOperatorC(operator));
4506 try f.writeCValueMember(writer, rhs, .{ .identifier = "is_null" });
4507 try writer.writeAll(" : ");
4508 try f.writeCValueMember(writer, lhs, .{ .identifier = "payload" });
4509 try writer.writeAll(compareOperatorC(operator));
4510 try f.writeCValueMember(writer, rhs, .{ .identifier = "payload" });
4567 try f.writeCValueMember(w, lhs, .{ .identifier = "is_null" });
4568 try w.writeAll(" || ");
4569 try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" });
4570 try w.writeAll(" ? ");
4571 try f.writeCValueMember(w, lhs, .{ .identifier = "is_null" });
4572 try w.writeAll(compareOperatorC(operator));
4573 try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" });
4574 try w.writeAll(" : ");
4575 try f.writeCValueMember(w, lhs, .{ .identifier = "payload" });
4576 try w.writeAll(compareOperatorC(operator));
4577 try f.writeCValueMember(w, rhs, .{ .identifier = "payload" });
45114578 } else for (0..aggregate.fields.len) |field_index| {
4512 if (field_index > 0) try writer.writeAll(switch (operator) {
4579 if (field_index > 0) try w.writeAll(switch (operator) {
45134580 .lt, .lte, .gte, .gt => unreachable,
45144581 .eq => " && ",
45154582 .neq => " || ",
......@@ -4517,12 +4584,12 @@ fn airEquality(
45174584 const field_name: CValue = .{
45184585 .ctype_pool_string = aggregate.fields.at(field_index, ctype_pool).name,
45194586 };
4520 try f.writeCValueMember(writer, lhs, field_name);
4521 try writer.writeAll(compareOperatorC(operator));
4522 try f.writeCValueMember(writer, rhs, field_name);
4587 try f.writeCValueMember(w, lhs, field_name);
4588 try w.writeAll(compareOperatorC(operator));
4589 try f.writeCValueMember(w, rhs, field_name);
45234590 },
45244591 }
4525 try a.end(f, writer);
4592 try a.end(f, w);
45264593
45274594 return local;
45284595}
......@@ -4533,12 +4600,13 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
45334600 const operand = try f.resolveInst(un_op);
45344601 try reap(f, inst, &.{un_op});
45354602
4536 const writer = f.object.writer();
4603 const w = &f.object.code.writer;
45374604 const local = try f.allocLocal(inst, .bool);
4538 try f.writeCValue(writer, local, .Other);
4539 try writer.writeAll(" = ");
4540 try f.writeCValue(writer, operand, .Other);
4541 try writer.print(" < sizeof({ }) / sizeof(*{0 });\n", .{fmtIdent("zig_errorName")});
4605 try f.writeCValue(w, local, .Other);
4606 try w.writeAll(" = ");
4607 try f.writeCValue(w, operand, .Other);
4608 try w.print(" < sizeof({f}) / sizeof(*{0f});", .{fmtIdentSolo("zig_errorName")});
4609 try f.object.newline();
45424610 return local;
45434611}
45444612
......@@ -4559,30 +4627,30 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
45594627 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
45604628
45614629 const local = try f.allocLocal(inst, inst_ty);
4562 const writer = f.object.writer();
4563 const v = try Vectorize.start(f, inst, writer, inst_ty);
4564 const a = try Assignment.start(f, writer, inst_scalar_ctype);
4565 try f.writeCValue(writer, local, .Other);
4566 try v.elem(f, writer);
4567 try a.assign(f, writer);
4630 const w = &f.object.code.writer;
4631 const v = try Vectorize.start(f, inst, w, inst_ty);
4632 const a = try Assignment.start(f, w, inst_scalar_ctype);
4633 try f.writeCValue(w, local, .Other);
4634 try v.elem(f, w);
4635 try a.assign(f, w);
45684636 // We must convert to and from integer types to prevent UB if the operation
45694637 // results in a NULL pointer, or if LHS is NULL. The operation is only UB
45704638 // if the result is NULL and then dereferenced.
4571 try writer.writeByte('(');
4572 try f.renderCType(writer, inst_scalar_ctype);
4573 try writer.writeAll(")(((uintptr_t)");
4574 try f.writeCValue(writer, lhs, .Other);
4575 try v.elem(f, writer);
4576 try writer.writeAll(") ");
4577 try writer.writeByte(operator);
4578 try writer.writeAll(" (");
4579 try f.writeCValue(writer, rhs, .Other);
4580 try v.elem(f, writer);
4581 try writer.writeAll("*sizeof(");
4582 try f.renderType(writer, elem_ty);
4583 try writer.writeAll(")))");
4584 try a.end(f, writer);
4585 try v.end(f, inst, writer);
4639 try w.writeByte('(');
4640 try f.renderCType(w, inst_scalar_ctype);
4641 try w.writeAll(")(((uintptr_t)");
4642 try f.writeCValue(w, lhs, .Other);
4643 try v.elem(f, w);
4644 try w.writeAll(") ");
4645 try w.writeByte(operator);
4646 try w.writeAll(" (");
4647 try f.writeCValue(w, rhs, .Other);
4648 try v.elem(f, w);
4649 try w.writeAll("*sizeof(");
4650 try f.renderType(w, elem_ty);
4651 try w.writeAll(")))");
4652 try a.end(f, w);
4653 try v.end(f, inst, w);
45864654 return local;
45874655}
45884656
......@@ -4601,28 +4669,29 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
46014669 const rhs = try f.resolveInst(bin_op.rhs);
46024670 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
46034671
4604 const writer = f.object.writer();
4672 const w = &f.object.code.writer;
46054673 const local = try f.allocLocal(inst, inst_ty);
4606 const v = try Vectorize.start(f, inst, writer, inst_ty);
4607 try f.writeCValue(writer, local, .Other);
4608 try v.elem(f, writer);
4674 const v = try Vectorize.start(f, inst, w, inst_ty);
4675 try f.writeCValue(w, local, .Other);
4676 try v.elem(f, w);
46094677 // (lhs <> rhs) ? lhs : rhs
4610 try writer.writeAll(" = (");
4611 try f.writeCValue(writer, lhs, .Other);
4612 try v.elem(f, writer);
4613 try writer.writeByte(' ');
4614 try writer.writeByte(operator);
4615 try writer.writeByte(' ');
4616 try f.writeCValue(writer, rhs, .Other);
4617 try v.elem(f, writer);
4618 try writer.writeAll(") ? ");
4619 try f.writeCValue(writer, lhs, .Other);
4620 try v.elem(f, writer);
4621 try writer.writeAll(" : ");
4622 try f.writeCValue(writer, rhs, .Other);
4623 try v.elem(f, writer);
4624 try writer.writeAll(";\n");
4625 try v.end(f, inst, writer);
4678 try w.writeAll(" = (");
4679 try f.writeCValue(w, lhs, .Other);
4680 try v.elem(f, w);
4681 try w.writeByte(' ');
4682 try w.writeByte(operator);
4683 try w.writeByte(' ');
4684 try f.writeCValue(w, rhs, .Other);
4685 try v.elem(f, w);
4686 try w.writeAll(") ? ");
4687 try f.writeCValue(w, lhs, .Other);
4688 try v.elem(f, w);
4689 try w.writeAll(" : ");
4690 try f.writeCValue(w, rhs, .Other);
4691 try v.elem(f, w);
4692 try w.writeByte(';');
4693 try f.object.newline();
4694 try v.end(f, inst, w);
46264695
46274696 return local;
46284697}
......@@ -4640,21 +4709,21 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
46404709 const inst_ty = f.typeOfIndex(inst);
46414710 const ptr_ty = inst_ty.slicePtrFieldType(zcu);
46424711
4643 const writer = f.object.writer();
4712 const w = &f.object.code.writer;
46444713 const local = try f.allocLocal(inst, inst_ty);
46454714 {
4646 const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete));
4647 try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
4648 try a.assign(f, writer);
4649 try f.writeCValue(writer, ptr, .Other);
4650 try a.end(f, writer);
4715 const a = try Assignment.start(f, w, try f.ctypeFromType(ptr_ty, .complete));
4716 try f.writeCValueMember(w, local, .{ .identifier = "ptr" });
4717 try a.assign(f, w);
4718 try f.writeCValue(w, ptr, .Other);
4719 try a.end(f, w);
46514720 }
46524721 {
4653 const a = try Assignment.start(f, writer, .usize);
4654 try f.writeCValueMember(writer, local, .{ .identifier = "len" });
4655 try a.assign(f, writer);
4656 try f.writeCValue(writer, len, .Other);
4657 try a.end(f, writer);
4722 const a = try Assignment.start(f, w, .usize);
4723 try f.writeCValueMember(w, local, .{ .identifier = "len" });
4724 try a.assign(f, w);
4725 try f.writeCValue(w, len, .Other);
4726 try a.end(f, w);
46584727 }
46594728 return local;
46604729}
......@@ -4671,7 +4740,7 @@ fn airCall(
46714740 if (f.object.dg.is_naked_fn) return .none;
46724741
46734742 const gpa = f.object.dg.gpa;
4674 const writer = f.object.writer();
4743 const w = &f.object.code.writer;
46754744
46764745 const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
46774746 const extra = f.air.extraData(Air.Call, pl_op.payload);
......@@ -4692,13 +4761,14 @@ fn airCall(
46924761 .ctype = arg_ctype,
46934762 .alignas = CType.AlignAs.fromAbiAlignment(arg_ty.abiAlignment(zcu)),
46944763 });
4695 try writer.writeAll("memcpy(");
4696 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
4697 try writer.writeAll(", ");
4698 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
4699 try writer.writeAll(", sizeof(");
4700 try f.renderCType(writer, arg_ctype);
4701 try writer.writeAll("));\n");
4764 try w.writeAll("memcpy(");
4765 try f.writeCValueMember(w, array_local, .{ .identifier = "array" });
4766 try w.writeAll(", ");
4767 try f.writeCValue(w, resolved_arg.*, .FunctionArgument);
4768 try w.writeAll(", sizeof(");
4769 try f.renderCType(w, arg_ctype);
4770 try w.writeAll("));");
4771 try f.object.newline();
47024772 resolved_arg.* = array_local;
47034773 }
47044774 }
......@@ -4726,22 +4796,22 @@ fn airCall(
47264796
47274797 const result_local = result: {
47284798 if (modifier == .always_tail) {
4729 try writer.writeAll("zig_always_tail return ");
4799 try w.writeAll("zig_always_tail return ");
47304800 break :result .none;
47314801 } else if (ret_ctype.index == .void) {
47324802 break :result .none;
47334803 } else if (f.liveness.isUnused(inst)) {
4734 try writer.writeByte('(');
4735 try f.renderCType(writer, .void);
4736 try writer.writeByte(')');
4804 try w.writeByte('(');
4805 try f.renderCType(w, .void);
4806 try w.writeByte(')');
47374807 break :result .none;
47384808 } else {
47394809 const local = try f.allocAlignedLocal(inst, .{
47404810 .ctype = ret_ctype,
47414811 .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(zcu)),
47424812 });
4743 try f.writeCValue(writer, local, .Other);
4744 try writer.writeAll(" = ");
4813 try f.writeCValue(w, local, .Other);
4814 try w.writeAll(" = ");
47454815 break :result local;
47464816 }
47474817 };
......@@ -4761,17 +4831,17 @@ fn airCall(
47614831 else => break :known,
47624832 };
47634833 if (need_cast) {
4764 try writer.writeAll("((");
4765 try f.renderType(writer, if (callee_is_ptr) callee_ty else try pt.singleConstPtrType(callee_ty));
4766 try writer.writeByte(')');
4767 if (!callee_is_ptr) try writer.writeByte('&');
4834 try w.writeAll("((");
4835 try f.renderType(w, if (callee_is_ptr) callee_ty else try pt.singleConstPtrType(callee_ty));
4836 try w.writeByte(')');
4837 if (!callee_is_ptr) try w.writeByte('&');
47684838 }
47694839 switch (modifier) {
4770 .auto, .always_tail => try f.object.dg.renderNavName(writer, fn_nav),
4771 inline .never_tail, .never_inline => |m| try writer.writeAll(try f.getLazyFnName(@unionInit(LazyFnKey, @tagName(m), fn_nav))),
4840 .auto, .always_tail => try f.object.dg.renderNavName(w, fn_nav),
4841 inline .never_tail, .never_inline => |m| try w.writeAll(try f.getLazyFnName(@unionInit(LazyFnKey, @tagName(m), fn_nav))),
47724842 else => unreachable,
47734843 }
4774 if (need_cast) try writer.writeByte(')');
4844 if (need_cast) try w.writeByte(')');
47754845 break :callee;
47764846 }
47774847 switch (modifier) {
......@@ -4781,32 +4851,37 @@ fn airCall(
47814851 else => unreachable,
47824852 }
47834853 // Fall back to function pointer call.
4784 try f.writeCValue(writer, callee, .Other);
4854 try f.writeCValue(w, callee, .Other);
47854855 }
47864856
4787 try writer.writeByte('(');
4857 try w.writeByte('(');
47884858 var need_comma = false;
47894859 for (resolved_args) |resolved_arg| {
47904860 if (resolved_arg == .none) continue;
4791 if (need_comma) try writer.writeAll(", ");
4861 if (need_comma) try w.writeAll(", ");
47924862 need_comma = true;
4793 try f.writeCValue(writer, resolved_arg, .FunctionArgument);
4863 try f.writeCValue(w, resolved_arg, .FunctionArgument);
47944864 try f.freeCValue(inst, resolved_arg);
47954865 }
4796 try writer.writeAll(");\n");
4866 try w.writeAll(");");
4867 switch (modifier) {
4868 .always_tail => try w.writeByte('\n'),
4869 else => try f.object.newline(),
4870 }
47974871
47984872 const result = result: {
47994873 if (result_local == .none or !lowersToArray(ret_ty, pt))
48004874 break :result result_local;
48014875
48024876 const array_local = try f.allocLocal(inst, ret_ty);
4803 try writer.writeAll("memcpy(");
4804 try f.writeCValue(writer, array_local, .FunctionArgument);
4805 try writer.writeAll(", ");
4806 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
4807 try writer.writeAll(", sizeof(");
4808 try f.renderType(writer, ret_ty);
4809 try writer.writeAll("));\n");
4877 try w.writeAll("memcpy(");
4878 try f.writeCValue(w, array_local, .FunctionArgument);
4879 try w.writeAll(", ");
4880 try f.writeCValueMember(w, result_local, .{ .identifier = "array" });
4881 try w.writeAll(", sizeof(");
4882 try f.renderType(w, ret_ty);
4883 try w.writeAll("));");
4884 try f.object.newline();
48104885 try freeLocal(f, inst, result_local.new_local, null);
48114886 break :result array_local;
48124887 };
......@@ -4816,7 +4891,7 @@ fn airCall(
48164891
48174892fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
48184893 const dbg_stmt = f.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
4819 const writer = f.object.writer();
4894 const w = &f.object.code.writer;
48204895 // TODO re-evaluate whether to emit these or not. If we naively emit
48214896 // these directives, the output file will report bogus line numbers because
48224897 // every newline after the #line directive adds one to the line.
......@@ -4824,13 +4899,16 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
48244899 // If we wanted to go this route, we would need to go all the way and not output
48254900 // newlines until the next dbg_stmt occurs.
48264901 // Perhaps an additional compilation option is in order?
4827 //try writer.print("#line {d}\n", .{dbg_stmt.line + 1});
4828 try writer.print("/* file:{d}:{d} */\n", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
4902 //try w.print("#line {d}", .{dbg_stmt.line + 1});
4903 //try f.object.newline();
4904 try w.print("/* file:{d}:{d} */", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
4905 try f.object.newline();
48294906 return .none;
48304907}
48314908
48324909fn airDbgEmptyStmt(f: *Function, _: Air.Inst.Index) !CValue {
4833 try f.object.writer().writeAll("(void)0;\n");
4910 try f.object.code.writer.writeAll("(void)0;");
4911 try f.object.newline();
48344912 return .none;
48354913}
48364914
......@@ -4841,8 +4919,9 @@ fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
48414919 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
48424920 const extra = f.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
48434921 const owner_nav = ip.getNav(zcu.funcInfo(extra.data.func).owner_nav);
4844 const writer = f.object.writer();
4845 try writer.print("/* inline:{} */\n", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
4922 const w = &f.object.code.writer;
4923 try w.print("/* inline:{f} */", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
4924 try f.object.newline();
48464925 return lowerBlock(f, inst, @ptrCast(f.air.extra.items[extra.end..][0..extra.data.body_len]));
48474926}
48484927
......@@ -4856,8 +4935,9 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
48564935 if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand);
48574936
48584937 try reap(f, inst, &.{pl_op.operand});
4859 const writer = f.object.writer();
4860 try writer.print("/* {s}:{s} */\n", .{ @tagName(tag), name.toSlice(f.air) });
4938 const w = &f.object.code.writer;
4939 try w.print("/* {s}:{s} */", .{ @tagName(tag), name.toSlice(f.air) });
4940 try f.object.newline();
48614941 return .none;
48624942}
48634943
......@@ -4874,7 +4954,7 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)
48744954
48754955 const block_id = f.next_block_index;
48764956 f.next_block_index += 1;
4877 const writer = f.object.writer();
4957 const w = &f.object.code.writer;
48784958
48794959 const inst_ty = f.typeOfIndex(inst);
48804960 const result = if (inst_ty.hasRuntimeBitsIgnoreComptime(zcu) and !f.liveness.isUnused(inst))
......@@ -4896,8 +4976,6 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)
48964976 try die(f, inst, death.toRef());
48974977 }
48984978
4899 try f.object.indent_writer.insertNewline();
4900
49014979 // noreturn blocks have no `br` instructions reaching them, so we don't want a label
49024980 if (f.object.dg.is_naked_fn) {
49034981 if (f.object.dg.expected_block) |expected_block| {
......@@ -4907,7 +4985,8 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)
49074985 }
49084986 } else if (!f.typeOfIndex(inst).isNoReturn(zcu)) {
49094987 // label must be followed by an expression, include an empty one.
4910 try writer.print("zig_block_{d}:;\n", .{block_id});
4988 try w.print("\nzig_block_{d}:;", .{block_id});
4989 try f.object.newline();
49114990 }
49124991
49134992 return result;
......@@ -4944,31 +5023,31 @@ fn lowerTry(
49445023 const err_union = try f.resolveInst(operand);
49455024 const inst_ty = f.typeOfIndex(inst);
49465025 const liveness_condbr = f.liveness.getCondBr(inst);
4947 const writer = f.object.writer();
5026 const w = &f.object.code.writer;
49485027 const payload_ty = err_union_ty.errorUnionPayload(zcu);
49495028 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(zcu);
49505029
49515030 if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
4952 try writer.writeAll("if (");
5031 try w.writeAll("if (");
49535032 if (!payload_has_bits) {
49545033 if (is_ptr)
4955 try f.writeCValueDeref(writer, err_union)
5034 try f.writeCValueDeref(w, err_union)
49565035 else
4957 try f.writeCValue(writer, err_union, .Other);
5036 try f.writeCValue(w, err_union, .Other);
49585037 } else {
49595038 // Reap the operand so that it can be reused inside genBody.
49605039 // Remember we must avoid calling reap() twice for the same operand
49615040 // in this function.
49625041 try reap(f, inst, &.{operand});
49635042 if (is_ptr)
4964 try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "error" })
5043 try f.writeCValueDerefMember(w, err_union, .{ .identifier = "error" })
49655044 else
4966 try f.writeCValueMember(writer, err_union, .{ .identifier = "error" });
5045 try f.writeCValueMember(w, err_union, .{ .identifier = "error" });
49675046 }
4968 try writer.writeAll(") ");
5047 try w.writeAll(") ");
49695048
49705049 try genBodyResolveState(f, inst, liveness_condbr.else_deaths, body, false);
4971 try f.object.indent_writer.insertNewline();
5050 try f.object.newline();
49725051 if (f.object.dg.expected_block) |_|
49735052 return f.fail("runtime code not allowed in naked function", .{});
49745053 }
......@@ -4991,14 +5070,14 @@ fn lowerTry(
49915070 if (f.liveness.isUnused(inst)) return .none;
49925071
49935072 const local = try f.allocLocal(inst, inst_ty);
4994 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
4995 try f.writeCValue(writer, local, .Other);
4996 try a.assign(f, writer);
5073 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
5074 try f.writeCValue(w, local, .Other);
5075 try a.assign(f, w);
49975076 if (is_ptr) {
4998 try writer.writeByte('&');
4999 try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "payload" });
5000 } else try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" });
5001 try a.end(f, writer);
5077 try w.writeByte('&');
5078 try f.writeCValueDerefMember(w, err_union, .{ .identifier = "payload" });
5079 } else try f.writeCValueMember(w, err_union, .{ .identifier = "payload" });
5080 try a.end(f, w);
50025081 return local;
50035082}
50045083
......@@ -5006,7 +5085,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !void {
50065085 const branch = f.air.instructions.items(.data)[@intFromEnum(inst)].br;
50075086 const block = f.blocks.get(branch.block_inst).?;
50085087 const result = block.result;
5009 const writer = f.object.writer();
5088 const w = &f.object.code.writer;
50105089
50115090 if (f.object.dg.is_naked_fn) {
50125091 if (result != .none) return f.fail("runtime code not allowed in naked function", .{});
......@@ -5020,27 +5099,26 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !void {
50205099 const operand = try f.resolveInst(branch.operand);
50215100 try reap(f, inst, &.{branch.operand});
50225101
5023 const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete));
5024 try f.writeCValue(writer, result, .Other);
5025 try a.assign(f, writer);
5026 try f.writeCValue(writer, operand, .Other);
5027 try a.end(f, writer);
5102 const a = try Assignment.start(f, w, try f.ctypeFromType(operand_ty, .complete));
5103 try f.writeCValue(w, result, .Other);
5104 try a.assign(f, w);
5105 try f.writeCValue(w, operand, .Other);
5106 try a.end(f, w);
50285107 }
50295108
5030 try writer.print("goto zig_block_{d};\n", .{block.block_id});
5109 try w.print("goto zig_block_{d};\n", .{block.block_id});
50315110}
50325111
50335112fn airRepeat(f: *Function, inst: Air.Inst.Index) !void {
50345113 const repeat = f.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
5035 const writer = f.object.writer();
5036 try writer.print("goto zig_loop_{d};\n", .{@intFromEnum(repeat.loop_inst)});
5114 try f.object.code.writer.print("goto zig_loop_{d};\n", .{@intFromEnum(repeat.loop_inst)});
50375115}
50385116
50395117fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
50405118 const pt = f.object.dg.pt;
50415119 const zcu = pt.zcu;
50425120 const br = f.air.instructions.items(.data)[@intFromEnum(inst)].br;
5043 const writer = f.object.writer();
5121 const w = &f.object.code.writer;
50445122
50455123 if (try f.air.value(br.operand, pt)) |cond_val| {
50465124 // Comptime-known dispatch. Iterate the cases to find the correct
......@@ -5062,18 +5140,19 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
50625140 }
50635141 }
50645142 } else switch_br.cases_len;
5065 try writer.print("goto zig_switch_{d}_dispatch_{d};\n", .{ @intFromEnum(br.block_inst), target_case_idx });
5143 try w.print("goto zig_switch_{d}_dispatch_{d};\n", .{ @intFromEnum(br.block_inst), target_case_idx });
50665144 return;
50675145 }
50685146
50695147 // Runtime-known dispatch. Set the switch condition, and branch back.
50705148 const cond = try f.resolveInst(br.operand);
50715149 const cond_local = f.loop_switch_conds.get(br.block_inst).?;
5072 try f.writeCValue(writer, .{ .local = cond_local }, .Other);
5073 try writer.writeAll(" = ");
5074 try f.writeCValue(writer, cond, .Other);
5075 try writer.writeAll(";\n");
5076 try writer.print("goto zig_switch_{d}_loop;", .{@intFromEnum(br.block_inst)});
5150 try f.writeCValue(w, .{ .local = cond_local }, .Other);
5151 try w.writeAll(" = ");
5152 try f.writeCValue(w, cond, .Other);
5153 try w.writeByte(';');
5154 try f.object.newline();
5155 try w.print("goto zig_switch_{d}_loop;\n", .{@intFromEnum(br.block_inst)});
50775156}
50785157
50795158fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -5093,7 +5172,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
50935172 const zcu = pt.zcu;
50945173 const target = &f.object.dg.mod.resolved_target.result;
50955174 const ctype_pool = &f.object.dg.ctype_pool;
5096 const writer = f.object.writer();
5175 const w = &f.object.code.writer;
50975176
50985177 if (operand_ty.isAbiInt(zcu) and dest_ty.isAbiInt(zcu)) {
50995178 const src_info = dest_ty.intInfo(zcu);
......@@ -5104,35 +5183,38 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
51045183
51055184 if (dest_ty.isPtrAtRuntime(zcu) or operand_ty.isPtrAtRuntime(zcu)) {
51065185 const local = try f.allocLocal(null, dest_ty);
5107 try f.writeCValue(writer, local, .Other);
5108 try writer.writeAll(" = (");
5109 try f.renderType(writer, dest_ty);
5110 try writer.writeByte(')');
5111 try f.writeCValue(writer, operand, .Other);
5112 try writer.writeAll(";\n");
5186 try f.writeCValue(w, local, .Other);
5187 try w.writeAll(" = (");
5188 try f.renderType(w, dest_ty);
5189 try w.writeByte(')');
5190 try f.writeCValue(w, operand, .Other);
5191 try w.writeByte(';');
5192 try f.object.newline();
51135193 return local;
51145194 }
51155195
51165196 const operand_lval = if (operand == .constant) blk: {
51175197 const operand_local = try f.allocLocal(null, operand_ty);
5118 try f.writeCValue(writer, operand_local, .Other);
5119 try writer.writeAll(" = ");
5120 try f.writeCValue(writer, operand, .Other);
5121 try writer.writeAll(";\n");
5198 try f.writeCValue(w, operand_local, .Other);
5199 try w.writeAll(" = ");
5200 try f.writeCValue(w, operand, .Other);
5201 try w.writeByte(';');
5202 try f.object.newline();
51225203 break :blk operand_local;
51235204 } else operand;
51245205
51255206 const local = try f.allocLocal(null, dest_ty);
5126 try writer.writeAll("memcpy(&");
5127 try f.writeCValue(writer, local, .Other);
5128 try writer.writeAll(", &");
5129 try f.writeCValue(writer, operand_lval, .Other);
5130 try writer.writeAll(", sizeof(");
5207 try w.writeAll("memcpy(&");
5208 try f.writeCValue(w, local, .Other);
5209 try w.writeAll(", &");
5210 try f.writeCValue(w, operand_lval, .Other);
5211 try w.writeAll(", sizeof(");
51315212 try f.renderType(
5132 writer,
5213 w,
51335214 if (dest_ty.abiSize(zcu) <= operand_ty.abiSize(zcu)) dest_ty else operand_ty,
51345215 );
5135 try writer.writeAll("));\n");
5216 try w.writeAll("));");
5217 try f.object.newline();
51365218
51375219 // Ensure padding bits have the expected value.
51385220 if (dest_ty.isAbiInt(zcu)) {
......@@ -5142,11 +5224,11 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
51425224 var wrap_ctype: ?CType = null;
51435225 var need_bitcasts = false;
51445226
5145 try f.writeCValue(writer, local, .Other);
5227 try f.writeCValue(w, local, .Other);
51465228 switch (dest_ctype.info(ctype_pool)) {
51475229 else => {},
51485230 .array => |array_info| {
5149 try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
5231 try w.print("[{d}]", .{switch (target.cpu.arch.endian()) {
51505232 .little => array_info.len - 1,
51515233 .big => 0,
51525234 }});
......@@ -5157,92 +5239,98 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
51575239 bits += 1;
51585240 },
51595241 }
5160 try writer.writeAll(" = ");
5242 try w.writeAll(" = ");
51615243 if (need_bitcasts) {
5162 try writer.writeAll("zig_bitCast_");
5163 try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?.toUnsigned());
5164 try writer.writeByte('(');
5244 try w.writeAll("zig_bitCast_");
5245 try f.object.dg.renderCTypeForBuiltinFnName(w, wrap_ctype.?.toUnsigned());
5246 try w.writeByte('(');
51655247 }
5166 try writer.writeAll("zig_wrap_");
5248 try w.writeAll("zig_wrap_");
51675249 const info_ty = try pt.intType(dest_info.signedness, bits);
51685250 if (wrap_ctype) |ctype|
5169 try f.object.dg.renderCTypeForBuiltinFnName(writer, ctype)
5251 try f.object.dg.renderCTypeForBuiltinFnName(w, ctype)
51705252 else
5171 try f.object.dg.renderTypeForBuiltinFnName(writer, info_ty);
5172 try writer.writeByte('(');
5253 try f.object.dg.renderTypeForBuiltinFnName(w, info_ty);
5254 try w.writeByte('(');
51735255 if (need_bitcasts) {
5174 try writer.writeAll("zig_bitCast_");
5175 try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?);
5176 try writer.writeByte('(');
5256 try w.writeAll("zig_bitCast_");
5257 try f.object.dg.renderCTypeForBuiltinFnName(w, wrap_ctype.?);
5258 try w.writeByte('(');
51775259 }
5178 try f.writeCValue(writer, local, .Other);
5260 try f.writeCValue(w, local, .Other);
51795261 switch (dest_ctype.info(ctype_pool)) {
51805262 else => {},
5181 .array => |array_info| try writer.print("[{d}]", .{
5263 .array => |array_info| try w.print("[{d}]", .{
51825264 switch (target.cpu.arch.endian()) {
51835265 .little => array_info.len - 1,
51845266 .big => 0,
51855267 },
51865268 }),
51875269 }
5188 if (need_bitcasts) try writer.writeByte(')');
5189 try f.object.dg.renderBuiltinInfo(writer, info_ty, .bits);
5190 if (need_bitcasts) try writer.writeByte(')');
5191 try writer.writeAll(");\n");
5270 if (need_bitcasts) try w.writeByte(')');
5271 try f.object.dg.renderBuiltinInfo(w, info_ty, .bits);
5272 if (need_bitcasts) try w.writeByte(')');
5273 try w.writeAll(");");
5274 try f.object.newline();
51925275 }
51935276
51945277 try f.freeCValue(null, operand_lval);
51955278 return local;
51965279}
51975280
5198fn airTrap(f: *Function, writer: anytype) !void {
5281fn airTrap(f: *Function, w: *Writer) !void {
51995282 // Not even allowed to call trap in a naked function.
52005283 if (f.object.dg.is_naked_fn) return;
5201 try writer.writeAll("zig_trap();\n");
5284 try w.writeAll("zig_trap();\n");
52025285}
52035286
5204fn airBreakpoint(writer: anytype) !CValue {
5205 try writer.writeAll("zig_breakpoint();\n");
5287fn airBreakpoint(f: *Function) !CValue {
5288 const w = &f.object.code.writer;
5289 try w.writeAll("zig_breakpoint();");
5290 try f.object.newline();
52065291 return .none;
52075292}
52085293
52095294fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
5210 const writer = f.object.writer();
5295 const w = &f.object.code.writer;
52115296 const local = try f.allocLocal(inst, .usize);
5212 try f.writeCValue(writer, local, .Other);
5213 try writer.writeAll(" = (");
5214 try f.renderType(writer, .usize);
5215 try writer.writeAll(")zig_return_address();\n");
5297 try f.writeCValue(w, local, .Other);
5298 try w.writeAll(" = (");
5299 try f.renderType(w, .usize);
5300 try w.writeAll(")zig_return_address();");
5301 try f.object.newline();
52165302 return local;
52175303}
52185304
52195305fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
5220 const writer = f.object.writer();
5306 const w = &f.object.code.writer;
52215307 const local = try f.allocLocal(inst, .usize);
5222 try f.writeCValue(writer, local, .Other);
5223 try writer.writeAll(" = (");
5224 try f.renderType(writer, .usize);
5225 try writer.writeAll(")zig_frame_address();\n");
5308 try f.writeCValue(w, local, .Other);
5309 try w.writeAll(" = (");
5310 try f.renderType(w, .usize);
5311 try w.writeAll(")zig_frame_address();");
5312 try f.object.newline();
52265313 return local;
52275314}
52285315
5229fn airUnreach(f: *Function) !void {
5316fn airUnreach(o: *Object) !void {
52305317 // Not even allowed to call unreachable in a naked function.
5231 if (f.object.dg.is_naked_fn) return;
5232 try f.object.writer().writeAll("zig_unreachable();\n");
5318 if (o.dg.is_naked_fn) return;
5319 try o.code.writer.writeAll("zig_unreachable();\n");
52335320}
52345321
52355322fn airLoop(f: *Function, inst: Air.Inst.Index) !void {
52365323 const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
52375324 const loop = f.air.extraData(Air.Block, ty_pl.payload);
52385325 const body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[loop.end..][0..loop.data.body_len]);
5239 const writer = f.object.writer();
5326 const w = &f.object.code.writer;
52405327
52415328 // `repeat` instructions matching this loop will branch to
52425329 // this label. Since we need a label for arbitrary `repeat`
52435330 // anyway, there's actually no need to use a "real" looping
52445331 // construct at all!
5245 try writer.print("zig_loop_{d}:\n", .{@intFromEnum(inst)});
5332 try w.print("zig_loop_{d}:", .{@intFromEnum(inst)});
5333 try f.object.newline();
52465334 try genBodyInner(f, body); // no need to restore state, we're noreturn
52475335}
52485336
......@@ -5254,14 +5342,14 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !void {
52545342 const then_body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[extra.end..][0..extra.data.then_body_len]);
52555343 const else_body: []const Air.Inst.Index = @ptrCast(f.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
52565344 const liveness_condbr = f.liveness.getCondBr(inst);
5257 const writer = f.object.writer();
5345 const w = &f.object.code.writer;
52585346
5259 try writer.writeAll("if (");
5260 try f.writeCValue(writer, cond, .Other);
5261 try writer.writeAll(") ");
5347 try w.writeAll("if (");
5348 try f.writeCValue(w, cond, .Other);
5349 try w.writeAll(") ");
52625350
52635351 try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false);
5264 try writer.writeByte('\n');
5352 try f.object.newline();
52655353 if (else_body.len > 0) if (f.object.dg.expected_block) |_|
52665354 return f.fail("runtime code not allowed in naked function", .{});
52675355
......@@ -5287,7 +5375,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
52875375 const init_condition = try f.resolveInst(switch_br.operand);
52885376 try reap(f, inst, &.{switch_br.operand});
52895377 const condition_ty = f.typeOf(switch_br.operand);
5290 const writer = f.object.writer();
5378 const w = &f.object.code.writer;
52915379
52925380 // For dispatches, we will create a local alloc to contain the condition value.
52935381 // This may not result in optimal codegen for switch loops, but it minimizes the
......@@ -5295,7 +5383,8 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
52955383 const condition = if (is_dispatch_loop) cond: {
52965384 const new_local = try f.allocLocal(inst, condition_ty);
52975385 try f.copyCValue(try f.ctypeFromType(condition_ty, .complete), new_local, init_condition);
5298 try writer.print("zig_switch_{d}_loop:\n", .{@intFromEnum(inst)});
5386 try w.print("zig_switch_{d}_loop:", .{@intFromEnum(inst)});
5387 try f.object.newline();
52995388 try f.loop_switch_conds.put(gpa, inst, new_local.new_local);
53005389 break :cond new_local;
53015390 } else init_condition;
......@@ -5304,7 +5393,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
53045393 assert(f.loop_switch_conds.remove(inst));
53055394 };
53065395
5307 try writer.writeAll("switch (");
5396 try w.writeAll("switch (");
53085397
53095398 const lowered_condition_ty: Type = if (condition_ty.toIntern() == .bool_type)
53105399 .u1
......@@ -5313,13 +5402,13 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
53135402 else
53145403 condition_ty;
53155404 if (condition_ty.toIntern() != lowered_condition_ty.toIntern()) {
5316 try writer.writeByte('(');
5317 try f.renderType(writer, lowered_condition_ty);
5318 try writer.writeByte(')');
5405 try w.writeByte('(');
5406 try f.renderType(w, lowered_condition_ty);
5407 try w.writeByte(')');
53195408 }
5320 try f.writeCValue(writer, condition, .Other);
5321 try writer.writeAll(") {");
5322 f.object.indent_writer.pushIndent();
5409 try f.writeCValue(w, condition, .Other);
5410 try w.writeAll(") {");
5411 f.object.indent();
53235412
53245413 const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.cases_len + 1);
53255414 defer gpa.free(liveness.deaths);
......@@ -5332,35 +5421,37 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
53325421 continue;
53335422 }
53345423 for (case.items) |item| {
5335 try f.object.indent_writer.insertNewline();
5336 try writer.writeAll("case ");
5424 try f.object.newline();
5425 try w.writeAll("case ");
53375426 const item_value = try f.air.value(item, pt);
53385427 // If `item_value` is a pointer with a known integer address, print the address
53395428 // with no cast to avoid a warning.
53405429 write_val: {
53415430 if (condition_ty.isPtrAtRuntime(zcu)) {
53425431 if (item_value.?.getUnsignedInt(zcu)) |item_int| {
5343 try writer.print("{}", .{try f.fmtIntLiteral(try pt.intValue(lowered_condition_ty, item_int))});
5432 try w.print("{f}", .{try f.fmtIntLiteralDec(try pt.intValue(lowered_condition_ty, item_int))});
53445433 break :write_val;
53455434 }
53465435 }
53475436 if (condition_ty.isPtrAtRuntime(zcu)) {
5348 try writer.writeByte('(');
5349 try f.renderType(writer, .usize);
5350 try writer.writeByte(')');
5437 try w.writeByte('(');
5438 try f.renderType(w, .usize);
5439 try w.writeByte(')');
53515440 }
5352 try f.object.dg.renderValue(writer, (try f.air.value(item, pt)).?, .Other);
5441 try f.object.dg.renderValue(w, (try f.air.value(item, pt)).?, .Other);
53535442 }
5354 try writer.writeByte(':');
5443 try w.writeByte(':');
53555444 }
5356 try writer.writeAll(" {\n");
5357 f.object.indent_writer.pushIndent();
5445 try w.writeAll(" {");
5446 f.object.indent();
5447 try f.object.newline();
53585448 if (is_dispatch_loop) {
5359 try writer.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });
5449 try w.print("zig_switch_{d}_dispatch_{d}:;", .{ @intFromEnum(inst), case.idx });
5450 try f.object.newline();
53605451 }
53615452 try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);
5362 f.object.indent_writer.popIndent();
5363 try writer.writeByte('}');
5453 try f.object.outdent();
5454 try w.writeByte('}');
53645455 if (f.object.dg.expected_block) |_|
53655456 return f.fail("runtime code not allowed in naked function", .{});
53665457
......@@ -5368,9 +5459,9 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
53685459 }
53695460
53705461 const else_body = it.elseBody();
5371 try f.object.indent_writer.insertNewline();
5462 try f.object.newline();
53725463
5373 try writer.writeAll("default: ");
5464 try w.writeAll("default: ");
53745465 if (any_range_cases) {
53755466 // We will iterate the cases again to handle those with ranges, and generate
53765467 // code using conditions rather than switch cases for such cases.
......@@ -5378,40 +5469,41 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
53785469 while (it.next()) |case| {
53795470 if (case.ranges.len == 0) continue; // handled above
53805471
5381 try writer.writeAll("if (");
5472 try w.writeAll("if (");
53825473 for (case.items, 0..) |item, item_i| {
5383 if (item_i != 0) try writer.writeAll(" || ");
5384 try f.writeCValue(writer, condition, .Other);
5385 try writer.writeAll(" == ");
5386 try f.object.dg.renderValue(writer, (try f.air.value(item, pt)).?, .Other);
5474 if (item_i != 0) try w.writeAll(" || ");
5475 try f.writeCValue(w, condition, .Other);
5476 try w.writeAll(" == ");
5477 try f.object.dg.renderValue(w, (try f.air.value(item, pt)).?, .Other);
53875478 }
53885479 for (case.ranges, 0..) |range, range_i| {
5389 if (case.items.len != 0 or range_i != 0) try writer.writeAll(" || ");
5480 if (case.items.len != 0 or range_i != 0) try w.writeAll(" || ");
53905481 // "(x >= lower && x <= upper)"
5391 try writer.writeByte('(');
5392 try f.writeCValue(writer, condition, .Other);
5393 try writer.writeAll(" >= ");
5394 try f.object.dg.renderValue(writer, (try f.air.value(range[0], pt)).?, .Other);
5395 try writer.writeAll(" && ");
5396 try f.writeCValue(writer, condition, .Other);
5397 try writer.writeAll(" <= ");
5398 try f.object.dg.renderValue(writer, (try f.air.value(range[1], pt)).?, .Other);
5399 try writer.writeByte(')');
5482 try w.writeByte('(');
5483 try f.writeCValue(w, condition, .Other);
5484 try w.writeAll(" >= ");
5485 try f.object.dg.renderValue(w, (try f.air.value(range[0], pt)).?, .Other);
5486 try w.writeAll(" && ");
5487 try f.writeCValue(w, condition, .Other);
5488 try w.writeAll(" <= ");
5489 try f.object.dg.renderValue(w, (try f.air.value(range[1], pt)).?, .Other);
5490 try w.writeByte(')');
54005491 }
5401 try writer.writeAll(") {\n");
5402 f.object.indent_writer.pushIndent();
5492 try w.writeAll(") {");
5493 f.object.indent();
5494 try f.object.newline();
54035495 if (is_dispatch_loop) {
5404 try writer.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });
5496 try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });
54055497 }
54065498 try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);
5407 f.object.indent_writer.popIndent();
5408 try writer.writeByte('}');
5499 try f.object.outdent();
5500 try w.writeByte('}');
54095501 if (f.object.dg.expected_block) |_|
54105502 return f.fail("runtime code not allowed in naked function", .{});
54115503 }
54125504 }
54135505 if (is_dispatch_loop) {
5414 try writer.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), switch_br.cases_len });
5506 try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), switch_br.cases_len });
54155507 }
54165508 if (else_body.len > 0) {
54175509 // Note that this must be the last case, so we do not need to use `genBodyResolveState` since
......@@ -5422,13 +5514,10 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
54225514 try genBody(f, else_body);
54235515 if (f.object.dg.expected_block) |_|
54245516 return f.fail("runtime code not allowed in naked function", .{});
5425 } else {
5426 try writer.writeAll("zig_unreachable();");
5427 }
5428 try f.object.indent_writer.insertNewline();
5429
5430 f.object.indent_writer.popIndent();
5431 try writer.writeAll("}\n");
5517 } else try airUnreach(&f.object);
5518 try f.object.newline();
5519 try f.object.outdent();
5520 try w.writeAll("}\n");
54325521}
54335522
54345523fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {
......@@ -5466,7 +5555,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
54665555 extra_i += inputs.len;
54675556
54685557 const result = result: {
5469 const writer = f.object.writer();
5558 const w = &f.object.code.writer;
54705559 const inst_ty = f.typeOfIndex(inst);
54715560 const inst_local = if (inst_ty.hasRuntimeBitsIgnoreComptime(zcu)) local: {
54725561 const inst_local = try f.allocLocalValue(.{
......@@ -5474,10 +5563,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
54745563 .alignas = CType.AlignAs.fromAbiAlignment(inst_ty.abiAlignment(zcu)),
54755564 });
54765565 if (f.wantSafety()) {
5477 try f.writeCValue(writer, inst_local, .Other);
5478 try writer.writeAll(" = ");
5479 try f.writeCValue(writer, .{ .undef = inst_ty }, .Other);
5480 try writer.writeAll(";\n");
5566 try f.writeCValue(w, inst_local, .Other);
5567 try w.writeAll(" = ");
5568 try f.writeCValue(w, .{ .undef = inst_ty }, .Other);
5569 try w.writeByte(';');
5570 try f.object.newline();
54815571 }
54825572 break :local inst_local;
54835573 } else .none;
......@@ -5501,21 +5591,22 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
55015591 const is_reg = constraint[1] == '{';
55025592 if (is_reg) {
55035593 const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(zcu);
5504 try writer.writeAll("register ");
5594 try w.writeAll("register ");
55055595 const output_local = try f.allocLocalValue(.{
55065596 .ctype = try f.ctypeFromType(output_ty, .complete),
55075597 .alignas = CType.AlignAs.fromAbiAlignment(output_ty.abiAlignment(zcu)),
55085598 });
55095599 try f.allocs.put(gpa, output_local.new_local, false);
5510 try f.object.dg.renderTypeAndName(writer, output_ty, output_local, .{}, .none, .complete);
5511 try writer.writeAll(" __asm(\"");
5512 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
5513 try writer.writeAll("\")");
5600 try f.object.dg.renderTypeAndName(w, output_ty, output_local, .{}, .none, .complete);
5601 try w.writeAll(" __asm(\"");
5602 try w.writeAll(constraint["={".len .. constraint.len - "}".len]);
5603 try w.writeAll("\")");
55145604 if (f.wantSafety()) {
5515 try writer.writeAll(" = ");
5516 try f.writeCValue(writer, .{ .undef = output_ty }, .Other);
5605 try w.writeAll(" = ");
5606 try f.writeCValue(w, .{ .undef = output_ty }, .Other);
55175607 }
5518 try writer.writeAll(";\n");
5608 try w.writeByte(';');
5609 try f.object.newline();
55195610 }
55205611 }
55215612 for (inputs) |input| {
......@@ -5536,21 +5627,22 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
55365627 const input_val = try f.resolveInst(input);
55375628 if (asmInputNeedsLocal(f, constraint, input_val)) {
55385629 const input_ty = f.typeOf(input);
5539 if (is_reg) try writer.writeAll("register ");
5630 if (is_reg) try w.writeAll("register ");
55405631 const input_local = try f.allocLocalValue(.{
55415632 .ctype = try f.ctypeFromType(input_ty, .complete),
55425633 .alignas = CType.AlignAs.fromAbiAlignment(input_ty.abiAlignment(zcu)),
55435634 });
55445635 try f.allocs.put(gpa, input_local.new_local, false);
5545 try f.object.dg.renderTypeAndName(writer, input_ty, input_local, Const, .none, .complete);
5636 try f.object.dg.renderTypeAndName(w, input_ty, input_local, Const, .none, .complete);
55465637 if (is_reg) {
5547 try writer.writeAll(" __asm(\"");
5548 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
5549 try writer.writeAll("\")");
5638 try w.writeAll(" __asm(\"");
5639 try w.writeAll(constraint["{".len .. constraint.len - "}".len]);
5640 try w.writeAll("\")");
55505641 }
5551 try writer.writeAll(" = ");
5552 try f.writeCValue(writer, input_val, .Other);
5553 try writer.writeAll(";\n");
5642 try w.writeAll(" = ");
5643 try f.writeCValue(w, input_val, .Other);
5644 try w.writeByte(';');
5645 try f.object.newline();
55545646 }
55555647 }
55565648 for (0..clobbers_len) |_| {
......@@ -5610,14 +5702,14 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
56105702 }
56115703 }
56125704
5613 try writer.writeAll("__asm");
5614 if (is_volatile) try writer.writeAll(" volatile");
5615 try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i], null)});
5705 try w.writeAll("__asm");
5706 if (is_volatile) try w.writeAll(" volatile");
5707 try w.print("({f}", .{fmtStringLiteral(fixed_asm_source[0..dst_i], null)});
56165708 }
56175709
56185710 extra_i = constraints_extra_begin;
56195711 var locals_index = locals_begin;
5620 try writer.writeByte(':');
5712 try w.writeByte(':');
56215713 for (outputs, 0..) |output, index| {
56225714 const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]);
56235715 const constraint = mem.sliceTo(extra_bytes, 0);
......@@ -5626,22 +5718,22 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
56265718 // for the string, we still use the next u32 for the null terminator.
56275719 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
56285720
5629 if (index > 0) try writer.writeByte(',');
5630 try writer.writeByte(' ');
5631 if (!mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
5721 if (index > 0) try w.writeByte(',');
5722 try w.writeByte(' ');
5723 if (!mem.eql(u8, name, "_")) try w.print("[{s}]", .{name});
56325724 const is_reg = constraint[1] == '{';
5633 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)});
5725 try w.print("{f}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)});
56345726 if (is_reg) {
5635 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
5727 try f.writeCValue(w, .{ .local = locals_index }, .Other);
56365728 locals_index += 1;
56375729 } else if (output == .none) {
5638 try f.writeCValue(writer, inst_local, .FunctionArgument);
5730 try f.writeCValue(w, inst_local, .FunctionArgument);
56395731 } else {
5640 try f.writeCValueDeref(writer, try f.resolveInst(output));
5732 try f.writeCValueDeref(w, try f.resolveInst(output));
56415733 }
5642 try writer.writeByte(')');
5734 try w.writeByte(')');
56435735 }
5644 try writer.writeByte(':');
5736 try w.writeByte(':');
56455737 for (inputs, 0..) |input, index| {
56465738 const extra_bytes = mem.sliceAsBytes(f.air.extra.items[extra_i..]);
56475739 const constraint = mem.sliceTo(extra_bytes, 0);
......@@ -5650,21 +5742,21 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
56505742 // for the string, we still use the next u32 for the null terminator.
56515743 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
56525744
5653 if (index > 0) try writer.writeByte(',');
5654 try writer.writeByte(' ');
5655 if (!mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
5745 if (index > 0) try w.writeByte(',');
5746 try w.writeByte(' ');
5747 if (!mem.eql(u8, name, "_")) try w.print("[{s}]", .{name});
56565748
56575749 const is_reg = constraint[0] == '{';
56585750 const input_val = try f.resolveInst(input);
5659 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)});
5660 try f.writeCValue(writer, if (asmInputNeedsLocal(f, constraint, input_val)) local: {
5751 try w.print("{f}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)});
5752 try f.writeCValue(w, if (asmInputNeedsLocal(f, constraint, input_val)) local: {
56615753 const input_local_idx = locals_index;
56625754 locals_index += 1;
56635755 break :local .{ .local = input_local_idx };
56645756 } else input_val, .Other);
5665 try writer.writeByte(')');
5757 try w.writeByte(')');
56665758 }
5667 try writer.writeByte(':');
5759 try w.writeByte(':');
56685760 for (0..clobbers_len) |clobber_i| {
56695761 const clobber = mem.sliceTo(mem.sliceAsBytes(f.air.extra.items[extra_i..]), 0);
56705762 // This equation accounts for the fact that even if we have exactly 4 bytes
......@@ -5673,10 +5765,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
56735765
56745766 if (clobber.len == 0) continue;
56755767
5676 if (clobber_i > 0) try writer.writeByte(',');
5677 try writer.print(" {s}", .{fmtStringLiteral(clobber, null)});
5768 if (clobber_i > 0) try w.writeByte(',');
5769 try w.print(" {f}", .{fmtStringLiteral(clobber, null)});
56785770 }
5679 try writer.writeAll(");\n");
5771 try w.writeAll(");");
5772 try f.object.newline();
56805773
56815774 extra_i = constraints_extra_begin;
56825775 locals_index = locals_begin;
......@@ -5690,14 +5783,15 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
56905783
56915784 const is_reg = constraint[1] == '{';
56925785 if (is_reg) {
5693 try f.writeCValueDeref(writer, if (output == .none)
5786 try f.writeCValueDeref(w, if (output == .none)
56945787 .{ .local_ref = inst_local.new_local }
56955788 else
56965789 try f.resolveInst(output));
5697 try writer.writeAll(" = ");
5698 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
5790 try w.writeAll(" = ");
5791 try f.writeCValue(w, .{ .local = locals_index }, .Other);
56995792 locals_index += 1;
5700 try writer.writeAll(";\n");
5793 try w.writeByte(';');
5794 try f.object.newline();
57015795 }
57025796 }
57035797
......@@ -5727,14 +5821,14 @@ fn airIsNull(
57275821 const ctype_pool = &f.object.dg.ctype_pool;
57285822 const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
57295823
5730 const writer = f.object.writer();
5824 const w = &f.object.code.writer;
57315825 const operand = try f.resolveInst(un_op);
57325826 try reap(f, inst, &.{un_op});
57335827
57345828 const local = try f.allocLocal(inst, .bool);
5735 const a = try Assignment.start(f, writer, .bool);
5736 try f.writeCValue(writer, local, .Other);
5737 try a.assign(f, writer);
5829 const a = try Assignment.start(f, w, .bool);
5830 try f.writeCValue(w, local, .Other);
5831 try a.assign(f, w);
57385832
57395833 const operand_ty = f.typeOf(un_op);
57405834 const optional_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
......@@ -5742,9 +5836,9 @@ fn airIsNull(
57425836 const rhs = switch (opt_ctype.info(ctype_pool)) {
57435837 .basic, .pointer => rhs: {
57445838 if (is_ptr)
5745 try f.writeCValueDeref(writer, operand)
5839 try f.writeCValueDeref(w, operand)
57465840 else
5747 try f.writeCValue(writer, operand, .Other);
5841 try f.writeCValue(w, operand, .Other);
57485842 break :rhs if (opt_ctype.isBool())
57495843 "true"
57505844 else if (opt_ctype.isInteger())
......@@ -5756,24 +5850,24 @@ fn airIsNull(
57565850 .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
57575851 .is_null, .payload => rhs: {
57585852 if (is_ptr)
5759 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" })
5853 try f.writeCValueDerefMember(w, operand, .{ .identifier = "is_null" })
57605854 else
5761 try f.writeCValueMember(writer, operand, .{ .identifier = "is_null" });
5855 try f.writeCValueMember(w, operand, .{ .identifier = "is_null" });
57625856 break :rhs "true";
57635857 },
57645858 .ptr, .len => rhs: {
57655859 if (is_ptr)
5766 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "ptr" })
5860 try f.writeCValueDerefMember(w, operand, .{ .identifier = "ptr" })
57675861 else
5768 try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" });
5862 try f.writeCValueMember(w, operand, .{ .identifier = "ptr" });
57695863 break :rhs "NULL";
57705864 },
57715865 else => unreachable,
57725866 },
57735867 };
5774 try writer.writeAll(compareOperatorC(operator));
5775 try writer.writeAll(rhs);
5776 try a.end(f, writer);
5868 try w.writeAll(compareOperatorC(operator));
5869 try w.writeAll(rhs);
5870 try a.end(f, w);
57775871 return local;
57785872}
57795873
......@@ -5795,16 +5889,16 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue
57955889 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
57965890 .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
57975891 .is_null, .payload => {
5798 const writer = f.object.writer();
5892 const w = &f.object.code.writer;
57995893 const local = try f.allocLocal(inst, inst_ty);
5800 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
5801 try f.writeCValue(writer, local, .Other);
5802 try a.assign(f, writer);
5894 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
5895 try f.writeCValue(w, local, .Other);
5896 try a.assign(f, w);
58035897 if (is_ptr) {
5804 try writer.writeByte('&');
5805 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
5806 } else try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
5807 try a.end(f, writer);
5898 try w.writeByte('&');
5899 try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
5900 } else try f.writeCValueMember(w, operand, .{ .identifier = "payload" });
5901 try a.end(f, w);
58085902 return local;
58095903 },
58105904 .ptr, .len => return f.moveCValue(inst, inst_ty, operand),
......@@ -5817,7 +5911,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
58175911 const pt = f.object.dg.pt;
58185912 const zcu = pt.zcu;
58195913 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5820 const writer = f.object.writer();
5914 const w = &f.object.code.writer;
58215915 const operand = try f.resolveInst(ty_op.operand);
58225916 try reap(f, inst, &.{ty_op.operand});
58235917 const operand_ty = f.typeOf(ty_op.operand);
......@@ -5826,40 +5920,40 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
58265920 const opt_ctype = try f.ctypeFromType(operand_ty.childType(zcu), .complete);
58275921 switch (opt_ctype.info(&f.object.dg.ctype_pool)) {
58285922 .basic => {
5829 const a = try Assignment.start(f, writer, opt_ctype);
5830 try f.writeCValueDeref(writer, operand);
5831 try a.assign(f, writer);
5832 try f.object.dg.renderValue(writer, Value.false, .Other);
5833 try a.end(f, writer);
5923 const a = try Assignment.start(f, w, opt_ctype);
5924 try f.writeCValueDeref(w, operand);
5925 try a.assign(f, w);
5926 try f.object.dg.renderValue(w, Value.false, .Other);
5927 try a.end(f, w);
58345928 return .none;
58355929 },
58365930 .pointer => {
58375931 if (f.liveness.isUnused(inst)) return .none;
58385932 const local = try f.allocLocal(inst, inst_ty);
5839 const a = try Assignment.start(f, writer, opt_ctype);
5840 try f.writeCValue(writer, local, .Other);
5841 try a.assign(f, writer);
5842 try f.writeCValue(writer, operand, .Other);
5843 try a.end(f, writer);
5933 const a = try Assignment.start(f, w, opt_ctype);
5934 try f.writeCValue(w, local, .Other);
5935 try a.assign(f, w);
5936 try f.writeCValue(w, operand, .Other);
5937 try a.end(f, w);
58445938 return local;
58455939 },
58465940 .aligned, .array, .vector, .fwd_decl, .function => unreachable,
58475941 .aggregate => {
58485942 {
5849 const a = try Assignment.start(f, writer, opt_ctype);
5850 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "is_null" });
5851 try a.assign(f, writer);
5852 try f.object.dg.renderValue(writer, Value.false, .Other);
5853 try a.end(f, writer);
5943 const a = try Assignment.start(f, w, opt_ctype);
5944 try f.writeCValueDerefMember(w, operand, .{ .identifier = "is_null" });
5945 try a.assign(f, w);
5946 try f.object.dg.renderValue(w, Value.false, .Other);
5947 try a.end(f, w);
58545948 }
58555949 if (f.liveness.isUnused(inst)) return .none;
58565950 const local = try f.allocLocal(inst, inst_ty);
5857 const a = try Assignment.start(f, writer, opt_ctype);
5858 try f.writeCValue(writer, local, .Other);
5859 try a.assign(f, writer);
5860 try writer.writeByte('&');
5861 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
5862 try a.end(f, writer);
5951 const a = try Assignment.start(f, w, opt_ctype);
5952 try f.writeCValue(w, local, .Other);
5953 try a.assign(f, w);
5954 try w.writeByte('&');
5955 try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
5956 try a.end(f, w);
58635957 return local;
58645958 },
58655959 }
......@@ -5967,42 +6061,43 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
59676061 const field_ptr_val = try f.resolveInst(extra.field_ptr);
59686062 try reap(f, inst, &.{extra.field_ptr});
59696063
5970 const writer = f.object.writer();
6064 const w = &f.object.code.writer;
59716065 const local = try f.allocLocal(inst, container_ptr_ty);
5972 try f.writeCValue(writer, local, .Other);
5973 try writer.writeAll(" = (");
5974 try f.renderType(writer, container_ptr_ty);
5975 try writer.writeByte(')');
6066 try f.writeCValue(w, local, .Other);
6067 try w.writeAll(" = (");
6068 try f.renderType(w, container_ptr_ty);
6069 try w.writeByte(')');
59766070
59776071 switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) {
5978 .begin => try f.writeCValue(writer, field_ptr_val, .Other),
6072 .begin => try f.writeCValue(w, field_ptr_val, .Other),
59796073 .field => |field| {
59806074 const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
59816075
5982 try writer.writeAll("((");
5983 try f.renderType(writer, u8_ptr_ty);
5984 try writer.writeByte(')');
5985 try f.writeCValue(writer, field_ptr_val, .Other);
5986 try writer.writeAll(" - offsetof(");
5987 try f.renderType(writer, container_ty);
5988 try writer.writeAll(", ");
5989 try f.writeCValue(writer, field, .Other);
5990 try writer.writeAll("))");
6076 try w.writeAll("((");
6077 try f.renderType(w, u8_ptr_ty);
6078 try w.writeByte(')');
6079 try f.writeCValue(w, field_ptr_val, .Other);
6080 try w.writeAll(" - offsetof(");
6081 try f.renderType(w, container_ty);
6082 try w.writeAll(", ");
6083 try f.writeCValue(w, field, .Other);
6084 try w.writeAll("))");
59916085 },
59926086 .byte_offset => |byte_offset| {
59936087 const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
59946088
5995 try writer.writeAll("((");
5996 try f.renderType(writer, u8_ptr_ty);
5997 try writer.writeByte(')');
5998 try f.writeCValue(writer, field_ptr_val, .Other);
5999 try writer.print(" - {})", .{
6000 try f.fmtIntLiteral(try pt.intValue(.usize, byte_offset)),
6089 try w.writeAll("((");
6090 try f.renderType(w, u8_ptr_ty);
6091 try w.writeByte(')');
6092 try f.writeCValue(w, field_ptr_val, .Other);
6093 try w.print(" - {f})", .{
6094 try f.fmtIntLiteralDec(try pt.intValue(.usize, byte_offset)),
60016095 });
60026096 },
60036097 }
60046098
6005 try writer.writeAll(";\n");
6099 try w.writeByte(';');
6100 try f.object.newline();
60066101 return local;
60076102}
60086103
......@@ -6021,33 +6116,34 @@ fn fieldPtr(
60216116 // Ensure complete type definition is visible before accessing fields.
60226117 _ = try f.ctypeFromType(container_ty, .complete);
60236118
6024 const writer = f.object.writer();
6119 const w = &f.object.code.writer;
60256120 const local = try f.allocLocal(inst, field_ptr_ty);
6026 try f.writeCValue(writer, local, .Other);
6027 try writer.writeAll(" = (");
6028 try f.renderType(writer, field_ptr_ty);
6029 try writer.writeByte(')');
6121 try f.writeCValue(w, local, .Other);
6122 try w.writeAll(" = (");
6123 try f.renderType(w, field_ptr_ty);
6124 try w.writeByte(')');
60306125
60316126 switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) {
6032 .begin => try f.writeCValue(writer, container_ptr_val, .Other),
6127 .begin => try f.writeCValue(w, container_ptr_val, .Other),
60336128 .field => |field| {
6034 try writer.writeByte('&');
6035 try f.writeCValueDerefMember(writer, container_ptr_val, field);
6129 try w.writeByte('&');
6130 try f.writeCValueDerefMember(w, container_ptr_val, field);
60366131 },
60376132 .byte_offset => |byte_offset| {
60386133 const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
60396134
6040 try writer.writeAll("((");
6041 try f.renderType(writer, u8_ptr_ty);
6042 try writer.writeByte(')');
6043 try f.writeCValue(writer, container_ptr_val, .Other);
6044 try writer.print(" + {})", .{
6045 try f.fmtIntLiteral(try pt.intValue(.usize, byte_offset)),
6135 try w.writeAll("((");
6136 try f.renderType(w, u8_ptr_ty);
6137 try w.writeByte(')');
6138 try f.writeCValue(w, container_ptr_val, .Other);
6139 try w.print(" + {f})", .{
6140 try f.fmtIntLiteralDec(try pt.intValue(.usize, byte_offset)),
60466141 });
60476142 },
60486143 }
60496144
6050 try writer.writeAll(";\n");
6145 try w.writeByte(';');
6146 try f.object.newline();
60516147 return local;
60526148}
60536149
......@@ -6067,7 +6163,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
60676163 const struct_byval = try f.resolveInst(extra.struct_operand);
60686164 try reap(f, inst, &.{extra.struct_operand});
60696165 const struct_ty = f.typeOf(extra.struct_operand);
6070 const writer = f.object.writer();
6166 const w = &f.object.code.writer;
60716167
60726168 // Ensure complete type definition is visible before accessing fields.
60736169 _ = try f.ctypeFromType(struct_ty, .complete);
......@@ -6094,42 +6190,44 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
60946190 const field_int_ty = try pt.intType(field_int_signedness, @as(u16, @intCast(inst_ty.bitSize(zcu))));
60956191
60966192 const temp_local = try f.allocLocal(inst, field_int_ty);
6097 try f.writeCValue(writer, temp_local, .Other);
6098 try writer.writeAll(" = zig_wrap_");
6099 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
6100 try writer.writeAll("((");
6101 try f.renderType(writer, field_int_ty);
6102 try writer.writeByte(')');
6193 try f.writeCValue(w, temp_local, .Other);
6194 try w.writeAll(" = zig_wrap_");
6195 try f.object.dg.renderTypeForBuiltinFnName(w, field_int_ty);
6196 try w.writeAll("((");
6197 try f.renderType(w, field_int_ty);
6198 try w.writeByte(')');
61036199 const cant_cast = int_info.bits > 64;
61046200 if (cant_cast) {
61056201 if (field_int_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
6106 try writer.writeAll("zig_lo_");
6107 try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
6108 try writer.writeByte('(');
6202 try w.writeAll("zig_lo_");
6203 try f.object.dg.renderTypeForBuiltinFnName(w, struct_ty);
6204 try w.writeByte('(');
61096205 }
61106206 if (bit_offset > 0) {
6111 try writer.writeAll("zig_shr_");
6112 try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
6113 try writer.writeByte('(');
6207 try w.writeAll("zig_shr_");
6208 try f.object.dg.renderTypeForBuiltinFnName(w, struct_ty);
6209 try w.writeByte('(');
61146210 }
6115 try f.writeCValue(writer, struct_byval, .Other);
6116 if (bit_offset > 0) try writer.print(", {})", .{
6117 try f.fmtIntLiteral(try pt.intValue(bit_offset_ty, bit_offset)),
6211 try f.writeCValue(w, struct_byval, .Other);
6212 if (bit_offset > 0) try w.print(", {f})", .{
6213 try f.fmtIntLiteralDec(try pt.intValue(bit_offset_ty, bit_offset)),
61186214 });
6119 if (cant_cast) try writer.writeByte(')');
6120 try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits);
6121 try writer.writeAll(");\n");
6215 if (cant_cast) try w.writeByte(')');
6216 try f.object.dg.renderBuiltinInfo(w, field_int_ty, .bits);
6217 try w.writeAll(");");
6218 try f.object.newline();
61226219 if (inst_ty.eql(field_int_ty, zcu)) return temp_local;
61236220
61246221 const local = try f.allocLocal(inst, inst_ty);
61256222 if (local.new_local != temp_local.new_local) {
6126 try writer.writeAll("memcpy(");
6127 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
6128 try writer.writeAll(", ");
6129 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
6130 try writer.writeAll(", sizeof(");
6131 try f.renderType(writer, inst_ty);
6132 try writer.writeAll("));\n");
6223 try w.writeAll("memcpy(");
6224 try f.writeCValue(w, .{ .local_ref = local.new_local }, .FunctionArgument);
6225 try w.writeAll(", ");
6226 try f.writeCValue(w, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
6227 try w.writeAll(", sizeof(");
6228 try f.renderType(w, inst_ty);
6229 try w.writeAll("));");
6230 try f.object.newline();
61336231 }
61346232 try freeLocal(f, inst, temp_local.new_local, null);
61356233 return local;
......@@ -6150,10 +6248,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
61506248 .@"packed" => {
61516249 const operand_lval = if (struct_byval == .constant) blk: {
61526250 const operand_local = try f.allocLocal(inst, struct_ty);
6153 try f.writeCValue(writer, operand_local, .Other);
6154 try writer.writeAll(" = ");
6155 try f.writeCValue(writer, struct_byval, .Other);
6156 try writer.writeAll(";\n");
6251 try f.writeCValue(w, operand_local, .Other);
6252 try w.writeAll(" = ");
6253 try f.writeCValue(w, struct_byval, .Other);
6254 try w.writeByte(';');
6255 try f.object.newline();
61576256 break :blk operand_local;
61586257 } else struct_byval;
61596258 const local = try f.allocLocal(inst, inst_ty);
......@@ -6164,13 +6263,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
61646263 },
61656264 else => true,
61666265 }) {
6167 try writer.writeAll("memcpy(&");
6168 try f.writeCValue(writer, local, .Other);
6169 try writer.writeAll(", &");
6170 try f.writeCValue(writer, operand_lval, .Other);
6171 try writer.writeAll(", sizeof(");
6172 try f.renderType(writer, inst_ty);
6173 try writer.writeAll("));\n");
6266 try w.writeAll("memcpy(&");
6267 try f.writeCValue(w, local, .Other);
6268 try w.writeAll(", &");
6269 try f.writeCValue(w, operand_lval, .Other);
6270 try w.writeAll(", sizeof(");
6271 try f.renderType(w, inst_ty);
6272 try w.writeAll("));");
6273 try f.object.newline();
61746274 }
61756275 try f.freeCValue(inst, operand_lval);
61766276 return local;
......@@ -6181,11 +6281,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
61816281 };
61826282
61836283 const local = try f.allocLocal(inst, inst_ty);
6184 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
6185 try f.writeCValue(writer, local, .Other);
6186 try a.assign(f, writer);
6187 try f.writeCValueMember(writer, struct_byval, field_name);
6188 try a.end(f, writer);
6284 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
6285 try f.writeCValue(w, local, .Other);
6286 try a.assign(f, w);
6287 try f.writeCValueMember(w, struct_byval, field_name);
6288 try a.end(f, w);
61896289 return local;
61906290}
61916291
......@@ -6212,21 +6312,22 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
62126312 return local;
62136313 }
62146314
6215 const writer = f.object.writer();
6216 try f.writeCValue(writer, local, .Other);
6217 try writer.writeAll(" = ");
6315 const w = &f.object.code.writer;
6316 try f.writeCValue(w, local, .Other);
6317 try w.writeAll(" = ");
62186318
62196319 if (!payload_ty.hasRuntimeBits(zcu))
6220 try f.writeCValue(writer, operand, .Other)
6320 try f.writeCValue(w, operand, .Other)
62216321 else if (error_ty.errorSetIsEmpty(zcu))
6222 try writer.print("{}", .{
6223 try f.fmtIntLiteral(try pt.intValue(try pt.errorIntType(), 0)),
6322 try w.print("{f}", .{
6323 try f.fmtIntLiteralDec(try pt.intValue(try pt.errorIntType(), 0)),
62246324 })
62256325 else if (operand_is_ptr)
6226 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" })
6326 try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" })
62276327 else
6228 try f.writeCValueMember(writer, operand, .{ .identifier = "error" });
6229 try writer.writeAll(";\n");
6328 try f.writeCValueMember(w, operand, .{ .identifier = "error" });
6329 try w.writeByte(';');
6330 try f.object.newline();
62306331 return local;
62316332}
62326333
......@@ -6241,29 +6342,30 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
62416342 const operand_ty = f.typeOf(ty_op.operand);
62426343 const error_union_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
62436344
6244 const writer = f.object.writer();
6345 const w = &f.object.code.writer;
62456346 if (!error_union_ty.errorUnionPayload(zcu).hasRuntimeBits(zcu)) {
62466347 if (!is_ptr) return .none;
62476348
62486349 const local = try f.allocLocal(inst, inst_ty);
6249 try f.writeCValue(writer, local, .Other);
6250 try writer.writeAll(" = (");
6251 try f.renderType(writer, inst_ty);
6252 try writer.writeByte(')');
6253 try f.writeCValue(writer, operand, .Other);
6254 try writer.writeAll(";\n");
6350 try f.writeCValue(w, local, .Other);
6351 try w.writeAll(" = (");
6352 try f.renderType(w, inst_ty);
6353 try w.writeByte(')');
6354 try f.writeCValue(w, operand, .Other);
6355 try w.writeByte(';');
6356 try f.object.newline();
62556357 return local;
62566358 }
62576359
62586360 const local = try f.allocLocal(inst, inst_ty);
6259 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
6260 try f.writeCValue(writer, local, .Other);
6261 try a.assign(f, writer);
6361 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
6362 try f.writeCValue(w, local, .Other);
6363 try a.assign(f, w);
62626364 if (is_ptr) {
6263 try writer.writeByte('&');
6264 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
6265 } else try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
6266 try a.end(f, writer);
6365 try w.writeByte('&');
6366 try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
6367 } else try f.writeCValueMember(w, operand, .{ .identifier = "payload" });
6368 try a.end(f, w);
62676369 return local;
62686370}
62696371
......@@ -6282,21 +6384,21 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
62826384 .aggregate => |aggregate| switch (aggregate.fields.at(0, ctype_pool).name.index) {
62836385 .is_null, .payload => {
62846386 const operand_ctype = try f.ctypeFromType(f.typeOf(ty_op.operand), .complete);
6285 const writer = f.object.writer();
6387 const w = &f.object.code.writer;
62866388 const local = try f.allocLocal(inst, inst_ty);
62876389 {
6288 const a = try Assignment.start(f, writer, .bool);
6289 try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });
6290 try a.assign(f, writer);
6291 try writer.writeAll("false");
6292 try a.end(f, writer);
6390 const a = try Assignment.start(f, w, .bool);
6391 try f.writeCValueMember(w, local, .{ .identifier = "is_null" });
6392 try a.assign(f, w);
6393 try w.writeAll("false");
6394 try a.end(f, w);
62936395 }
62946396 {
6295 const a = try Assignment.start(f, writer, operand_ctype);
6296 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
6297 try a.assign(f, writer);
6298 try f.writeCValue(writer, operand, .Other);
6299 try a.end(f, writer);
6397 const a = try Assignment.start(f, w, operand_ctype);
6398 try f.writeCValueMember(w, local, .{ .identifier = "payload" });
6399 try a.assign(f, w);
6400 try f.writeCValue(w, operand, .Other);
6401 try a.end(f, w);
63006402 }
63016403 return local;
63026404 },
......@@ -6318,7 +6420,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
63186420 const err = try f.resolveInst(ty_op.operand);
63196421 try reap(f, inst, &.{ty_op.operand});
63206422
6321 const writer = f.object.writer();
6423 const w = &f.object.code.writer;
63226424 const local = try f.allocLocal(inst, inst_ty);
63236425
63246426 if (repr_is_err and err == .local and err.local == local.new_local) {
......@@ -6327,21 +6429,21 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
63276429 }
63286430
63296431 if (!repr_is_err) {
6330 const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
6331 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
6332 try a.assign(f, writer);
6333 try f.object.dg.renderUndefValue(writer, payload_ty, .Other);
6334 try a.end(f, writer);
6432 const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete));
6433 try f.writeCValueMember(w, local, .{ .identifier = "payload" });
6434 try a.assign(f, w);
6435 try f.object.dg.renderUndefValue(w, payload_ty, .Other);
6436 try a.end(f, w);
63356437 }
63366438 {
6337 const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete));
6439 const a = try Assignment.start(f, w, try f.ctypeFromType(err_ty, .complete));
63386440 if (repr_is_err)
6339 try f.writeCValue(writer, local, .Other)
6441 try f.writeCValue(w, local, .Other)
63406442 else
6341 try f.writeCValueMember(writer, local, .{ .identifier = "error" });
6342 try a.assign(f, writer);
6343 try f.writeCValue(writer, err, .Other);
6344 try a.end(f, writer);
6443 try f.writeCValueMember(w, local, .{ .identifier = "error" });
6444 try a.assign(f, w);
6445 try f.writeCValue(w, err, .Other);
6446 try a.end(f, w);
63456447 }
63466448 return local;
63476449}
......@@ -6349,7 +6451,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
63496451fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
63506452 const pt = f.object.dg.pt;
63516453 const zcu = pt.zcu;
6352 const writer = f.object.writer();
6454 const w = &f.object.code.writer;
63536455 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
63546456 const inst_ty = f.typeOfIndex(inst);
63556457 const operand = try f.resolveInst(ty_op.operand);
......@@ -6363,31 +6465,31 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
63636465
63646466 // First, set the non-error value.
63656467 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
6366 const a = try Assignment.start(f, writer, try f.ctypeFromType(operand_ty, .complete));
6367 try f.writeCValueDeref(writer, operand);
6368 try a.assign(f, writer);
6369 try writer.print("{}", .{try f.fmtIntLiteral(no_err)});
6370 try a.end(f, writer);
6468 const a = try Assignment.start(f, w, try f.ctypeFromType(operand_ty, .complete));
6469 try f.writeCValueDeref(w, operand);
6470 try a.assign(f, w);
6471 try w.print("{f}", .{try f.fmtIntLiteralDec(no_err)});
6472 try a.end(f, w);
63716473 return .none;
63726474 }
63736475 {
6374 const a = try Assignment.start(f, writer, try f.ctypeFromType(err_int_ty, .complete));
6375 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" });
6376 try a.assign(f, writer);
6377 try writer.print("{}", .{try f.fmtIntLiteral(no_err)});
6378 try a.end(f, writer);
6476 const a = try Assignment.start(f, w, try f.ctypeFromType(err_int_ty, .complete));
6477 try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" });
6478 try a.assign(f, w);
6479 try w.print("{f}", .{try f.fmtIntLiteralDec(no_err)});
6480 try a.end(f, w);
63796481 }
63806482
63816483 // Then return the payload pointer (only if it is used)
63826484 if (f.liveness.isUnused(inst)) return .none;
63836485
63846486 const local = try f.allocLocal(inst, inst_ty);
6385 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
6386 try f.writeCValue(writer, local, .Other);
6387 try a.assign(f, writer);
6388 try writer.writeByte('&');
6389 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
6390 try a.end(f, writer);
6487 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
6488 try f.writeCValue(w, local, .Other);
6489 try a.assign(f, w);
6490 try w.writeByte('&');
6491 try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
6492 try a.end(f, w);
63916493 return local;
63926494}
63936495
......@@ -6418,24 +6520,24 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
64186520 const err_ty = inst_ty.errorUnionSet(zcu);
64196521 try reap(f, inst, &.{ty_op.operand});
64206522
6421 const writer = f.object.writer();
6523 const w = &f.object.code.writer;
64226524 const local = try f.allocLocal(inst, inst_ty);
64236525 if (!repr_is_err) {
6424 const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
6425 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
6426 try a.assign(f, writer);
6427 try f.writeCValue(writer, payload, .Other);
6428 try a.end(f, writer);
6526 const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete));
6527 try f.writeCValueMember(w, local, .{ .identifier = "payload" });
6528 try a.assign(f, w);
6529 try f.writeCValue(w, payload, .Other);
6530 try a.end(f, w);
64296531 }
64306532 {
6431 const a = try Assignment.start(f, writer, try f.ctypeFromType(err_ty, .complete));
6533 const a = try Assignment.start(f, w, try f.ctypeFromType(err_ty, .complete));
64326534 if (repr_is_err)
6433 try f.writeCValue(writer, local, .Other)
6535 try f.writeCValue(w, local, .Other)
64346536 else
6435 try f.writeCValueMember(writer, local, .{ .identifier = "error" });
6436 try a.assign(f, writer);
6437 try f.object.dg.renderValue(writer, try pt.intValue(try pt.errorIntType(), 0), .Other);
6438 try a.end(f, writer);
6537 try f.writeCValueMember(w, local, .{ .identifier = "error" });
6538 try a.assign(f, w);
6539 try f.object.dg.renderValue(w, try pt.intValue(try pt.errorIntType(), 0), .Other);
6540 try a.end(f, w);
64396541 }
64406542 return local;
64416543}
......@@ -6445,7 +6547,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
64456547 const zcu = pt.zcu;
64466548 const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
64476549
6448 const writer = f.object.writer();
6550 const w = &f.object.code.writer;
64496551 const operand = try f.resolveInst(un_op);
64506552 try reap(f, inst, &.{un_op});
64516553 const operand_ty = f.typeOf(un_op);
......@@ -6454,25 +6556,25 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
64546556 const payload_ty = err_union_ty.errorUnionPayload(zcu);
64556557 const error_ty = err_union_ty.errorUnionSet(zcu);
64566558
6457 const a = try Assignment.start(f, writer, .bool);
6458 try f.writeCValue(writer, local, .Other);
6459 try a.assign(f, writer);
6559 const a = try Assignment.start(f, w, .bool);
6560 try f.writeCValue(w, local, .Other);
6561 try a.assign(f, w);
64606562 const err_int_ty = try pt.errorIntType();
64616563 if (!error_ty.errorSetIsEmpty(zcu))
64626564 if (payload_ty.hasRuntimeBits(zcu))
64636565 if (is_ptr)
6464 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" })
6566 try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" })
64656567 else
6466 try f.writeCValueMember(writer, operand, .{ .identifier = "error" })
6568 try f.writeCValueMember(w, operand, .{ .identifier = "error" })
64676569 else
6468 try f.writeCValue(writer, operand, .Other)
6570 try f.writeCValue(w, operand, .Other)
64696571 else
6470 try f.object.dg.renderValue(writer, try pt.intValue(err_int_ty, 0), .Other);
6471 try writer.writeByte(' ');
6472 try writer.writeAll(operator);
6473 try writer.writeByte(' ');
6474 try f.object.dg.renderValue(writer, try pt.intValue(err_int_ty, 0), .Other);
6475 try a.end(f, writer);
6572 try f.object.dg.renderValue(w, try pt.intValue(err_int_ty, 0), .Other);
6573 try w.writeByte(' ');
6574 try w.writeAll(operator);
6575 try w.writeByte(' ');
6576 try f.object.dg.renderValue(w, try pt.intValue(err_int_ty, 0), .Other);
6577 try a.end(f, w);
64766578 return local;
64776579}
64786580
......@@ -6486,45 +6588,45 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
64866588 try reap(f, inst, &.{ty_op.operand});
64876589 const inst_ty = f.typeOfIndex(inst);
64886590 const ptr_ty = inst_ty.slicePtrFieldType(zcu);
6489 const writer = f.object.writer();
6591 const w = &f.object.code.writer;
64906592 const local = try f.allocLocal(inst, inst_ty);
64916593 const operand_ty = f.typeOf(ty_op.operand);
64926594 const array_ty = operand_ty.childType(zcu);
64936595
64946596 {
6495 const a = try Assignment.start(f, writer, try f.ctypeFromType(ptr_ty, .complete));
6496 try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
6497 try a.assign(f, writer);
6597 const a = try Assignment.start(f, w, try f.ctypeFromType(ptr_ty, .complete));
6598 try f.writeCValueMember(w, local, .{ .identifier = "ptr" });
6599 try a.assign(f, w);
64986600 if (operand == .undef) {
6499 try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Other);
6601 try f.writeCValue(w, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Other);
65006602 } else {
65016603 const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete);
65026604 const ptr_child_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
65036605 const elem_ty = array_ty.childType(zcu);
65046606 const elem_ctype = try f.ctypeFromType(elem_ty, .complete);
65056607 if (!ptr_child_ctype.eql(elem_ctype)) {
6506 try writer.writeByte('(');
6507 try f.renderCType(writer, ptr_ctype);
6508 try writer.writeByte(')');
6608 try w.writeByte('(');
6609 try f.renderCType(w, ptr_ctype);
6610 try w.writeByte(')');
65096611 }
65106612 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
65116613 const operand_child_ctype = operand_ctype.info(ctype_pool).pointer.elem_ctype;
65126614 if (operand_child_ctype.info(ctype_pool) == .array) {
6513 try writer.writeByte('&');
6514 try f.writeCValueDeref(writer, operand);
6515 try writer.print("[{}]", .{try f.fmtIntLiteral(.zero_usize)});
6516 } else try f.writeCValue(writer, operand, .Other);
6615 try w.writeByte('&');
6616 try f.writeCValueDeref(w, operand);
6617 try w.print("[{f}]", .{try f.fmtIntLiteralDec(.zero_usize)});
6618 } else try f.writeCValue(w, operand, .Other);
65176619 }
6518 try a.end(f, writer);
6620 try a.end(f, w);
65196621 }
65206622 {
6521 const a = try Assignment.start(f, writer, .usize);
6522 try f.writeCValueMember(writer, local, .{ .identifier = "len" });
6523 try a.assign(f, writer);
6524 try writer.print("{}", .{
6525 try f.fmtIntLiteral(try pt.intValue(.usize, array_ty.arrayLen(zcu))),
6623 const a = try Assignment.start(f, w, .usize);
6624 try f.writeCValueMember(w, local, .{ .identifier = "len" });
6625 try a.assign(f, w);
6626 try w.print("{f}", .{
6627 try f.fmtIntLiteralDec(try pt.intValue(.usize, array_ty.arrayLen(zcu))),
65266628 });
6527 try a.end(f, writer);
6629 try a.end(f, w);
65286630 }
65296631
65306632 return local;
......@@ -6551,32 +6653,32 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
65516653 else
65526654 unreachable;
65536655
6554 const writer = f.object.writer();
6656 const w = &f.object.code.writer;
65556657 const local = try f.allocLocal(inst, inst_ty);
6556 const v = try Vectorize.start(f, inst, writer, operand_ty);
6557 const a = try Assignment.start(f, writer, try f.ctypeFromType(scalar_ty, .complete));
6558 try f.writeCValue(writer, local, .Other);
6559 try v.elem(f, writer);
6560 try a.assign(f, writer);
6658 const v = try Vectorize.start(f, inst, w, operand_ty);
6659 const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete));
6660 try f.writeCValue(w, local, .Other);
6661 try v.elem(f, w);
6662 try a.assign(f, w);
65616663 if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) {
6562 try writer.writeAll("zig_wrap_");
6563 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_scalar_ty);
6564 try writer.writeByte('(');
6565 }
6566 try writer.writeAll("zig_");
6567 try writer.writeAll(operation);
6568 try writer.writeAll(compilerRtAbbrev(scalar_ty, zcu, target));
6569 try writer.writeAll(compilerRtAbbrev(inst_scalar_ty, zcu, target));
6570 try writer.writeByte('(');
6571 try f.writeCValue(writer, operand, .FunctionArgument);
6572 try v.elem(f, writer);
6573 try writer.writeByte(')');
6664 try w.writeAll("zig_wrap_");
6665 try f.object.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty);
6666 try w.writeByte('(');
6667 }
6668 try w.writeAll("zig_");
6669 try w.writeAll(operation);
6670 try w.writeAll(compilerRtAbbrev(scalar_ty, zcu, target));
6671 try w.writeAll(compilerRtAbbrev(inst_scalar_ty, zcu, target));
6672 try w.writeByte('(');
6673 try f.writeCValue(w, operand, .FunctionArgument);
6674 try v.elem(f, w);
6675 try w.writeByte(')');
65746676 if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) {
6575 try f.object.dg.renderBuiltinInfo(writer, inst_scalar_ty, .bits);
6576 try writer.writeByte(')');
6677 try f.object.dg.renderBuiltinInfo(w, inst_scalar_ty, .bits);
6678 try w.writeByte(')');
65776679 }
6578 try a.end(f, writer);
6579 try v.end(f, inst, writer);
6680 try a.end(f, w);
6681 try v.end(f, inst, w);
65806682
65816683 return local;
65826684}
......@@ -6601,27 +6703,28 @@ fn airUnBuiltinCall(
66016703 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
66026704 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
66036705
6604 const writer = f.object.writer();
6706 const w = &f.object.code.writer;
66056707 const local = try f.allocLocal(inst, inst_ty);
6606 const v = try Vectorize.start(f, inst, writer, operand_ty);
6708 const v = try Vectorize.start(f, inst, w, operand_ty);
66076709 if (!ref_ret) {
6608 try f.writeCValue(writer, local, .Other);
6609 try v.elem(f, writer);
6610 try writer.writeAll(" = ");
6710 try f.writeCValue(w, local, .Other);
6711 try v.elem(f, w);
6712 try w.writeAll(" = ");
66116713 }
6612 try writer.print("zig_{s}_", .{operation});
6613 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
6614 try writer.writeByte('(');
6714 try w.print("zig_{s}_", .{operation});
6715 try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
6716 try w.writeByte('(');
66156717 if (ref_ret) {
6616 try f.writeCValue(writer, local, .FunctionArgument);
6617 try v.elem(f, writer);
6618 try writer.writeAll(", ");
6718 try f.writeCValue(w, local, .FunctionArgument);
6719 try v.elem(f, w);
6720 try w.writeAll(", ");
66196721 }
6620 try f.writeCValue(writer, operand, .FunctionArgument);
6621 try v.elem(f, writer);
6622 try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info);
6623 try writer.writeAll(");\n");
6624 try v.end(f, inst, writer);
6722 try f.writeCValue(w, operand, .FunctionArgument);
6723 try v.elem(f, w);
6724 try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
6725 try w.writeAll(");");
6726 try f.object.newline();
6727 try v.end(f, inst, w);
66256728
66266729 return local;
66276730}
......@@ -6651,31 +6754,31 @@ fn airBinBuiltinCall(
66516754 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
66526755 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
66536756
6654 const writer = f.object.writer();
6757 const w = &f.object.code.writer;
66556758 const local = try f.allocLocal(inst, inst_ty);
66566759 if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6657 const v = try Vectorize.start(f, inst, writer, operand_ty);
6760 const v = try Vectorize.start(f, inst, w, operand_ty);
66586761 if (!ref_ret) {
6659 try f.writeCValue(writer, local, .Other);
6660 try v.elem(f, writer);
6661 try writer.writeAll(" = ");
6762 try f.writeCValue(w, local, .Other);
6763 try v.elem(f, w);
6764 try w.writeAll(" = ");
66626765 }
6663 try writer.print("zig_{s}_", .{operation});
6664 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
6665 try writer.writeByte('(');
6766 try w.print("zig_{s}_", .{operation});
6767 try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
6768 try w.writeByte('(');
66666769 if (ref_ret) {
6667 try f.writeCValue(writer, local, .FunctionArgument);
6668 try v.elem(f, writer);
6669 try writer.writeAll(", ");
6670 }
6671 try f.writeCValue(writer, lhs, .FunctionArgument);
6672 try v.elem(f, writer);
6673 try writer.writeAll(", ");
6674 try f.writeCValue(writer, rhs, .FunctionArgument);
6675 if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, writer);
6676 try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info);
6677 try writer.writeAll(");\n");
6678 try v.end(f, inst, writer);
6770 try f.writeCValue(w, local, .FunctionArgument);
6771 try v.elem(f, w);
6772 try w.writeAll(", ");
6773 }
6774 try f.writeCValue(w, lhs, .FunctionArgument);
6775 try v.elem(f, w);
6776 try w.writeAll(", ");
6777 try f.writeCValue(w, rhs, .FunctionArgument);
6778 if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w);
6779 try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
6780 try w.writeAll(");\n");
6781 try v.end(f, inst, w);
66796782
66806783 return local;
66816784}
......@@ -6702,38 +6805,39 @@ fn airCmpBuiltinCall(
67026805 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
67036806 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
67046807
6705 const writer = f.object.writer();
6808 const w = &f.object.code.writer;
67066809 const local = try f.allocLocal(inst, inst_ty);
6707 const v = try Vectorize.start(f, inst, writer, operand_ty);
6810 const v = try Vectorize.start(f, inst, w, operand_ty);
67086811 if (!ref_ret) {
6709 try f.writeCValue(writer, local, .Other);
6710 try v.elem(f, writer);
6711 try writer.writeAll(" = ");
6812 try f.writeCValue(w, local, .Other);
6813 try v.elem(f, w);
6814 try w.writeAll(" = ");
67126815 }
6713 try writer.print("zig_{s}_", .{switch (operation) {
6816 try w.print("zig_{s}_", .{switch (operation) {
67146817 else => @tagName(operation),
67156818 .operator => compareOperatorAbbrev(operator),
67166819 }});
6717 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
6718 try writer.writeByte('(');
6820 try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
6821 try w.writeByte('(');
67196822 if (ref_ret) {
6720 try f.writeCValue(writer, local, .FunctionArgument);
6721 try v.elem(f, writer);
6722 try writer.writeAll(", ");
6723 }
6724 try f.writeCValue(writer, lhs, .FunctionArgument);
6725 try v.elem(f, writer);
6726 try writer.writeAll(", ");
6727 try f.writeCValue(writer, rhs, .FunctionArgument);
6728 try v.elem(f, writer);
6729 try f.object.dg.renderBuiltinInfo(writer, scalar_ty, info);
6730 try writer.writeByte(')');
6731 if (!ref_ret) try writer.print("{s}{}", .{
6823 try f.writeCValue(w, local, .FunctionArgument);
6824 try v.elem(f, w);
6825 try w.writeAll(", ");
6826 }
6827 try f.writeCValue(w, lhs, .FunctionArgument);
6828 try v.elem(f, w);
6829 try w.writeAll(", ");
6830 try f.writeCValue(w, rhs, .FunctionArgument);
6831 try v.elem(f, w);
6832 try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
6833 try w.writeByte(')');
6834 if (!ref_ret) try w.print("{s}{f}", .{
67326835 compareOperatorC(operator),
6733 try f.fmtIntLiteral(try pt.intValue(.i32, 0)),
6836 try f.fmtIntLiteralDec(try pt.intValue(.i32, 0)),
67346837 });
6735 try writer.writeAll(";\n");
6736 try v.end(f, inst, writer);
6838 try w.writeByte(';');
6839 try f.object.newline();
6840 try v.end(f, inst, w);
67376841
67386842 return local;
67396843}
......@@ -6751,7 +6855,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
67516855 const ty = ptr_ty.childType(zcu);
67526856 const ctype = try f.ctypeFromType(ty, .complete);
67536857
6754 const writer = f.object.writer();
6858 const w = &f.object.code.writer;
67556859 const new_value_mat = try Materialize.start(f, inst, ty, new_value);
67566860 try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value });
67576861
......@@ -6763,76 +6867,78 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
67636867 const local = try f.allocLocal(inst, inst_ty);
67646868 if (inst_ty.isPtrLikeOptional(zcu)) {
67656869 {
6766 const a = try Assignment.start(f, writer, ctype);
6767 try f.writeCValue(writer, local, .Other);
6768 try a.assign(f, writer);
6769 try f.writeCValue(writer, expected_value, .Other);
6770 try a.end(f, writer);
6870 const a = try Assignment.start(f, w, ctype);
6871 try f.writeCValue(w, local, .Other);
6872 try a.assign(f, w);
6873 try f.writeCValue(w, expected_value, .Other);
6874 try a.end(f, w);
67716875 }
67726876
6773 try writer.writeAll("if (");
6774 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
6775 try f.renderType(writer, ty);
6776 try writer.writeByte(')');
6777 if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile");
6778 try writer.writeAll(" *)");
6779 try f.writeCValue(writer, ptr, .Other);
6780 try writer.writeAll(", ");
6781 try f.writeCValue(writer, local, .FunctionArgument);
6782 try writer.writeAll(", ");
6783 try new_value_mat.mat(f, writer);
6784 try writer.writeAll(", ");
6785 try writeMemoryOrder(writer, extra.successOrder());
6786 try writer.writeAll(", ");
6787 try writeMemoryOrder(writer, extra.failureOrder());
6788 try writer.writeAll(", ");
6789 try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
6790 try writer.writeAll(", ");
6791 try f.renderType(writer, repr_ty);
6792 try writer.writeByte(')');
6793 try writer.writeAll(") {\n");
6794 f.object.indent_writer.pushIndent();
6877 try w.writeAll("if (");
6878 try w.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
6879 try f.renderType(w, ty);
6880 try w.writeByte(')');
6881 if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
6882 try w.writeAll(" *)");
6883 try f.writeCValue(w, ptr, .Other);
6884 try w.writeAll(", ");
6885 try f.writeCValue(w, local, .FunctionArgument);
6886 try w.writeAll(", ");
6887 try new_value_mat.mat(f, w);
6888 try w.writeAll(", ");
6889 try writeMemoryOrder(w, extra.successOrder());
6890 try w.writeAll(", ");
6891 try writeMemoryOrder(w, extra.failureOrder());
6892 try w.writeAll(", ");
6893 try f.object.dg.renderTypeForBuiltinFnName(w, ty);
6894 try w.writeAll(", ");
6895 try f.renderType(w, repr_ty);
6896 try w.writeByte(')');
6897 try w.writeAll(") {");
6898 f.object.indent();
6899 try f.object.newline();
67956900 {
6796 const a = try Assignment.start(f, writer, ctype);
6797 try f.writeCValue(writer, local, .Other);
6798 try a.assign(f, writer);
6799 try writer.writeAll("NULL");
6800 try a.end(f, writer);
6901 const a = try Assignment.start(f, w, ctype);
6902 try f.writeCValue(w, local, .Other);
6903 try a.assign(f, w);
6904 try w.writeAll("NULL");
6905 try a.end(f, w);
68016906 }
6802 f.object.indent_writer.popIndent();
6803 try writer.writeAll("}\n");
6907 try f.object.outdent();
6908 try w.writeByte('}');
6909 try f.object.newline();
68046910 } else {
68056911 {
6806 const a = try Assignment.start(f, writer, ctype);
6807 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
6808 try a.assign(f, writer);
6809 try f.writeCValue(writer, expected_value, .Other);
6810 try a.end(f, writer);
6912 const a = try Assignment.start(f, w, ctype);
6913 try f.writeCValueMember(w, local, .{ .identifier = "payload" });
6914 try a.assign(f, w);
6915 try f.writeCValue(w, expected_value, .Other);
6916 try a.end(f, w);
68116917 }
68126918 {
6813 const a = try Assignment.start(f, writer, .bool);
6814 try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });
6815 try a.assign(f, writer);
6816 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
6817 try f.renderType(writer, ty);
6818 try writer.writeByte(')');
6819 if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile");
6820 try writer.writeAll(" *)");
6821 try f.writeCValue(writer, ptr, .Other);
6822 try writer.writeAll(", ");
6823 try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
6824 try writer.writeAll(", ");
6825 try new_value_mat.mat(f, writer);
6826 try writer.writeAll(", ");
6827 try writeMemoryOrder(writer, extra.successOrder());
6828 try writer.writeAll(", ");
6829 try writeMemoryOrder(writer, extra.failureOrder());
6830 try writer.writeAll(", ");
6831 try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
6832 try writer.writeAll(", ");
6833 try f.renderType(writer, repr_ty);
6834 try writer.writeByte(')');
6835 try a.end(f, writer);
6919 const a = try Assignment.start(f, w, .bool);
6920 try f.writeCValueMember(w, local, .{ .identifier = "is_null" });
6921 try a.assign(f, w);
6922 try w.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
6923 try f.renderType(w, ty);
6924 try w.writeByte(')');
6925 if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
6926 try w.writeAll(" *)");
6927 try f.writeCValue(w, ptr, .Other);
6928 try w.writeAll(", ");
6929 try f.writeCValueMember(w, local, .{ .identifier = "payload" });
6930 try w.writeAll(", ");
6931 try new_value_mat.mat(f, w);
6932 try w.writeAll(", ");
6933 try writeMemoryOrder(w, extra.successOrder());
6934 try w.writeAll(", ");
6935 try writeMemoryOrder(w, extra.failureOrder());
6936 try w.writeAll(", ");
6937 try f.object.dg.renderTypeForBuiltinFnName(w, ty);
6938 try w.writeAll(", ");
6939 try f.renderType(w, repr_ty);
6940 try w.writeByte(')');
6941 try a.end(f, w);
68366942 }
68376943 }
68386944 try new_value_mat.end(f, inst);
......@@ -6856,7 +6962,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
68566962 const ptr = try f.resolveInst(pl_op.operand);
68576963 const operand = try f.resolveInst(extra.operand);
68586964
6859 const writer = f.object.writer();
6965 const w = &f.object.code.writer;
68606966 const operand_mat = try Materialize.start(f, inst, ty, operand);
68616967 try reap(f, inst, &.{ pl_op.operand, extra.operand });
68626968
......@@ -6866,31 +6972,32 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
68666972 const repr_ty = if (is_float) pt.intType(.unsigned, repr_bits) catch unreachable else ty;
68676973
68686974 const local = try f.allocLocal(inst, inst_ty);
6869 try writer.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())});
6870 if (is_float) try writer.writeAll("_float") else if (is_128) try writer.writeAll("_int128");
6871 try writer.writeByte('(');
6872 try f.writeCValue(writer, local, .Other);
6873 try writer.writeAll(", (");
6975 try w.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())});
6976 if (is_float) try w.writeAll("_float") else if (is_128) try w.writeAll("_int128");
6977 try w.writeByte('(');
6978 try f.writeCValue(w, local, .Other);
6979 try w.writeAll(", (");
68746980 const use_atomic = switch (extra.op()) {
68756981 else => true,
68766982 // These are missing from stdatomic.h, so no atomic types unless a fallback is used.
68776983 .Nand, .Min, .Max => is_float or is_128,
68786984 };
6879 if (use_atomic) try writer.writeAll("zig_atomic(");
6880 try f.renderType(writer, ty);
6881 if (use_atomic) try writer.writeByte(')');
6882 if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile");
6883 try writer.writeAll(" *)");
6884 try f.writeCValue(writer, ptr, .Other);
6885 try writer.writeAll(", ");
6886 try operand_mat.mat(f, writer);
6887 try writer.writeAll(", ");
6888 try writeMemoryOrder(writer, extra.ordering());
6889 try writer.writeAll(", ");
6890 try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
6891 try writer.writeAll(", ");
6892 try f.renderType(writer, repr_ty);
6893 try writer.writeAll(");\n");
6985 if (use_atomic) try w.writeAll("zig_atomic(");
6986 try f.renderType(w, ty);
6987 if (use_atomic) try w.writeByte(')');
6988 if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
6989 try w.writeAll(" *)");
6990 try f.writeCValue(w, ptr, .Other);
6991 try w.writeAll(", ");
6992 try operand_mat.mat(f, w);
6993 try w.writeAll(", ");
6994 try writeMemoryOrder(w, extra.ordering());
6995 try w.writeAll(", ");
6996 try f.object.dg.renderTypeForBuiltinFnName(w, ty);
6997 try w.writeAll(", ");
6998 try f.renderType(w, repr_ty);
6999 try w.writeAll(");");
7000 try f.object.newline();
68947001 try operand_mat.end(f, inst);
68957002
68967003 if (f.liveness.isUnused(inst)) {
......@@ -6916,24 +7023,25 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
69167023 ty;
69177024
69187025 const inst_ty = f.typeOfIndex(inst);
6919 const writer = f.object.writer();
7026 const w = &f.object.code.writer;
69207027 const local = try f.allocLocal(inst, inst_ty);
69217028
6922 try writer.writeAll("zig_atomic_load(");
6923 try f.writeCValue(writer, local, .Other);
6924 try writer.writeAll(", (zig_atomic(");
6925 try f.renderType(writer, ty);
6926 try writer.writeByte(')');
6927 if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile");
6928 try writer.writeAll(" *)");
6929 try f.writeCValue(writer, ptr, .Other);
6930 try writer.writeAll(", ");
6931 try writeMemoryOrder(writer, atomic_load.order);
6932 try writer.writeAll(", ");
6933 try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
6934 try writer.writeAll(", ");
6935 try f.renderType(writer, repr_ty);
6936 try writer.writeAll(");\n");
7029 try w.writeAll("zig_atomic_load(");
7030 try f.writeCValue(w, local, .Other);
7031 try w.writeAll(", (zig_atomic(");
7032 try f.renderType(w, ty);
7033 try w.writeByte(')');
7034 if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
7035 try w.writeAll(" *)");
7036 try f.writeCValue(w, ptr, .Other);
7037 try w.writeAll(", ");
7038 try writeMemoryOrder(w, atomic_load.order);
7039 try w.writeAll(", ");
7040 try f.object.dg.renderTypeForBuiltinFnName(w, ty);
7041 try w.writeAll(", ");
7042 try f.renderType(w, repr_ty);
7043 try w.writeAll(");");
7044 try f.object.newline();
69377045
69387046 return local;
69397047}
......@@ -6947,7 +7055,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
69477055 const ptr = try f.resolveInst(bin_op.lhs);
69487056 const element = try f.resolveInst(bin_op.rhs);
69497057
6950 const writer = f.object.writer();
7058 const w = &f.object.code.writer;
69517059 const element_mat = try Materialize.start(f, inst, ty, element);
69527060 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
69537061
......@@ -6956,31 +7064,32 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
69567064 else
69577065 ty;
69587066
6959 try writer.writeAll("zig_atomic_store((zig_atomic(");
6960 try f.renderType(writer, ty);
6961 try writer.writeByte(')');
6962 if (ptr_ty.isVolatilePtr(zcu)) try writer.writeAll(" volatile");
6963 try writer.writeAll(" *)");
6964 try f.writeCValue(writer, ptr, .Other);
6965 try writer.writeAll(", ");
6966 try element_mat.mat(f, writer);
6967 try writer.print(", {s}, ", .{order});
6968 try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
6969 try writer.writeAll(", ");
6970 try f.renderType(writer, repr_ty);
6971 try writer.writeAll(");\n");
7067 try w.writeAll("zig_atomic_store((zig_atomic(");
7068 try f.renderType(w, ty);
7069 try w.writeByte(')');
7070 if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
7071 try w.writeAll(" *)");
7072 try f.writeCValue(w, ptr, .Other);
7073 try w.writeAll(", ");
7074 try element_mat.mat(f, w);
7075 try w.print(", {s}, ", .{order});
7076 try f.object.dg.renderTypeForBuiltinFnName(w, ty);
7077 try w.writeAll(", ");
7078 try f.renderType(w, repr_ty);
7079 try w.writeAll(");");
7080 try f.object.newline();
69727081 try element_mat.end(f, inst);
69737082
69747083 return .none;
69757084}
69767085
6977fn writeSliceOrPtr(f: *Function, writer: anytype, ptr: CValue, ptr_ty: Type) !void {
7086fn writeSliceOrPtr(f: *Function, w: *Writer, ptr: CValue, ptr_ty: Type) !void {
69787087 const pt = f.object.dg.pt;
69797088 const zcu = pt.zcu;
69807089 if (ptr_ty.isSlice(zcu)) {
6981 try f.writeCValueMember(writer, ptr, .{ .identifier = "ptr" });
7090 try f.writeCValueMember(w, ptr, .{ .identifier = "ptr" });
69827091 } else {
6983 try f.writeCValue(writer, ptr, .FunctionArgument);
7092 try f.writeCValue(w, ptr, .FunctionArgument);
69847093 }
69857094}
69867095
......@@ -6994,7 +7103,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
69947103 const elem_ty = f.typeOf(bin_op.rhs);
69957104 const elem_abi_size = elem_ty.abiSize(zcu);
69967105 const val_is_undef = if (try f.air.value(bin_op.rhs, pt)) |val| val.isUndefDeep(zcu) else false;
6997 const writer = f.object.writer();
7106 const w = &f.object.code.writer;
69987107
69997108 if (val_is_undef) {
70007109 if (!safety) {
......@@ -7002,24 +7111,25 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
70027111 return .none;
70037112 }
70047113
7005 try writer.writeAll("memset(");
7114 try w.writeAll("memset(");
70067115 switch (dest_ty.ptrSize(zcu)) {
70077116 .slice => {
7008 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });
7009 try writer.writeAll(", 0xaa, ");
7010 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
7117 try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" });
7118 try w.writeAll(", 0xaa, ");
7119 try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" });
70117120 if (elem_abi_size > 1) {
7012 try writer.print(" * {d});\n", .{elem_abi_size});
7013 } else {
7014 try writer.writeAll(");\n");
7121 try w.print(" * {d}", .{elem_abi_size});
70157122 }
7123 try w.writeAll(");");
7124 try f.object.newline();
70167125 },
70177126 .one => {
70187127 const array_ty = dest_ty.childType(zcu);
70197128 const len = array_ty.arrayLen(zcu) * elem_abi_size;
70207129
7021 try f.writeCValue(writer, dest_slice, .FunctionArgument);
7022 try writer.print(", 0xaa, {d});\n", .{len});
7130 try f.writeCValue(w, dest_slice, .FunctionArgument);
7131 try w.print(", 0xaa, {d});", .{len});
7132 try f.object.newline();
70237133 },
70247134 .many, .c => unreachable,
70257135 }
......@@ -7040,38 +7150,38 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
70407150
70417151 const index = try f.allocLocal(inst, .usize);
70427152
7043 try writer.writeAll("for (");
7044 try f.writeCValue(writer, index, .Other);
7045 try writer.writeAll(" = ");
7046 try f.object.dg.renderValue(writer, .zero_usize, .Other);
7047 try writer.writeAll("; ");
7048 try f.writeCValue(writer, index, .Other);
7049 try writer.writeAll(" != ");
7153 try w.writeAll("for (");
7154 try f.writeCValue(w, index, .Other);
7155 try w.writeAll(" = ");
7156 try f.object.dg.renderValue(w, .zero_usize, .Other);
7157 try w.writeAll("; ");
7158 try f.writeCValue(w, index, .Other);
7159 try w.writeAll(" != ");
70507160 switch (dest_ty.ptrSize(zcu)) {
70517161 .slice => {
7052 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
7162 try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" });
70537163 },
70547164 .one => {
70557165 const array_ty = dest_ty.childType(zcu);
7056 try writer.print("{d}", .{array_ty.arrayLen(zcu)});
7166 try w.print("{d}", .{array_ty.arrayLen(zcu)});
70577167 },
70587168 .many, .c => unreachable,
70597169 }
7060 try writer.writeAll("; ++");
7061 try f.writeCValue(writer, index, .Other);
7062 try writer.writeAll(") ");
7063
7064 const a = try Assignment.start(f, writer, try f.ctypeFromType(elem_ty, .complete));
7065 try writer.writeAll("((");
7066 try f.renderType(writer, elem_ptr_ty);
7067 try writer.writeByte(')');
7068 try writeSliceOrPtr(f, writer, dest_slice, dest_ty);
7069 try writer.writeAll(")[");
7070 try f.writeCValue(writer, index, .Other);
7071 try writer.writeByte(']');
7072 try a.assign(f, writer);
7073 try f.writeCValue(writer, value, .Other);
7074 try a.end(f, writer);
7170 try w.writeAll("; ++");
7171 try f.writeCValue(w, index, .Other);
7172 try w.writeAll(") ");
7173
7174 const a = try Assignment.start(f, w, try f.ctypeFromType(elem_ty, .complete));
7175 try w.writeAll("((");
7176 try f.renderType(w, elem_ptr_ty);
7177 try w.writeByte(')');
7178 try writeSliceOrPtr(f, w, dest_slice, dest_ty);
7179 try w.writeAll(")[");
7180 try f.writeCValue(w, index, .Other);
7181 try w.writeByte(']');
7182 try a.assign(f, w);
7183 try f.writeCValue(w, value, .Other);
7184 try a.end(f, w);
70757185
70767186 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
70777187 try freeLocal(f, inst, index.new_local, null);
......@@ -7081,24 +7191,26 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
70817191
70827192 const bitcasted = try bitcast(f, .u8, value, elem_ty);
70837193
7084 try writer.writeAll("memset(");
7194 try w.writeAll("memset(");
70857195 switch (dest_ty.ptrSize(zcu)) {
70867196 .slice => {
7087 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" });
7088 try writer.writeAll(", ");
7089 try f.writeCValue(writer, bitcasted, .FunctionArgument);
7090 try writer.writeAll(", ");
7091 try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" });
7092 try writer.writeAll(");\n");
7197 try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" });
7198 try w.writeAll(", ");
7199 try f.writeCValue(w, bitcasted, .FunctionArgument);
7200 try w.writeAll(", ");
7201 try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" });
7202 try w.writeAll(");");
7203 try f.object.newline();
70937204 },
70947205 .one => {
70957206 const array_ty = dest_ty.childType(zcu);
70967207 const len = array_ty.arrayLen(zcu) * elem_abi_size;
70977208
7098 try f.writeCValue(writer, dest_slice, .FunctionArgument);
7099 try writer.writeAll(", ");
7100 try f.writeCValue(writer, bitcasted, .FunctionArgument);
7101 try writer.print(", {d});\n", .{len});
7209 try f.writeCValue(w, dest_slice, .FunctionArgument);
7210 try w.writeAll(", ");
7211 try f.writeCValue(w, bitcasted, .FunctionArgument);
7212 try w.print(", {d});", .{len});
7213 try f.object.newline();
71027214 },
71037215 .many, .c => unreachable,
71047216 }
......@@ -7115,36 +7227,38 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV
71157227 const src_ptr = try f.resolveInst(bin_op.rhs);
71167228 const dest_ty = f.typeOf(bin_op.lhs);
71177229 const src_ty = f.typeOf(bin_op.rhs);
7118 const writer = f.object.writer();
7230 const w = &f.object.code.writer;
71197231
71207232 if (dest_ty.ptrSize(zcu) != .one) {
7121 try writer.writeAll("if (");
7122 try writeArrayLen(f, writer, dest_ptr, dest_ty);
7123 try writer.writeAll(" != 0) ");
7124 }
7125 try writer.writeAll(function_paren);
7126 try writeSliceOrPtr(f, writer, dest_ptr, dest_ty);
7127 try writer.writeAll(", ");
7128 try writeSliceOrPtr(f, writer, src_ptr, src_ty);
7129 try writer.writeAll(", ");
7130 try writeArrayLen(f, writer, dest_ptr, dest_ty);
7131 try writer.writeAll(" * sizeof(");
7132 try f.renderType(writer, dest_ty.elemType2(zcu));
7133 try writer.writeAll("));\n");
7233 try w.writeAll("if (");
7234 try writeArrayLen(f, dest_ptr, dest_ty);
7235 try w.writeAll(" != 0) ");
7236 }
7237 try w.writeAll(function_paren);
7238 try writeSliceOrPtr(f, w, dest_ptr, dest_ty);
7239 try w.writeAll(", ");
7240 try writeSliceOrPtr(f, w, src_ptr, src_ty);
7241 try w.writeAll(", ");
7242 try writeArrayLen(f, dest_ptr, dest_ty);
7243 try w.writeAll(" * sizeof(");
7244 try f.renderType(w, dest_ty.elemType2(zcu));
7245 try w.writeAll("));");
7246 try f.object.newline();
71347247
71357248 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
71367249 return .none;
71377250}
71387251
7139fn writeArrayLen(f: *Function, writer: ArrayListWriter, dest_ptr: CValue, dest_ty: Type) !void {
7252fn writeArrayLen(f: *Function, dest_ptr: CValue, dest_ty: Type) !void {
71407253 const pt = f.object.dg.pt;
71417254 const zcu = pt.zcu;
7255 const w = &f.object.code.writer;
71427256 switch (dest_ty.ptrSize(zcu)) {
7143 .one => try writer.print("{}", .{
7144 try f.fmtIntLiteral(try pt.intValue(.usize, dest_ty.childType(zcu).arrayLen(zcu))),
7257 .one => try w.print("{f}", .{
7258 try f.fmtIntLiteralDec(try pt.intValue(.usize, dest_ty.childType(zcu).arrayLen(zcu))),
71457259 }),
71467260 .many, .c => unreachable,
7147 .slice => try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }),
7261 .slice => try f.writeCValueMember(w, dest_ptr, .{ .identifier = "len" }),
71487262 }
71497263}
71507264
......@@ -7161,12 +7275,12 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
71617275 if (layout.tag_size == 0) return .none;
71627276 const tag_ty = union_ty.unionTagTypeSafety(zcu).?;
71637277
7164 const writer = f.object.writer();
7165 const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete));
7166 try f.writeCValueDerefMember(writer, union_ptr, .{ .identifier = "tag" });
7167 try a.assign(f, writer);
7168 try f.writeCValue(writer, new_tag, .Other);
7169 try a.end(f, writer);
7278 const w = &f.object.code.writer;
7279 const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));
7280 try f.writeCValueDerefMember(w, union_ptr, .{ .identifier = "tag" });
7281 try a.assign(f, w);
7282 try f.writeCValue(w, new_tag, .Other);
7283 try a.end(f, w);
71707284 return .none;
71717285}
71727286
......@@ -7183,13 +7297,13 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
71837297 if (layout.tag_size == 0) return .none;
71847298
71857299 const inst_ty = f.typeOfIndex(inst);
7186 const writer = f.object.writer();
7300 const w = &f.object.code.writer;
71877301 const local = try f.allocLocal(inst, inst_ty);
7188 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
7189 try f.writeCValue(writer, local, .Other);
7190 try a.assign(f, writer);
7191 try f.writeCValueMember(writer, operand, .{ .identifier = "tag" });
7192 try a.end(f, writer);
7302 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
7303 try f.writeCValue(w, local, .Other);
7304 try a.assign(f, w);
7305 try f.writeCValueMember(w, operand, .{ .identifier = "tag" });
7306 try a.end(f, w);
71937307 return local;
71947308}
71957309
......@@ -7201,14 +7315,15 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
72017315 const operand = try f.resolveInst(un_op);
72027316 try reap(f, inst, &.{un_op});
72037317
7204 const writer = f.object.writer();
7318 const w = &f.object.code.writer;
72057319 const local = try f.allocLocal(inst, inst_ty);
7206 try f.writeCValue(writer, local, .Other);
7207 try writer.print(" = {s}(", .{
7320 try f.writeCValue(w, local, .Other);
7321 try w.print(" = {s}(", .{
72087322 try f.getLazyFnName(.{ .tag_name = enum_ty.toIntern() }),
72097323 });
7210 try f.writeCValue(writer, operand, .Other);
7211 try writer.writeAll(");\n");
7324 try f.writeCValue(w, operand, .Other);
7325 try w.writeAll(");");
7326 try f.object.newline();
72127327
72137328 return local;
72147329}
......@@ -7216,16 +7331,17 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
72167331fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
72177332 const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
72187333
7219 const writer = f.object.writer();
7334 const w = &f.object.code.writer;
72207335 const inst_ty = f.typeOfIndex(inst);
72217336 const operand = try f.resolveInst(un_op);
72227337 try reap(f, inst, &.{un_op});
72237338 const local = try f.allocLocal(inst, inst_ty);
7224 try f.writeCValue(writer, local, .Other);
7339 try f.writeCValue(w, local, .Other);
72257340
7226 try writer.writeAll(" = zig_errorName[");
7227 try f.writeCValue(writer, operand, .Other);
7228 try writer.writeAll(" - 1];\n");
7341 try w.writeAll(" = zig_errorName[");
7342 try f.writeCValue(w, operand, .Other);
7343 try w.writeAll(" - 1];");
7344 try f.object.newline();
72297345 return local;
72307346}
72317347
......@@ -7240,16 +7356,16 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
72407356 const inst_ty = f.typeOfIndex(inst);
72417357 const inst_scalar_ty = inst_ty.scalarType(zcu);
72427358
7243 const writer = f.object.writer();
7359 const w = &f.object.code.writer;
72447360 const local = try f.allocLocal(inst, inst_ty);
7245 const v = try Vectorize.start(f, inst, writer, inst_ty);
7246 const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_scalar_ty, .complete));
7247 try f.writeCValue(writer, local, .Other);
7248 try v.elem(f, writer);
7249 try a.assign(f, writer);
7250 try f.writeCValue(writer, operand, .Other);
7251 try a.end(f, writer);
7252 try v.end(f, inst, writer);
7361 const v = try Vectorize.start(f, inst, w, inst_ty);
7362 const a = try Assignment.start(f, w, try f.ctypeFromType(inst_scalar_ty, .complete));
7363 try f.writeCValue(w, local, .Other);
7364 try v.elem(f, w);
7365 try a.assign(f, w);
7366 try f.writeCValue(w, operand, .Other);
7367 try a.end(f, w);
7368 try v.end(f, inst, w);
72537369
72547370 return local;
72557371}
......@@ -7265,22 +7381,23 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
72657381
72667382 const inst_ty = f.typeOfIndex(inst);
72677383
7268 const writer = f.object.writer();
7384 const w = &f.object.code.writer;
72697385 const local = try f.allocLocal(inst, inst_ty);
7270 const v = try Vectorize.start(f, inst, writer, inst_ty);
7271 try f.writeCValue(writer, local, .Other);
7272 try v.elem(f, writer);
7273 try writer.writeAll(" = ");
7274 try f.writeCValue(writer, pred, .Other);
7275 try v.elem(f, writer);
7276 try writer.writeAll(" ? ");
7277 try f.writeCValue(writer, lhs, .Other);
7278 try v.elem(f, writer);
7279 try writer.writeAll(" : ");
7280 try f.writeCValue(writer, rhs, .Other);
7281 try v.elem(f, writer);
7282 try writer.writeAll(";\n");
7283 try v.end(f, inst, writer);
7386 const v = try Vectorize.start(f, inst, w, inst_ty);
7387 try f.writeCValue(w, local, .Other);
7388 try v.elem(f, w);
7389 try w.writeAll(" = ");
7390 try f.writeCValue(w, pred, .Other);
7391 try v.elem(f, w);
7392 try w.writeAll(" ? ");
7393 try f.writeCValue(w, lhs, .Other);
7394 try v.elem(f, w);
7395 try w.writeAll(" : ");
7396 try f.writeCValue(w, rhs, .Other);
7397 try v.elem(f, w);
7398 try w.writeByte(';');
7399 try f.object.newline();
7400 try v.end(f, inst, w);
72847401
72857402 return local;
72867403}
......@@ -7294,24 +7411,24 @@ fn airShuffleOne(f: *Function, inst: Air.Inst.Index) !CValue {
72947411 const operand = try f.resolveInst(unwrapped.operand);
72957412 const inst_ty = unwrapped.result_ty;
72967413
7297 const writer = f.object.writer();
7414 const w = &f.object.code.writer;
72987415 const local = try f.allocLocal(inst, inst_ty);
72997416 try reap(f, inst, &.{unwrapped.operand}); // local cannot alias operand
73007417 for (mask, 0..) |mask_elem, out_idx| {
7301 try f.writeCValue(writer, local, .Other);
7302 try writer.writeByte('[');
7303 try f.object.dg.renderValue(writer, try pt.intValue(.usize, out_idx), .Other);
7304 try writer.writeAll("] = ");
7418 try f.writeCValue(w, local, .Other);
7419 try w.writeByte('[');
7420 try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other);
7421 try w.writeAll("] = ");
73057422 switch (mask_elem.unwrap()) {
73067423 .elem => |src_idx| {
7307 try f.writeCValue(writer, operand, .Other);
7308 try writer.writeByte('[');
7309 try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);
7310 try writer.writeByte(']');
7424 try f.writeCValue(w, operand, .Other);
7425 try w.writeByte('[');
7426 try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
7427 try w.writeByte(']');
73117428 },
7312 .value => |val| try f.object.dg.renderValue(writer, .fromInterned(val), .Other),
7429 .value => |val| try f.object.dg.renderValue(w, .fromInterned(val), .Other),
73137430 }
7314 try writer.writeAll(";\n");
7431 try w.writeAll(";\n");
73157432 }
73167433
73177434 return local;
......@@ -7328,30 +7445,31 @@ fn airShuffleTwo(f: *Function, inst: Air.Inst.Index) !CValue {
73287445 const inst_ty = unwrapped.result_ty;
73297446 const elem_ty = inst_ty.childType(zcu);
73307447
7331 const writer = f.object.writer();
7448 const w = &f.object.code.writer;
73327449 const local = try f.allocLocal(inst, inst_ty);
73337450 try reap(f, inst, &.{ unwrapped.operand_a, unwrapped.operand_b }); // local cannot alias operands
73347451 for (mask, 0..) |mask_elem, out_idx| {
7335 try f.writeCValue(writer, local, .Other);
7336 try writer.writeByte('[');
7337 try f.object.dg.renderValue(writer, try pt.intValue(.usize, out_idx), .Other);
7338 try writer.writeAll("] = ");
7452 try f.writeCValue(w, local, .Other);
7453 try w.writeByte('[');
7454 try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other);
7455 try w.writeAll("] = ");
73397456 switch (mask_elem.unwrap()) {
73407457 .a_elem => |src_idx| {
7341 try f.writeCValue(writer, operand_a, .Other);
7342 try writer.writeByte('[');
7343 try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);
7344 try writer.writeByte(']');
7458 try f.writeCValue(w, operand_a, .Other);
7459 try w.writeByte('[');
7460 try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
7461 try w.writeByte(']');
73457462 },
73467463 .b_elem => |src_idx| {
7347 try f.writeCValue(writer, operand_b, .Other);
7348 try writer.writeByte('[');
7349 try f.object.dg.renderValue(writer, try pt.intValue(.usize, src_idx), .Other);
7350 try writer.writeByte(']');
7464 try f.writeCValue(w, operand_b, .Other);
7465 try w.writeByte('[');
7466 try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
7467 try w.writeByte(']');
73517468 },
7352 .undef => try f.object.dg.renderUndefValue(writer, elem_ty, .Other),
7469 .undef => try f.object.dg.renderUndefValue(w, elem_ty, .Other),
73537470 }
7354 try writer.writeAll(";\n");
7471 try w.writeByte(';');
7472 try f.object.newline();
73557473 }
73567474
73577475 return local;
......@@ -7366,7 +7484,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
73667484 const operand = try f.resolveInst(reduce.operand);
73677485 try reap(f, inst, &.{reduce.operand});
73687486 const operand_ty = f.typeOf(reduce.operand);
7369 const writer = f.object.writer();
7487 const w = &f.object.code.writer;
73707488
73717489 const use_operator = scalar_ty.bitSize(zcu) <= 64;
73727490 const op: union(enum) {
......@@ -7413,10 +7531,10 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
74137531 // }
74147532
74157533 const accum = try f.allocLocal(inst, scalar_ty);
7416 try f.writeCValue(writer, accum, .Other);
7417 try writer.writeAll(" = ");
7534 try f.writeCValue(w, accum, .Other);
7535 try w.writeAll(" = ");
74187536
7419 try f.object.dg.renderValue(writer, switch (reduce.operation) {
7537 try f.object.dg.renderValue(w, switch (reduce.operation) {
74207538 .Or, .Xor => switch (scalar_ty.zigTypeTag(zcu)) {
74217539 .bool => Value.false,
74227540 .int => try pt.intValue(scalar_ty, 0),
......@@ -7453,42 +7571,44 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
74537571 else => unreachable,
74547572 },
74557573 }, .Other);
7456 try writer.writeAll(";\n");
7574 try w.writeByte(';');
7575 try f.object.newline();
74577576
7458 const v = try Vectorize.start(f, inst, writer, operand_ty);
7459 try f.writeCValue(writer, accum, .Other);
7577 const v = try Vectorize.start(f, inst, w, operand_ty);
7578 try f.writeCValue(w, accum, .Other);
74607579 switch (op) {
74617580 .builtin => |func| {
7462 try writer.print(" = zig_{s}_", .{func.operation});
7463 try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
7464 try writer.writeByte('(');
7465 try f.writeCValue(writer, accum, .FunctionArgument);
7466 try writer.writeAll(", ");
7467 try f.writeCValue(writer, operand, .Other);
7468 try v.elem(f, writer);
7469 try f.object.dg.renderBuiltinInfo(writer, scalar_ty, func.info);
7470 try writer.writeByte(')');
7581 try w.print(" = zig_{s}_", .{func.operation});
7582 try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
7583 try w.writeByte('(');
7584 try f.writeCValue(w, accum, .FunctionArgument);
7585 try w.writeAll(", ");
7586 try f.writeCValue(w, operand, .Other);
7587 try v.elem(f, w);
7588 try f.object.dg.renderBuiltinInfo(w, scalar_ty, func.info);
7589 try w.writeByte(')');
74717590 },
74727591 .infix => |ass| {
7473 try writer.writeAll(ass);
7474 try f.writeCValue(writer, operand, .Other);
7475 try v.elem(f, writer);
7592 try w.writeAll(ass);
7593 try f.writeCValue(w, operand, .Other);
7594 try v.elem(f, w);
74767595 },
74777596 .ternary => |cmp| {
7478 try writer.writeAll(" = ");
7479 try f.writeCValue(writer, accum, .Other);
7480 try writer.writeAll(cmp);
7481 try f.writeCValue(writer, operand, .Other);
7482 try v.elem(f, writer);
7483 try writer.writeAll(" ? ");
7484 try f.writeCValue(writer, accum, .Other);
7485 try writer.writeAll(" : ");
7486 try f.writeCValue(writer, operand, .Other);
7487 try v.elem(f, writer);
7597 try w.writeAll(" = ");
7598 try f.writeCValue(w, accum, .Other);
7599 try w.writeAll(cmp);
7600 try f.writeCValue(w, operand, .Other);
7601 try v.elem(f, w);
7602 try w.writeAll(" ? ");
7603 try f.writeCValue(w, accum, .Other);
7604 try w.writeAll(" : ");
7605 try f.writeCValue(w, operand, .Other);
7606 try v.elem(f, w);
74887607 },
74897608 }
7490 try writer.writeAll(";\n");
7491 try v.end(f, inst, writer);
7609 try w.writeByte(';');
7610 try f.object.newline();
7611 try v.end(f, inst, w);
74927612
74937613 return accum;
74947614}
......@@ -7514,7 +7634,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
75147634 }
75157635 }
75167636
7517 const writer = f.object.writer();
7637 const w = &f.object.code.writer;
75187638 const local = try f.allocLocal(inst, inst_ty);
75197639 switch (ip.indexToKey(inst_ty.toIntern())) {
75207640 inline .array_type, .vector_type => |info, tag| {
......@@ -7522,20 +7642,20 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
75227642 .ctype = try f.ctypeFromType(.fromInterned(info.child), .complete),
75237643 };
75247644 for (resolved_elements, 0..) |element, i| {
7525 try a.restart(f, writer);
7526 try f.writeCValue(writer, local, .Other);
7527 try writer.print("[{d}]", .{i});
7528 try a.assign(f, writer);
7529 try f.writeCValue(writer, element, .Other);
7530 try a.end(f, writer);
7645 try a.restart(f, w);
7646 try f.writeCValue(w, local, .Other);
7647 try w.print("[{d}]", .{i});
7648 try a.assign(f, w);
7649 try f.writeCValue(w, element, .Other);
7650 try a.end(f, w);
75317651 }
75327652 if (tag == .array_type and info.sentinel != .none) {
7533 try a.restart(f, writer);
7534 try f.writeCValue(writer, local, .Other);
7535 try writer.print("[{d}]", .{info.len});
7536 try a.assign(f, writer);
7537 try f.object.dg.renderValue(writer, Value.fromInterned(info.sentinel), .Other);
7538 try a.end(f, writer);
7653 try a.restart(f, w);
7654 try f.writeCValue(w, local, .Other);
7655 try w.print("[{d}]", .{info.len});
7656 try a.assign(f, w);
7657 try f.object.dg.renderValue(w, Value.fromInterned(info.sentinel), .Other);
7658 try a.end(f, w);
75397659 }
75407660 },
75417661 .struct_type => {
......@@ -7547,19 +7667,19 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
75477667 const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
75487668 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
75497669
7550 const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete));
7551 try f.writeCValueMember(writer, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name|
7670 const a = try Assignment.start(f, w, try f.ctypeFromType(field_ty, .complete));
7671 try f.writeCValueMember(w, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name|
75527672 .{ .identifier = field_name.toSlice(ip) }
75537673 else
75547674 .{ .field = field_index });
7555 try a.assign(f, writer);
7556 try f.writeCValue(writer, resolved_elements[field_index], .Other);
7557 try a.end(f, writer);
7675 try a.assign(f, w);
7676 try f.writeCValue(w, resolved_elements[field_index], .Other);
7677 try a.end(f, w);
75587678 }
75597679 },
75607680 .@"packed" => {
7561 try f.writeCValue(writer, local, .Other);
7562 try writer.writeAll(" = ");
7681 try f.writeCValue(w, local, .Other);
7682 try w.writeAll(" = ");
75637683
75647684 const backing_int_ty: Type = .fromInterned(loaded_struct.backingIntTypeUnordered(ip));
75657685 const int_info = backing_int_ty.intInfo(zcu);
......@@ -7575,9 +7695,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
75757695 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
75767696
75777697 if (!empty) {
7578 try writer.writeAll("zig_or_");
7579 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
7580 try writer.writeByte('(');
7698 try w.writeAll("zig_or_");
7699 try f.object.dg.renderTypeForBuiltinFnName(w, inst_ty);
7700 try w.writeByte('(');
75817701 }
75827702 empty = false;
75837703 }
......@@ -7587,57 +7707,58 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
75877707 const field_ty = inst_ty.fieldType(field_index, zcu);
75887708 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
75897709
7590 if (!empty) try writer.writeAll(", ");
7710 if (!empty) try w.writeAll(", ");
75917711 // TODO: Skip this entire shift if val is 0?
7592 try writer.writeAll("zig_shlw_");
7593 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
7594 try writer.writeByte('(');
7712 try w.writeAll("zig_shlw_");
7713 try f.object.dg.renderTypeForBuiltinFnName(w, inst_ty);
7714 try w.writeByte('(');
75957715
75967716 if (field_ty.isAbiInt(zcu)) {
7597 try writer.writeAll("zig_and_");
7598 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
7599 try writer.writeByte('(');
7717 try w.writeAll("zig_and_");
7718 try f.object.dg.renderTypeForBuiltinFnName(w, inst_ty);
7719 try w.writeByte('(');
76007720 }
76017721
76027722 if (inst_ty.isAbiInt(zcu) and (field_ty.isAbiInt(zcu) or field_ty.isPtrAtRuntime(zcu))) {
7603 try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument);
7723 try f.renderIntCast(w, inst_ty, element, .{}, field_ty, .FunctionArgument);
76047724 } else {
7605 try writer.writeByte('(');
7606 try f.renderType(writer, inst_ty);
7607 try writer.writeByte(')');
7725 try w.writeByte('(');
7726 try f.renderType(w, inst_ty);
7727 try w.writeByte(')');
76087728 if (field_ty.isPtrAtRuntime(zcu)) {
7609 try writer.writeByte('(');
7610 try f.renderType(writer, switch (int_info.signedness) {
7729 try w.writeByte('(');
7730 try f.renderType(w, switch (int_info.signedness) {
76117731 .unsigned => .usize,
76127732 .signed => .isize,
76137733 });
7614 try writer.writeByte(')');
7734 try w.writeByte(')');
76157735 }
7616 try f.writeCValue(writer, element, .Other);
7736 try f.writeCValue(w, element, .Other);
76177737 }
76187738
76197739 if (field_ty.isAbiInt(zcu)) {
7620 try writer.writeAll(", ");
7740 try w.writeAll(", ");
76217741 const field_int_info = field_ty.intInfo(zcu);
76227742 const field_mask = if (int_info.signedness == .signed and int_info.bits == field_int_info.bits)
76237743 try pt.intValue(backing_int_ty, -1)
76247744 else
76257745 try (try pt.intType(.unsigned, field_int_info.bits)).maxIntScalar(pt, backing_int_ty);
7626 try f.object.dg.renderValue(writer, field_mask, .FunctionArgument);
7627 try writer.writeByte(')');
7746 try f.object.dg.renderValue(w, field_mask, .FunctionArgument);
7747 try w.writeByte(')');
76287748 }
76297749
7630 try writer.print(", {}", .{
7631 try f.fmtIntLiteral(try pt.intValue(bit_offset_ty, bit_offset)),
7750 try w.print(", {f}", .{
7751 try f.fmtIntLiteralDec(try pt.intValue(bit_offset_ty, bit_offset)),
76327752 });
7633 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits);
7634 try writer.writeByte(')');
7635 if (!empty) try writer.writeByte(')');
7753 try f.object.dg.renderBuiltinInfo(w, inst_ty, .bits);
7754 try w.writeByte(')');
7755 if (!empty) try w.writeByte(')');
76367756
76377757 bit_offset += field_ty.bitSize(zcu);
76387758 empty = false;
76397759 }
7640 try writer.writeAll(";\n");
7760 try w.writeByte(';');
7761 try f.object.newline();
76417762 },
76427763 }
76437764 },
......@@ -7646,11 +7767,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
76467767 const field_ty: Type = .fromInterned(tuple_info.types.get(ip)[field_index]);
76477768 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
76487769
7649 const a = try Assignment.start(f, writer, try f.ctypeFromType(field_ty, .complete));
7650 try f.writeCValueMember(writer, local, .{ .field = field_index });
7651 try a.assign(f, writer);
7652 try f.writeCValue(writer, resolved_elements[field_index], .Other);
7653 try a.end(f, writer);
7770 const a = try Assignment.start(f, w, try f.ctypeFromType(field_ty, .complete));
7771 try f.writeCValueMember(w, local, .{ .field = field_index });
7772 try a.assign(f, w);
7773 try f.writeCValue(w, resolved_elements[field_index], .Other);
7774 try a.end(f, w);
76547775 },
76557776 else => unreachable,
76567777 }
......@@ -7672,7 +7793,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
76727793 const payload = try f.resolveInst(extra.init);
76737794 try reap(f, inst, &.{extra.init});
76747795
7675 const writer = f.object.writer();
7796 const w = &f.object.code.writer;
76767797 const local = try f.allocLocal(inst, union_ty);
76777798 if (loaded_union.flagsUnordered(ip).layout == .@"packed") return f.moveCValue(inst, union_ty, payload);
76787799
......@@ -7682,20 +7803,20 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
76827803 const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
76837804 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
76847805
7685 const a = try Assignment.start(f, writer, try f.ctypeFromType(tag_ty, .complete));
7686 try f.writeCValueMember(writer, local, .{ .identifier = "tag" });
7687 try a.assign(f, writer);
7688 try writer.print("{}", .{try f.fmtIntLiteral(try tag_val.intFromEnum(tag_ty, pt))});
7689 try a.end(f, writer);
7806 const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));
7807 try f.writeCValueMember(w, local, .{ .identifier = "tag" });
7808 try a.assign(f, w);
7809 try w.print("{f}", .{try f.fmtIntLiteralDec(try tag_val.intFromEnum(tag_ty, pt))});
7810 try a.end(f, w);
76907811 }
76917812 break :field .{ .payload_identifier = field_name.toSlice(ip) };
76927813 } else .{ .identifier = field_name.toSlice(ip) };
76937814
7694 const a = try Assignment.start(f, writer, try f.ctypeFromType(payload_ty, .complete));
7695 try f.writeCValueMember(writer, local, field);
7696 try a.assign(f, writer);
7697 try f.writeCValue(writer, payload, .Other);
7698 try a.end(f, writer);
7815 const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete));
7816 try f.writeCValueMember(w, local, field);
7817 try a.assign(f, w);
7818 try f.writeCValue(w, payload, .Other);
7819 try a.end(f, w);
76997820 return local;
77007821}
77017822
......@@ -7708,15 +7829,16 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
77087829 const ptr = try f.resolveInst(prefetch.ptr);
77097830 try reap(f, inst, &.{prefetch.ptr});
77107831
7711 const writer = f.object.writer();
7832 const w = &f.object.code.writer;
77127833 switch (prefetch.cache) {
77137834 .data => {
7714 try writer.writeAll("zig_prefetch(");
7835 try w.writeAll("zig_prefetch(");
77157836 if (ptr_ty.isSlice(zcu))
7716 try f.writeCValueMember(writer, ptr, .{ .identifier = "ptr" })
7837 try f.writeCValueMember(w, ptr, .{ .identifier = "ptr" })
77177838 else
7718 try f.writeCValue(writer, ptr, .FunctionArgument);
7719 try writer.print(", {d}, {d});\n", .{ @intFromEnum(prefetch.rw), prefetch.locality });
7839 try f.writeCValue(w, ptr, .FunctionArgument);
7840 try w.print(", {d}, {d});", .{ @intFromEnum(prefetch.rw), prefetch.locality });
7841 try f.object.newline();
77207842 },
77217843 // The available prefetch intrinsics do not accept a cache argument; only
77227844 // address, rw, and locality.
......@@ -7729,13 +7851,14 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
77297851fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
77307852 const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
77317853
7732 const writer = f.object.writer();
7854 const w = &f.object.code.writer;
77337855 const inst_ty = f.typeOfIndex(inst);
77347856 const local = try f.allocLocal(inst, inst_ty);
7735 try f.writeCValue(writer, local, .Other);
7857 try f.writeCValue(w, local, .Other);
77367858
7737 try writer.writeAll(" = ");
7738 try writer.print("zig_wasm_memory_size({d});\n", .{pl_op.payload});
7859 try w.writeAll(" = ");
7860 try w.print("zig_wasm_memory_size({d});", .{pl_op.payload});
7861 try f.object.newline();
77397862
77407863 return local;
77417864}
......@@ -7743,17 +7866,18 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
77437866fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
77447867 const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
77457868
7746 const writer = f.object.writer();
7869 const w = &f.object.code.writer;
77477870 const inst_ty = f.typeOfIndex(inst);
77487871 const operand = try f.resolveInst(pl_op.operand);
77497872 try reap(f, inst, &.{pl_op.operand});
77507873 const local = try f.allocLocal(inst, inst_ty);
7751 try f.writeCValue(writer, local, .Other);
7874 try f.writeCValue(w, local, .Other);
77527875
7753 try writer.writeAll(" = ");
7754 try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload});
7755 try f.writeCValue(writer, operand, .FunctionArgument);
7756 try writer.writeAll(");\n");
7876 try w.writeAll(" = ");
7877 try w.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload});
7878 try f.writeCValue(w, operand, .FunctionArgument);
7879 try w.writeAll(");");
7880 try f.object.newline();
77577881 return local;
77587882}
77597883
......@@ -7771,36 +7895,38 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
77717895 const inst_ty = f.typeOfIndex(inst);
77727896 const inst_scalar_ty = inst_ty.scalarType(zcu);
77737897
7774 const writer = f.object.writer();
7898 const w = &f.object.code.writer;
77757899 const local = try f.allocLocal(inst, inst_ty);
7776 const v = try Vectorize.start(f, inst, writer, inst_ty);
7777 try f.writeCValue(writer, local, .Other);
7778 try v.elem(f, writer);
7779 try writer.writeAll(" = zig_fma_");
7780 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_scalar_ty);
7781 try writer.writeByte('(');
7782 try f.writeCValue(writer, mulend1, .FunctionArgument);
7783 try v.elem(f, writer);
7784 try writer.writeAll(", ");
7785 try f.writeCValue(writer, mulend2, .FunctionArgument);
7786 try v.elem(f, writer);
7787 try writer.writeAll(", ");
7788 try f.writeCValue(writer, addend, .FunctionArgument);
7789 try v.elem(f, writer);
7790 try writer.writeAll(");\n");
7791 try v.end(f, inst, writer);
7900 const v = try Vectorize.start(f, inst, w, inst_ty);
7901 try f.writeCValue(w, local, .Other);
7902 try v.elem(f, w);
7903 try w.writeAll(" = zig_fma_");
7904 try f.object.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty);
7905 try w.writeByte('(');
7906 try f.writeCValue(w, mulend1, .FunctionArgument);
7907 try v.elem(f, w);
7908 try w.writeAll(", ");
7909 try f.writeCValue(w, mulend2, .FunctionArgument);
7910 try v.elem(f, w);
7911 try w.writeAll(", ");
7912 try f.writeCValue(w, addend, .FunctionArgument);
7913 try v.elem(f, w);
7914 try w.writeAll(");");
7915 try f.object.newline();
7916 try v.end(f, inst, w);
77927917
77937918 return local;
77947919}
77957920
77967921fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
77977922 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
7798 const writer = f.object.writer();
7923 const w = &f.object.code.writer;
77997924 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
7800 try f.writeCValue(writer, local, .Other);
7801 try writer.writeAll(" = ");
7802 try f.object.dg.renderNav(writer, ty_nav.nav, .Other);
7803 try writer.writeAll(";\n");
7925 try f.writeCValue(w, local, .Other);
7926 try w.writeAll(" = ");
7927 try f.object.dg.renderNav(w, ty_nav.nav, .Other);
7928 try w.writeByte(';');
7929 try f.object.newline();
78047930 return local;
78057931}
78067932
......@@ -7812,15 +7938,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
78127938 const function_info = (try f.ctypeFromType(function_ty, .complete)).info(&f.object.dg.ctype_pool).function;
78137939 assert(function_info.varargs);
78147940
7815 const writer = f.object.writer();
7941 const w = &f.object.code.writer;
78167942 const local = try f.allocLocal(inst, inst_ty);
7817 try writer.writeAll("va_start(*(va_list *)&");
7818 try f.writeCValue(writer, local, .Other);
7943 try w.writeAll("va_start(*(va_list *)&");
7944 try f.writeCValue(w, local, .Other);
78197945 if (function_info.param_ctypes.len > 0) {
7820 try writer.writeAll(", ");
7821 try f.writeCValue(writer, .{ .arg = function_info.param_ctypes.len - 1 }, .FunctionArgument);
7946 try w.writeAll(", ");
7947 try f.writeCValue(w, .{ .arg = function_info.param_ctypes.len - 1 }, .FunctionArgument);
78227948 }
7823 try writer.writeAll(");\n");
7949 try w.writeAll(");");
7950 try f.object.newline();
78247951 return local;
78257952}
78267953
......@@ -7831,14 +7958,15 @@ fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
78317958 const va_list = try f.resolveInst(ty_op.operand);
78327959 try reap(f, inst, &.{ty_op.operand});
78337960
7834 const writer = f.object.writer();
7961 const w = &f.object.code.writer;
78357962 const local = try f.allocLocal(inst, inst_ty);
7836 try f.writeCValue(writer, local, .Other);
7837 try writer.writeAll(" = va_arg(*(va_list *)");
7838 try f.writeCValue(writer, va_list, .Other);
7839 try writer.writeAll(", ");
7840 try f.renderType(writer, ty_op.ty.toType());
7841 try writer.writeAll(");\n");
7963 try f.writeCValue(w, local, .Other);
7964 try w.writeAll(" = va_arg(*(va_list *)");
7965 try f.writeCValue(w, va_list, .Other);
7966 try w.writeAll(", ");
7967 try f.renderType(w, ty_op.ty.toType());
7968 try w.writeAll(");");
7969 try f.object.newline();
78427970 return local;
78437971}
78447972
......@@ -7848,10 +7976,11 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
78487976 const va_list = try f.resolveInst(un_op);
78497977 try reap(f, inst, &.{un_op});
78507978
7851 const writer = f.object.writer();
7852 try writer.writeAll("va_end(*(va_list *)");
7853 try f.writeCValue(writer, va_list, .Other);
7854 try writer.writeAll(");\n");
7979 const w = &f.object.code.writer;
7980 try w.writeAll("va_end(*(va_list *)");
7981 try f.writeCValue(w, va_list, .Other);
7982 try w.writeAll(");");
7983 try f.object.newline();
78557984 return .none;
78567985}
78577986
......@@ -7862,13 +7991,14 @@ fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
78627991 const va_list = try f.resolveInst(ty_op.operand);
78637992 try reap(f, inst, &.{ty_op.operand});
78647993
7865 const writer = f.object.writer();
7994 const w = &f.object.code.writer;
78667995 const local = try f.allocLocal(inst, inst_ty);
7867 try writer.writeAll("va_copy(*(va_list *)&");
7868 try f.writeCValue(writer, local, .Other);
7869 try writer.writeAll(", *(va_list *)");
7870 try f.writeCValue(writer, va_list, .Other);
7871 try writer.writeAll(");\n");
7996 try w.writeAll("va_copy(*(va_list *)&");
7997 try f.writeCValue(w, local, .Other);
7998 try w.writeAll(", *(va_list *)");
7999 try f.writeCValue(w, va_list, .Other);
8000 try w.writeAll(");");
8001 try f.object.newline();
78728002 return local;
78738003}
78748004
......@@ -7883,7 +8013,7 @@ fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
78838013 };
78848014}
78858015
7886fn writeMemoryOrder(w: anytype, order: std.builtin.AtomicOrder) !void {
8016fn writeMemoryOrder(w: *Writer, order: std.builtin.AtomicOrder) !void {
78878017 return w.writeAll(toMemoryOrder(order));
78888018}
78898019
......@@ -7970,93 +8100,6 @@ fn toAtomicRmwSuffix(order: std.builtin.AtomicRmwOp) []const u8 {
79708100 };
79718101}
79728102
7973const ArrayListWriter = ErrorOnlyGenericWriter(std.ArrayList(u8).Writer.Error);
7974
7975fn arrayListWriter(list: *std.ArrayList(u8)) ArrayListWriter {
7976 return .{ .context = .{
7977 .context = list,
7978 .writeFn = struct {
7979 fn write(context: *const anyopaque, bytes: []const u8) anyerror!usize {
7980 const l: *std.ArrayList(u8) = @alignCast(@constCast(@ptrCast(context)));
7981 return l.writer().write(bytes);
7982 }
7983 }.write,
7984 } };
7985}
7986
7987fn IndentWriter(comptime UnderlyingWriter: type) type {
7988 return struct {
7989 const Self = @This();
7990 pub const Error = UnderlyingWriter.Error;
7991 pub const Writer = ErrorOnlyGenericWriter(Error);
7992
7993 pub const indent_delta = 1;
7994
7995 underlying_writer: UnderlyingWriter,
7996 indent_count: usize = 0,
7997 current_line_empty: bool = true,
7998
7999 pub fn writer(self: *Self) Writer {
8000 return .{ .context = .{
8001 .context = self,
8002 .writeFn = writeAny,
8003 } };
8004 }
8005
8006 pub fn write(self: *Self, bytes: []const u8) Error!usize {
8007 if (bytes.len == 0) return 0;
8008
8009 const current_indent = self.indent_count * Self.indent_delta;
8010 if (self.current_line_empty and current_indent > 0) {
8011 try self.underlying_writer.writeByteNTimes(' ', current_indent);
8012 }
8013 self.current_line_empty = false;
8014
8015 return self.writeNoIndent(bytes);
8016 }
8017
8018 fn writeAny(context: *const anyopaque, bytes: []const u8) anyerror!usize {
8019 const self: *Self = @alignCast(@constCast(@ptrCast(context)));
8020 return self.write(bytes);
8021 }
8022
8023 pub fn insertNewline(self: *Self) Error!void {
8024 _ = try self.writeNoIndent("\n");
8025 }
8026
8027 pub fn pushIndent(self: *Self) void {
8028 self.indent_count += 1;
8029 }
8030
8031 pub fn popIndent(self: *Self) void {
8032 assert(self.indent_count != 0);
8033 self.indent_count -= 1;
8034 }
8035
8036 fn writeNoIndent(self: *Self, bytes: []const u8) Error!usize {
8037 if (bytes.len == 0) return 0;
8038
8039 try self.underlying_writer.writeAll(bytes);
8040 if (bytes[bytes.len - 1] == '\n') {
8041 self.current_line_empty = true;
8042 }
8043 return bytes.len;
8044 }
8045 };
8046}
8047
8048/// A wrapper around `std.io.AnyWriter` that maintains a generic error set while
8049/// erasing the rest of the implementation. This is intended to avoid duplicate
8050/// generic instantiations for writer types which share the same error set, while
8051/// maintaining ease of error handling.
8052fn ErrorOnlyGenericWriter(comptime Error: type) type {
8053 return std.io.GenericWriter(std.io.AnyWriter, Error, struct {
8054 fn write(context: std.io.AnyWriter, bytes: []const u8) Error!usize {
8055 return @errorCast(context.write(bytes));
8056 }
8057 }.write);
8058}
8059
80608103fn toCIntBits(zig_bits: u32) ?u32 {
80618104 for (&[_]u8{ 8, 16, 32, 64, 128 }) |c_bits| {
80628105 if (zig_bits <= c_bits) {
......@@ -8111,7 +8154,12 @@ fn compareOperatorC(operator: std.math.CompareOperator) []const u8 {
81118154 };
81128155}
81138156
8114fn StringLiteral(comptime WriterType: type) type {
8157const StringLiteral = struct {
8158 len: usize,
8159 cur_len: usize,
8160 w: *Writer,
8161 first: bool,
8162
81158163 // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal,
81168164 // regardless of the length of the string literal initializing it. Array initializer syntax is
81178165 // used instead.
......@@ -8123,99 +8171,116 @@ fn StringLiteral(comptime WriterType: type) type {
81238171 const max_char_len = 4;
81248172 const max_literal_len = @min(16380 - max_char_len, 4095);
81258173
8126 return struct {
8127 len: u64,
8128 cur_len: u64 = 0,
8129 counting_writer: std.io.CountingWriter(WriterType),
8130
8131 pub const Error = WriterType.Error;
8132
8133 const Self = @This();
8174 fn init(w: *Writer, len: usize) StringLiteral {
8175 return .{
8176 .cur_len = 0,
8177 .len = len,
8178 .w = w,
8179 .first = true,
8180 };
8181 }
81348182
8135 pub fn start(self: *Self) Error!void {
8136 const writer = self.counting_writer.writer();
8137 if (self.len <= max_string_initializer_len) {
8138 try writer.writeByte('\"');
8139 } else {
8140 try writer.writeByte('{');
8141 }
8183 pub fn start(sl: *StringLiteral) Writer.Error!void {
8184 if (sl.len <= max_string_initializer_len) {
8185 try sl.w.writeByte('\"');
8186 } else {
8187 try sl.w.writeByte('{');
81428188 }
8189 }
81438190
8144 pub fn end(self: *Self) Error!void {
8145 const writer = self.counting_writer.writer();
8146 if (self.len <= max_string_initializer_len) {
8147 try writer.writeByte('\"');
8148 } else {
8149 try writer.writeByte('}');
8150 }
8191 pub fn end(sl: *StringLiteral) Writer.Error!void {
8192 if (sl.len <= max_string_initializer_len) {
8193 try sl.w.writeByte('\"');
8194 } else {
8195 try sl.w.writeByte('}');
81518196 }
8197 }
81528198
8153 fn writeStringLiteralChar(writer: anytype, c: u8) !void {
8154 switch (c) {
8155 7 => try writer.writeAll("\\a"),
8156 8 => try writer.writeAll("\\b"),
8157 '\t' => try writer.writeAll("\\t"),
8158 '\n' => try writer.writeAll("\\n"),
8159 11 => try writer.writeAll("\\v"),
8160 12 => try writer.writeAll("\\f"),
8161 '\r' => try writer.writeAll("\\r"),
8162 '"', '\'', '?', '\\' => try writer.print("\\{c}", .{c}),
8163 else => switch (c) {
8164 ' '...'~' => try writer.writeByte(c),
8165 else => try writer.print("\\{o:0>3}", .{c}),
8166 },
8167 }
8199 fn writeStringLiteralChar(sl: *StringLiteral, c: u8) Writer.Error!usize {
8200 const w = sl.w;
8201 switch (c) {
8202 7 => {
8203 try w.writeAll("\\a");
8204 return 2;
8205 },
8206 8 => {
8207 try w.writeAll("\\b");
8208 return 2;
8209 },
8210 '\t' => {
8211 try w.writeAll("\\t");
8212 return 2;
8213 },
8214 '\n' => {
8215 try w.writeAll("\\n");
8216 return 2;
8217 },
8218 11 => {
8219 try w.writeAll("\\v");
8220 return 2;
8221 },
8222 12 => {
8223 try w.writeAll("\\f");
8224 return 2;
8225 },
8226 '\r' => {
8227 try w.writeAll("\\r");
8228 return 2;
8229 },
8230 '"', '\'', '?', '\\' => {
8231 try w.print("\\{c}", .{c});
8232 return 2;
8233 },
8234 ' '...'!', '#'...'&', '('...'>', '@'...'[', ']'...'~' => {
8235 try w.writeByte(c);
8236 return 1;
8237 },
8238 else => {
8239 var buf: [4]u8 = undefined;
8240 const printed = std.fmt.bufPrint(&buf, "\\{o:0>3}", .{c}) catch unreachable;
8241 try w.writeAll(printed);
8242 return printed.len;
8243 },
81688244 }
8245 }
81698246
8170 pub fn writeChar(self: *Self, c: u8) Error!void {
8171 const writer = self.counting_writer.writer();
8172 if (self.len <= max_string_initializer_len) {
8173 if (self.cur_len == 0 and self.counting_writer.bytes_written > 1)
8174 try writer.writeAll("\"\"");
8175
8176 const len = self.counting_writer.bytes_written;
8177 try writeStringLiteralChar(writer, c);
8247 pub fn writeChar(sl: *StringLiteral, c: u8) Writer.Error!void {
8248 if (sl.len <= max_string_initializer_len) {
8249 if (sl.cur_len == 0 and !sl.first) try sl.w.writeAll("\"\"");
81788250
8179 const char_length = self.counting_writer.bytes_written - len;
8180 assert(char_length <= max_char_len);
8181 self.cur_len += char_length;
8251 const char_len = try sl.writeStringLiteralChar(c);
8252 assert(char_len <= max_char_len);
8253 sl.cur_len += char_len;
81828254
8183 if (self.cur_len >= max_literal_len) self.cur_len = 0;
8184 } else {
8185 if (self.counting_writer.bytes_written > 1) try writer.writeByte(',');
8186 try writer.print("'\\x{x}'", .{c});
8255 if (sl.cur_len >= max_literal_len) {
8256 sl.cur_len = 0;
8257 sl.first = false;
81878258 }
8259 } else {
8260 if (!sl.first) try sl.w.writeByte(',');
8261 var buf: [6]u8 = undefined;
8262 const printed = std.fmt.bufPrint(&buf, "'\\x{x}'", .{c}) catch unreachable;
8263 try sl.w.writeAll(printed);
8264 sl.cur_len += printed.len;
8265 sl.first = false;
81888266 }
8189 };
8190}
8191
8192fn stringLiteral(
8193 child_stream: anytype,
8194 len: u64,
8195) StringLiteral(@TypeOf(child_stream)) {
8196 return .{
8197 .len = len,
8198 .counting_writer = std.io.countingWriter(child_stream),
8199 };
8200}
8267 }
8268};
82018269
8202const FormatStringContext = struct { str: []const u8, sentinel: ?u8 };
8203fn formatStringLiteral(
8204 data: FormatStringContext,
8205 comptime fmt: []const u8,
8206 _: std.fmt.FormatOptions,
8207 writer: anytype,
8208) @TypeOf(writer).Error!void {
8209 if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt);
8270const FormatStringContext = struct {
8271 str: []const u8,
8272 sentinel: ?u8,
8273};
82108274
8211 var literal = stringLiteral(writer, data.str.len + @intFromBool(data.sentinel != null));
8275fn formatStringLiteral(data: FormatStringContext, w: *std.io.Writer) std.io.Writer.Error!void {
8276 var literal: StringLiteral = .init(w, data.str.len + @intFromBool(data.sentinel != null));
82128277 try literal.start();
82138278 for (data.str) |c| try literal.writeChar(c);
82148279 if (data.sentinel) |sentinel| if (sentinel != 0) try literal.writeChar(sentinel);
82158280 try literal.end();
82168281}
82178282
8218fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Formatter(formatStringLiteral) {
8283fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Formatter(FormatStringContext, formatStringLiteral) {
82198284 return .{ .data = .{ .str = str, .sentinel = sentinel } };
82208285}
82218286
......@@ -8231,13 +8296,10 @@ const FormatIntLiteralContext = struct {
82318296 kind: CType.Kind,
82328297 ctype: CType,
82338298 val: Value,
8299 base: u8,
8300 case: std.fmt.Case,
82348301};
8235fn formatIntLiteral(
8236 data: FormatIntLiteralContext,
8237 comptime fmt: []const u8,
8238 options: std.fmt.FormatOptions,
8239 writer: anytype,
8240) @TypeOf(writer).Error!void {
8302fn formatIntLiteral(data: FormatIntLiteralContext, w: *std.io.Writer) std.io.Writer.Error!void {
82418303 const pt = data.dg.pt;
82428304 const zcu = pt.zcu;
82438305 const target = &data.dg.mod.resolved_target.result;
......@@ -8262,7 +8324,7 @@ fn formatIntLiteral(
82628324
82638325 var int_buf: Value.BigIntSpace = undefined;
82648326 const int = if (data.val.isUndefDeep(zcu)) blk: {
8265 undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits));
8327 undef_limbs = allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits)) catch return error.WriteFailed;
82668328 @memset(undef_limbs, undefPattern(BigIntLimb));
82678329
82688330 var undef_int = BigInt.Mutable{
......@@ -8280,7 +8342,7 @@ fn formatIntLiteral(
82808342 const one = BigInt.Mutable.init(&one_limbs, 1).toConst();
82818343
82828344 var wrap = BigInt.Mutable{
8283 .limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(c_bits)),
8345 .limbs = allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(c_bits)) catch return error.WriteFailed,
82848346 .len = undefined,
82858347 .positive = undefined,
82868348 };
......@@ -8317,46 +8379,29 @@ fn formatIntLiteral(
83178379 if (c_limb_info.count == 1) {
83188380 if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or
83198381 data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits))
8320 return writer.print("{s}_{s}", .{
8321 data.ctype.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{
8382 return w.print("{s}_{s}", .{
8383 data.ctype.getStandardDefineAbbrev() orelse return w.print("zig_{s}Int_{c}{d}", .{
83228384 if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits,
83238385 }),
83248386 if (int.positive) "MAX" else "MIN",
83258387 });
83268388
8327 if (!int.positive) try writer.writeByte('-');
8328 try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool);
8389 if (!int.positive) try w.writeByte('-');
8390 try data.ctype.renderLiteralPrefix(w, data.kind, ctype_pool);
83298391
8330 const style: struct { base: u8, case: std.fmt.Case = undefined } = switch (fmt.len) {
8331 0 => .{ .base = 10 },
8332 1 => switch (fmt[0]) {
8333 'b' => style: {
8334 try writer.writeAll("0b");
8335 break :style .{ .base = 2 };
8336 },
8337 'o' => style: {
8338 try writer.writeByte('0');
8339 break :style .{ .base = 8 };
8340 },
8341 'd' => .{ .base = 10 },
8342 'x', 'X' => |base| style: {
8343 try writer.writeAll("0x");
8344 break :style .{ .base = 16, .case = switch (base) {
8345 'x' => .lower,
8346 'X' => .upper,
8347 else => unreachable,
8348 } };
8349 },
8350 else => @compileError("Invalid fmt: " ++ fmt),
8351 },
8352 else => @compileError("Invalid fmt: " ++ fmt),
8353 };
8354
8355 const string = try int.abs().toStringAlloc(allocator, style.base, style.case);
8392 switch (data.base) {
8393 2 => try w.writeAll("0b"),
8394 8 => try w.writeByte('0'),
8395 10 => {},
8396 16 => try w.writeAll("0x"),
8397 else => unreachable,
8398 }
8399 const string = int.abs().toStringAlloc(allocator, data.base, data.case) catch
8400 return error.WriteFailed;
83568401 defer allocator.free(string);
8357 try writer.writeAll(string);
8402 try w.writeAll(string);
83588403 } else {
8359 try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool);
8404 try data.ctype.renderLiteralPrefix(w, data.kind, ctype_pool);
83608405 wrap.truncate(int, .unsigned, c_bits);
83618406 @memset(wrap.limbs[wrap.len..], 0);
83628407 wrap.len = wrap.limbs.len;
......@@ -8399,17 +8444,20 @@ fn formatIntLiteral(
83998444 c_limb_ctype = c_limb_info.ctype;
84008445 }
84018446
8402 if (limb_offset > 0) try writer.writeAll(", ");
8447 if (limb_offset > 0) try w.writeAll(", ");
84038448 try formatIntLiteral(.{
84048449 .dg = data.dg,
84058450 .int_info = c_limb_int_info,
84068451 .kind = data.kind,
84078452 .ctype = c_limb_ctype,
8408 .val = try pt.intValue_big(.comptime_int, c_limb_mut.toConst()),
8409 }, fmt, options, writer);
8453 .val = pt.intValue_big(.comptime_int, c_limb_mut.toConst()) catch
8454 return error.WriteFailed,
8455 .base = data.base,
8456 .case = data.case,
8457 }, w);
84108458 }
84118459 }
8412 try data.ctype.renderLiteralSuffix(writer, ctype_pool);
8460 try data.ctype.renderLiteralSuffix(w, ctype_pool);
84138461}
84148462
84158463const Materialize = struct {
......@@ -8423,8 +8471,8 @@ const Materialize = struct {
84238471 } };
84248472 }
84258473
8426 pub fn mat(self: Materialize, f: *Function, writer: anytype) !void {
8427 try f.writeCValue(writer, self.local, .Other);
8474 pub fn mat(self: Materialize, f: *Function, w: *Writer) !void {
8475 try f.writeCValue(w, self.local, .Other);
84288476 }
84298477
84308478 pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void {
......@@ -8435,36 +8483,37 @@ const Materialize = struct {
84358483const Assignment = struct {
84368484 ctype: CType,
84378485
8438 pub fn start(f: *Function, writer: anytype, ctype: CType) !Assignment {
8486 pub fn start(f: *Function, w: *Writer, ctype: CType) !Assignment {
84398487 const self: Assignment = .{ .ctype = ctype };
8440 try self.restart(f, writer);
8488 try self.restart(f, w);
84418489 return self;
84428490 }
84438491
8444 pub fn restart(self: Assignment, f: *Function, writer: anytype) !void {
8492 pub fn restart(self: Assignment, f: *Function, w: *Writer) !void {
84458493 switch (self.strategy(f)) {
84468494 .assign => {},
8447 .memcpy => try writer.writeAll("memcpy("),
8495 .memcpy => try w.writeAll("memcpy("),
84488496 }
84498497 }
84508498
8451 pub fn assign(self: Assignment, f: *Function, writer: anytype) !void {
8499 pub fn assign(self: Assignment, f: *Function, w: *Writer) !void {
84528500 switch (self.strategy(f)) {
8453 .assign => try writer.writeAll(" = "),
8454 .memcpy => try writer.writeAll(", "),
8501 .assign => try w.writeAll(" = "),
8502 .memcpy => try w.writeAll(", "),
84558503 }
84568504 }
84578505
8458 pub fn end(self: Assignment, f: *Function, writer: anytype) !void {
8506 pub fn end(self: Assignment, f: *Function, w: *Writer) !void {
84598507 switch (self.strategy(f)) {
84608508 .assign => {},
84618509 .memcpy => {
8462 try writer.writeAll(", sizeof(");
8463 try f.renderCType(writer, self.ctype);
8464 try writer.writeAll("))");
8510 try w.writeAll(", sizeof(");
8511 try f.renderCType(w, self.ctype);
8512 try w.writeAll("))");
84658513 },
84668514 }
8467 try writer.writeAll(";\n");
8515 try w.writeByte(';');
8516 try f.object.newline();
84688517 }
84698518
84708519 fn strategy(self: Assignment, f: *Function) enum { assign, memcpy } {
......@@ -8478,37 +8527,39 @@ const Assignment = struct {
84788527const Vectorize = struct {
84798528 index: CValue = .none,
84808529
8481 pub fn start(f: *Function, inst: Air.Inst.Index, writer: anytype, ty: Type) !Vectorize {
8530 pub fn start(f: *Function, inst: Air.Inst.Index, w: *Writer, ty: Type) !Vectorize {
84828531 const pt = f.object.dg.pt;
84838532 const zcu = pt.zcu;
84848533 return if (ty.zigTypeTag(zcu) == .vector) index: {
84858534 const local = try f.allocLocal(inst, .usize);
84868535
8487 try writer.writeAll("for (");
8488 try f.writeCValue(writer, local, .Other);
8489 try writer.print(" = {d}; ", .{try f.fmtIntLiteral(.zero_usize)});
8490 try f.writeCValue(writer, local, .Other);
8491 try writer.print(" < {d}; ", .{try f.fmtIntLiteral(try pt.intValue(.usize, ty.vectorLen(zcu)))});
8492 try f.writeCValue(writer, local, .Other);
8493 try writer.print(" += {d}) {{\n", .{try f.fmtIntLiteral(.one_usize)});
8494 f.object.indent_writer.pushIndent();
8536 try w.writeAll("for (");
8537 try f.writeCValue(w, local, .Other);
8538 try w.print(" = {f}; ", .{try f.fmtIntLiteralDec(.zero_usize)});
8539 try f.writeCValue(w, local, .Other);
8540 try w.print(" < {f}; ", .{try f.fmtIntLiteralDec(try pt.intValue(.usize, ty.vectorLen(zcu)))});
8541 try f.writeCValue(w, local, .Other);
8542 try w.print(" += {f}) {{\n", .{try f.fmtIntLiteralDec(.one_usize)});
8543 f.object.indent();
8544 try f.object.newline();
84958545
84968546 break :index .{ .index = local };
84978547 } else .{};
84988548 }
84998549
8500 pub fn elem(self: Vectorize, f: *Function, writer: anytype) !void {
8550 pub fn elem(self: Vectorize, f: *Function, w: *Writer) !void {
85018551 if (self.index != .none) {
8502 try writer.writeByte('[');
8503 try f.writeCValue(writer, self.index, .Other);
8504 try writer.writeByte(']');
8552 try w.writeByte('[');
8553 try f.writeCValue(w, self.index, .Other);
8554 try w.writeByte(']');
85058555 }
85068556 }
85078557
8508 pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, writer: anytype) !void {
8558 pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, w: *Writer) !void {
85098559 if (self.index != .none) {
8510 f.object.indent_writer.popIndent();
8511 try writer.writeAll("}\n");
8560 try f.object.outdent();
8561 try w.writeByte('}');
8562 try f.object.newline();
85128563 try freeLocal(f, inst, self.index.new_local, null);
85138564 }
85148565 }
src/codegen/c/Type.zig+21-25
......@@ -209,7 +209,7 @@ pub fn getStandardDefineAbbrev(ctype: CType) ?[]const u8 {
209209 };
210210}
211211
212pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *const Pool) @TypeOf(writer).Error!void {
212pub fn renderLiteralPrefix(ctype: CType, w: *Writer, kind: Kind, pool: *const Pool) Writer.Error!void {
213213 switch (ctype.info(pool)) {
214214 .basic => |basic_info| switch (basic_info) {
215215 .void => unreachable,
......@@ -224,7 +224,7 @@ pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *con
224224 .uintptr_t,
225225 .intptr_t,
226226 => switch (kind) {
227 else => try writer.print("({s})", .{@tagName(basic_info)}),
227 else => try w.print("({s})", .{@tagName(basic_info)}),
228228 .global => {},
229229 },
230230 .int,
......@@ -246,7 +246,7 @@ pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *con
246246 .int32_t,
247247 .uint64_t,
248248 .int64_t,
249 => try writer.print("{s}_C(", .{ctype.getStandardDefineAbbrev().?}),
249 => try w.print("{s}_C(", .{ctype.getStandardDefineAbbrev().?}),
250250 .zig_u128,
251251 .zig_i128,
252252 .zig_f16,
......@@ -255,7 +255,7 @@ pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *con
255255 .zig_f80,
256256 .zig_f128,
257257 .zig_c_longdouble,
258 => try writer.print("zig_{s}_{s}(", .{
258 => try w.print("zig_{s}_{s}(", .{
259259 switch (kind) {
260260 else => "make",
261261 .global => "init",
......@@ -265,12 +265,12 @@ pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *con
265265 .va_list => unreachable,
266266 _ => unreachable,
267267 },
268 .array, .vector => try writer.writeByte('{'),
268 .array, .vector => try w.writeByte('{'),
269269 else => unreachable,
270270 }
271271}
272272
273pub fn renderLiteralSuffix(ctype: CType, writer: anytype, pool: *const Pool) @TypeOf(writer).Error!void {
273pub fn renderLiteralSuffix(ctype: CType, w: *Writer, pool: *const Pool) Writer.Error!void {
274274 switch (ctype.info(pool)) {
275275 .basic => |basic_info| switch (basic_info) {
276276 .void => unreachable,
......@@ -280,20 +280,20 @@ pub fn renderLiteralSuffix(ctype: CType, writer: anytype, pool: *const Pool) @Ty
280280 .short,
281281 .int,
282282 => {},
283 .long => try writer.writeByte('l'),
284 .@"long long" => try writer.writeAll("ll"),
283 .long => try w.writeByte('l'),
284 .@"long long" => try w.writeAll("ll"),
285285 .@"unsigned char",
286286 .@"unsigned short",
287287 .@"unsigned int",
288 => try writer.writeByte('u'),
288 => try w.writeByte('u'),
289289 .@"unsigned long",
290290 .size_t,
291291 .uintptr_t,
292 => try writer.writeAll("ul"),
293 .@"unsigned long long" => try writer.writeAll("ull"),
294 .float => try writer.writeByte('f'),
292 => try w.writeAll("ul"),
293 .@"unsigned long long" => try w.writeAll("ull"),
294 .float => try w.writeByte('f'),
295295 .double => {},
296 .@"long double" => try writer.writeByte('l'),
296 .@"long double" => try w.writeByte('l'),
297297 .bool,
298298 .ptrdiff_t,
299299 .intptr_t,
......@@ -314,11 +314,11 @@ pub fn renderLiteralSuffix(ctype: CType, writer: anytype, pool: *const Pool) @Ty
314314 .zig_f80,
315315 .zig_f128,
316316 .zig_c_longdouble,
317 => try writer.writeByte(')'),
317 => try w.writeByte(')'),
318318 .va_list => unreachable,
319319 _ => unreachable,
320320 },
321 .array, .vector => try writer.writeByte('}'),
321 .array, .vector => try w.writeByte('}'),
322322 else => unreachable,
323323 }
324324}
......@@ -938,19 +938,13 @@ pub const Pool = struct {
938938 index: String.Index,
939939
940940 const FormatData = struct { string: String, pool: *const Pool };
941 fn format(
942 data: FormatData,
943 comptime fmt_str: []const u8,
944 _: std.fmt.FormatOptions,
945 writer: anytype,
946 ) @TypeOf(writer).Error!void {
947 if (fmt_str.len > 0) @compileError("invalid format string '" ++ fmt_str ++ "'");
941 fn format(data: FormatData, writer: *Writer) Writer.Error!void {
948942 if (data.string.toSlice(data.pool)) |slice|
949943 try writer.writeAll(slice)
950944 else
951945 try writer.print("f{d}", .{@intFromEnum(data.string.index)});
952946 }
953 pub fn fmt(str: String, pool: *const Pool) std.fmt.Formatter(format) {
947 pub fn fmt(str: String, pool: *const Pool) std.fmt.Formatter(FormatData, format) {
954948 return .{ .data = .{ .string = str, .pool = pool } };
955949 }
956950
......@@ -2890,7 +2884,7 @@ pub const Pool = struct {
28902884 comptime fmt_str: []const u8,
28912885 fmt_args: anytype,
28922886 ) !String {
2893 try pool.string_bytes.writer(allocator).print(fmt_str, fmt_args);
2887 try pool.string_bytes.print(allocator, fmt_str, fmt_args);
28942888 return pool.trailingString(allocator);
28952889 }
28962890
......@@ -3281,10 +3275,12 @@ pub const AlignAs = packed struct {
32813275 }
32823276};
32833277
3278const std = @import("std");
32843279const assert = std.debug.assert;
3280const Writer = std.io.Writer;
3281
32853282const CType = @This();
32863283const InternPool = @import("../../InternPool.zig");
32873284const Module = @import("../../Package/Module.zig");
3288const std = @import("std");
32893285const Type = @import("../../Type.zig");
32903286const Zcu = @import("../../Zcu.zig");
src/codegen/llvm.zig+29-19
......@@ -239,12 +239,12 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8
239239 .none,
240240 .windows,
241241 => {},
242 .semver => |ver| try llvm_triple.writer().print("{d}.{d}.{d}", .{
242 .semver => |ver| try llvm_triple.print("{d}.{d}.{d}", .{
243243 ver.min.major,
244244 ver.min.minor,
245245 ver.min.patch,
246246 }),
247 inline .linux, .hurd => |ver| try llvm_triple.writer().print("{d}.{d}.{d}", .{
247 inline .linux, .hurd => |ver| try llvm_triple.print("{d}.{d}.{d}", .{
248248 ver.range.min.major,
249249 ver.range.min.minor,
250250 ver.range.min.patch,
......@@ -295,13 +295,13 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8
295295 .windows,
296296 => {},
297297 inline .hurd, .linux => |ver| if (target.abi.isGnu()) {
298 try llvm_triple.writer().print("{d}.{d}.{d}", .{
298 try llvm_triple.print("{d}.{d}.{d}", .{
299299 ver.glibc.major,
300300 ver.glibc.minor,
301301 ver.glibc.patch,
302302 });
303303 } else if (@TypeOf(ver) == std.Target.Os.LinuxVersionRange and target.abi.isAndroid()) {
304 try llvm_triple.writer().print("{d}", .{ver.android});
304 try llvm_triple.print("{d}", .{ver.android});
305305 },
306306 }
307307
......@@ -746,12 +746,18 @@ pub const Object = struct {
746746 try wip.finish();
747747 }
748748
749 fn genModuleLevelAssembly(object: *Object) !void {
750 const writer = object.builder.setModuleAsm();
749 fn genModuleLevelAssembly(object: *Object) Allocator.Error!void {
750 const b = &object.builder;
751 const gpa = b.gpa;
752 b.module_asm.clearRetainingCapacity();
751753 for (object.pt.zcu.global_assembly.values()) |assembly| {
752 try writer.print("{s}\n", .{assembly});
754 try b.module_asm.ensureUnusedCapacity(gpa, assembly.len + 1);
755 b.module_asm.appendSliceAssumeCapacity(assembly);
756 b.module_asm.appendAssumeCapacity('\n');
757 }
758 if (b.module_asm.getLastOrNull()) |last| {
759 if (last != '\n') try b.module_asm.append(gpa, '\n');
753760 }
754 try object.builder.finishModuleAsm();
755761 }
756762
757763 pub const EmitOptions = struct {
......@@ -939,7 +945,9 @@ pub const Object = struct {
939945 if (std.mem.eql(u8, path, "-")) {
940946 o.builder.dump();
941947 } else {
942 _ = try o.builder.printToFile(path);
948 o.builder.printToFilePath(std.fs.cwd(), path) catch |err| {
949 log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) });
950 };
943951 }
944952 }
945953
......@@ -2486,7 +2494,7 @@ pub const Object = struct {
24862494 var union_name_buf: ?[:0]const u8 = null;
24872495 defer if (union_name_buf) |buf| gpa.free(buf);
24882496 const union_name = if (layout.tag_size == 0) name else name: {
2489 union_name_buf = try std.fmt.allocPrintZ(gpa, "{s}:Payload", .{name});
2497 union_name_buf = try std.fmt.allocPrintSentinel(gpa, "{s}:Payload", .{name}, 0);
24902498 break :name union_name_buf.?;
24912499 };
24922500
......@@ -2680,10 +2688,12 @@ pub const Object = struct {
26802688 }
26812689
26822690 fn allocTypeName(o: *Object, ty: Type) Allocator.Error![:0]const u8 {
2683 var buffer = std.ArrayList(u8).init(o.gpa);
2684 errdefer buffer.deinit();
2685 try ty.print(buffer.writer(), o.pt);
2686 return buffer.toOwnedSliceSentinel(0);
2691 var aw: std.io.Writer.Allocating = .init(o.gpa);
2692 defer aw.deinit();
2693 ty.print(&aw.writer, o.pt) catch |err| switch (err) {
2694 error.WriteFailed => return error.OutOfMemory,
2695 };
2696 return aw.toOwnedSliceSentinel(0);
26872697 }
26882698
26892699 /// If the llvm function does not exist, create it.
......@@ -4482,7 +4492,7 @@ pub const Object = struct {
44824492 const target = &zcu.root_mod.resolved_target.result;
44834493 const function_index = try o.builder.addFunction(
44844494 try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal),
4485 try o.builder.strtabStringFmt("__zig_tag_name_{}", .{enum_type.name.fmt(ip)}),
4495 try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_type.name.fmt(ip)}),
44864496 toLlvmAddressSpace(.generic, target),
44874497 );
44884498
......@@ -4633,7 +4643,7 @@ pub const NavGen = struct {
46334643 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
46344644 if (lib_name.toSlice(ip)) |lib_name_slice| {
46354645 if (!std.mem.eql(u8, lib_name_slice, "c")) {
4636 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
4646 break :decl_name try o.builder.strtabStringFmt("{f}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
46374647 }
46384648 }
46394649 }
......@@ -7472,7 +7482,7 @@ pub const FuncGen = struct {
74727482 llvm_param_types[llvm_param_i] = llvm_elem_ty;
74737483 }
74747484
7475 try llvm_constraints.writer(self.gpa).print(",{d}", .{output_index});
7485 try llvm_constraints.print(self.gpa, ",{d}", .{output_index});
74767486
74777487 // In the case of indirect inputs, LLVM requires the callsite to have
74787488 // an elementtype(<ty>) attribute.
......@@ -7573,7 +7583,7 @@ pub const FuncGen = struct {
75737583 // we should validate the assembly in Sema; by now it is too late
75747584 return self.todo("unknown input or output name: '{s}'", .{name});
75757585 };
7576 try rendered_template.writer().print("{d}", .{index});
7586 try rendered_template.print("{d}", .{index});
75777587 if (byte == ':') {
75787588 try rendered_template.append(':');
75797589 modifier_start = i + 1;
......@@ -10370,7 +10380,7 @@ pub const FuncGen = struct {
1037010380 const target = &zcu.root_mod.resolved_target.result;
1037110381 const function_index = try o.builder.addFunction(
1037210382 try o.builder.fnType(.i1, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal),
10373 try o.builder.strtabStringFmt("__zig_is_named_enum_value_{}", .{enum_type.name.fmt(ip)}),
10383 try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_type.name.fmt(ip)}),
1037410384 toLlvmAddressSpace(.generic, target),
1037510385 );
1037610386
src/codegen/spirv.zig+10-8
......@@ -817,7 +817,7 @@ const NavGen = struct {
817817 const result_ty_id = try self.resolveType(ty, repr);
818818 const ip = &zcu.intern_pool;
819819
820 log.debug("lowering constant: ty = {}, val = {}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) });
820 log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) });
821821 if (val.isUndefDeep(zcu)) {
822822 return self.spv.constUndef(result_ty_id);
823823 }
......@@ -1147,7 +1147,7 @@ const NavGen = struct {
11471147 return result_ptr_id;
11481148 }
11491149
1150 return self.fail("cannot perform pointer cast: '{}' to '{}'", .{
1150 return self.fail("cannot perform pointer cast: '{f}' to '{f}'", .{
11511151 parent_ptr_ty.fmt(pt),
11521152 oac.new_ptr_ty.fmt(pt),
11531153 });
......@@ -1260,10 +1260,12 @@ const NavGen = struct {
12601260
12611261 // Turn a Zig type's name into a cache reference.
12621262 fn resolveTypeName(self: *NavGen, ty: Type) ![]const u8 {
1263 var name = std.ArrayList(u8).init(self.gpa);
1264 defer name.deinit();
1265 try ty.print(name.writer(), self.pt);
1266 return try name.toOwnedSlice();
1263 var aw: std.io.Writer.Allocating = .init(self.gpa);
1264 defer aw.deinit();
1265 ty.print(&aw.writer, self.pt) catch |err| switch (err) {
1266 error.WriteFailed => return error.OutOfMemory,
1267 };
1268 return try aw.toOwnedSlice();
12671269 }
12681270
12691271 /// Create an integer type suitable for storing at least 'bits' bits.
......@@ -1462,7 +1464,7 @@ const NavGen = struct {
14621464 const pt = self.pt;
14631465 const zcu = pt.zcu;
14641466 const ip = &zcu.intern_pool;
1465 log.debug("resolveType: ty = {}", .{ty.fmt(pt)});
1467 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});
14661468 const target = self.spv.target;
14671469
14681470 const section = &self.spv.sections.types_globals_constants;
......@@ -3068,7 +3070,7 @@ const NavGen = struct {
30683070 try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});
30693071 try self.spv.addFunction(spv_decl_index, self.func);
30703072
3071 try self.spv.debugNameFmt(initializer_id, "initializer of {}", .{nav.fqn.fmt(ip)});
3073 try self.spv.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
30723074
30733075 try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpExtInst, .{
30743076 .id_result_type = ptr_ty_id,
src/codegen/spirv/spec.zig+3-7
......@@ -1,6 +1,7 @@
11//! This file is auto-generated by tools/gen_spirv_spec.zig.
22
33const std = @import("std");
4const assert = std.debug.assert;
45
56pub const Version = packed struct(Word) {
67 padding: u8 = 0,
......@@ -18,15 +19,10 @@ pub const IdResult = enum(Word) {
1819 none,
1920 _,
2021
21 pub fn format(
22 self: IdResult,
23 comptime _: []const u8,
24 _: std.fmt.FormatOptions,
25 writer: anytype,
26 ) @TypeOf(writer).Error!void {
22 pub fn format(self: IdResult, writer: *std.io.Writer) std.io.Writer.Error!void {
2723 switch (self) {
2824 .none => try writer.writeAll("(none)"),
29 else => try writer.print("%{}", .{@intFromEnum(self)}),
25 else => try writer.print("%{d}", .{@intFromEnum(self)}),
3026 }
3127 }
3228};
src/crash_report.zig+22-15
......@@ -80,18 +80,19 @@ fn dumpStatusReport() !void {
8080 var fba = std.heap.FixedBufferAllocator.init(&crash_heap);
8181 const allocator = fba.allocator();
8282
83 const stderr = io.getStdErr().writer();
83 var stderr_fw = std.fs.File.stderr().writer(&.{});
84 const stderr = &stderr_fw.interface;
8485 const block: *Sema.Block = anal.block;
8586 const zcu = anal.sema.pt.zcu;
8687
8788 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu) orelse {
8889 const file = zcu.fileByIndex(block.src_base_inst.resolveFile(&zcu.intern_pool));
89 try stderr.print("Analyzing lost instruction in file '{}'. This should not happen!\n\n", .{file.path.fmt(zcu.comp)});
90 try stderr.print("Analyzing lost instruction in file '{f}'. This should not happen!\n\n", .{file.path.fmt(zcu.comp)});
9091 return;
9192 };
9293
9394 try stderr.writeAll("Analyzing ");
94 try stderr.print("Analyzing '{}'\n", .{file.path.fmt(zcu.comp)});
95 try stderr.print("Analyzing '{f}'\n", .{file.path.fmt(zcu.comp)});
9596
9697 print_zir.renderInstructionContext(
9798 allocator,
......@@ -107,7 +108,7 @@ fn dumpStatusReport() !void {
107108 };
108109 try stderr.print(
109110 \\ For full context, use the command
110 \\ zig ast-check -t {}
111 \\ zig ast-check -t {f}
111112 \\
112113 \\
113114 , .{file.path.fmt(zcu.comp)});
......@@ -116,7 +117,7 @@ fn dumpStatusReport() !void {
116117 while (parent) |curr| {
117118 fba.reset();
118119 const cur_block_file = zcu.fileByIndex(curr.block.src_base_inst.resolveFile(&zcu.intern_pool));
119 try stderr.print(" in {}\n", .{cur_block_file.path.fmt(zcu.comp)});
120 try stderr.print(" in {f}\n", .{cur_block_file.path.fmt(zcu.comp)});
120121 _, const cur_block_src_base_node = Zcu.LazySrcLoc.resolveBaseNode(curr.block.src_base_inst, zcu) orelse {
121122 try stderr.writeAll(" > [lost instruction; this should not happen]\n");
122123 parent = curr.parent;
......@@ -139,7 +140,7 @@ fn dumpStatusReport() !void {
139140 parent = curr.parent;
140141 }
141142
142 try stderr.writeAll("\n");
143 try stderr.writeByte('\n');
143144}
144145
145146var crash_heap: [16 * 4096]u8 = undefined;
......@@ -268,11 +269,12 @@ const StackContext = union(enum) {
268269 debug.dumpCurrentStackTrace(ct.ret_addr);
269270 },
270271 .exception => |context| {
271 debug.dumpStackTraceFromBase(context);
272 var stderr_fw = std.fs.File.stderr().writer(&.{});
273 const stderr = &stderr_fw.interface;
274 debug.dumpStackTraceFromBase(context, stderr);
272275 },
273276 .not_supported => {
274 const stderr = io.getStdErr().writer();
275 stderr.writeAll("Stack trace not supported on this platform.\n") catch {};
277 std.fs.File.stderr().writeAll("Stack trace not supported on this platform.\n") catch {};
276278 },
277279 }
278280 }
......@@ -379,7 +381,8 @@ const PanicSwitch = struct {
379381
380382 state.recover_stage = .release_mutex;
381383
382 const stderr = io.getStdErr().writer();
384 var stderr_fw = std.fs.File.stderr().writer(&.{});
385 const stderr = &stderr_fw.interface;
383386 if (builtin.single_threaded) {
384387 stderr.print("panic: ", .{}) catch goTo(releaseMutex, .{state});
385388 } else {
......@@ -406,7 +409,8 @@ const PanicSwitch = struct {
406409 recover(state, trace, stack, msg);
407410
408411 state.recover_stage = .release_mutex;
409 const stderr = io.getStdErr().writer();
412 var stderr_fw = std.fs.File.stderr().writer(&.{});
413 const stderr = &stderr_fw.interface;
410414 stderr.writeAll("\nOriginal Error:\n") catch {};
411415 goTo(reportStack, .{state});
412416 }
......@@ -477,7 +481,8 @@ const PanicSwitch = struct {
477481 recover(state, trace, stack, msg);
478482
479483 state.recover_stage = .silent_abort;
480 const stderr = io.getStdErr().writer();
484 var stderr_fw = std.fs.File.stderr().writer(&.{});
485 const stderr = &stderr_fw.interface;
481486 stderr.writeAll("Aborting...\n") catch {};
482487 goTo(abort, .{});
483488 }
......@@ -505,7 +510,8 @@ const PanicSwitch = struct {
505510 // lower the verbosity, and restore it at the end if we don't panic.
506511 state.recover_verbosity = .message_only;
507512
508 const stderr = io.getStdErr().writer();
513 var stderr_fw = std.fs.File.stderr().writer(&.{});
514 const stderr = &stderr_fw.interface;
509515 stderr.writeAll("\nPanicked during a panic: ") catch {};
510516 stderr.writeAll(msg) catch {};
511517 stderr.writeAll("\nInner panic stack:\n") catch {};
......@@ -519,10 +525,11 @@ const PanicSwitch = struct {
519525 .message_only => {
520526 state.recover_verbosity = .silent;
521527
522 const stderr = io.getStdErr().writer();
528 var stderr_fw = std.fs.File.stderr().writer(&.{});
529 const stderr = &stderr_fw.interface;
523530 stderr.writeAll("\nPanicked while dumping inner panic stack: ") catch {};
524531 stderr.writeAll(msg) catch {};
525 stderr.writeAll("\n") catch {};
532 stderr.writeByte('\n') catch {};
526533
527534 // If we succeed, restore all the way to dumping the stack.
528535 state.recover_verbosity = .message_and_stack;
src/deprecated.zig created+431
......@@ -0,0 +1,431 @@
1//! Deprecated. Stop using this API
2
3const std = @import("std");
4const math = std.math;
5const mem = std.mem;
6const Allocator = mem.Allocator;
7const assert = std.debug.assert;
8const testing = std.testing;
9
10pub fn LinearFifo(comptime T: type) type {
11 return struct {
12 allocator: Allocator,
13 buf: []T,
14 head: usize,
15 count: usize,
16
17 const Self = @This();
18
19 pub fn init(allocator: Allocator) Self {
20 return .{
21 .allocator = allocator,
22 .buf = &.{},
23 .head = 0,
24 .count = 0,
25 };
26 }
27
28 pub fn deinit(self: *Self) void {
29 self.allocator.free(self.buf);
30 self.* = undefined;
31 }
32
33 pub fn realign(self: *Self) void {
34 if (self.buf.len - self.head >= self.count) {
35 mem.copyForwards(T, self.buf[0..self.count], self.buf[self.head..][0..self.count]);
36 self.head = 0;
37 } else {
38 var tmp: [4096 / 2 / @sizeOf(T)]T = undefined;
39
40 while (self.head != 0) {
41 const n = @min(self.head, tmp.len);
42 const m = self.buf.len - n;
43 @memcpy(tmp[0..n], self.buf[0..n]);
44 mem.copyForwards(T, self.buf[0..m], self.buf[n..][0..m]);
45 @memcpy(self.buf[m..][0..n], tmp[0..n]);
46 self.head -= n;
47 }
48 }
49 { // set unused area to undefined
50 const unused = mem.sliceAsBytes(self.buf[self.count..]);
51 @memset(unused, undefined);
52 }
53 }
54
55 /// Reduce allocated capacity to `size`.
56 pub fn shrink(self: *Self, size: usize) void {
57 assert(size >= self.count);
58 self.realign();
59 self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) {
60 error.OutOfMemory => return, // no problem, capacity is still correct then.
61 };
62 }
63
64 /// Ensure that the buffer can fit at least `size` items
65 pub fn ensureTotalCapacity(self: *Self, size: usize) !void {
66 if (self.buf.len >= size) return;
67 self.realign();
68 const new_size = math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory;
69 self.buf = try self.allocator.realloc(self.buf, new_size);
70 }
71
72 /// Makes sure at least `size` items are unused
73 pub fn ensureUnusedCapacity(self: *Self, size: usize) error{OutOfMemory}!void {
74 if (self.writableLength() >= size) return;
75
76 return try self.ensureTotalCapacity(math.add(usize, self.count, size) catch return error.OutOfMemory);
77 }
78
79 /// Returns number of items currently in fifo
80 pub fn readableLength(self: Self) usize {
81 return self.count;
82 }
83
84 /// Returns a writable slice from the 'read' end of the fifo
85 fn readableSliceMut(self: Self, offset: usize) []T {
86 if (offset > self.count) return &[_]T{};
87
88 var start = self.head + offset;
89 if (start >= self.buf.len) {
90 start -= self.buf.len;
91 return self.buf[start .. start + (self.count - offset)];
92 } else {
93 const end = @min(self.head + self.count, self.buf.len);
94 return self.buf[start..end];
95 }
96 }
97
98 /// Returns a readable slice from `offset`
99 pub fn readableSlice(self: Self, offset: usize) []const T {
100 return self.readableSliceMut(offset);
101 }
102
103 pub fn readableSliceOfLen(self: *Self, len: usize) []const T {
104 assert(len <= self.count);
105 const buf = self.readableSlice(0);
106 if (buf.len >= len) {
107 return buf[0..len];
108 } else {
109 self.realign();
110 return self.readableSlice(0)[0..len];
111 }
112 }
113
114 /// Discard first `count` items in the fifo
115 pub fn discard(self: *Self, count: usize) void {
116 assert(count <= self.count);
117 { // set old range to undefined. Note: may be wrapped around
118 const slice = self.readableSliceMut(0);
119 if (slice.len >= count) {
120 const unused = mem.sliceAsBytes(slice[0..count]);
121 @memset(unused, undefined);
122 } else {
123 const unused = mem.sliceAsBytes(slice[0..]);
124 @memset(unused, undefined);
125 const unused2 = mem.sliceAsBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]);
126 @memset(unused2, undefined);
127 }
128 }
129 var head = self.head + count;
130 // Note it is safe to do a wrapping subtract as
131 // bitwise & with all 1s is a noop
132 head &= self.buf.len -% 1;
133 self.head = head;
134 self.count -= count;
135 }
136
137 /// Read the next item from the fifo
138 pub fn readItem(self: *Self) ?T {
139 if (self.count == 0) return null;
140
141 const c = self.buf[self.head];
142 self.discard(1);
143 return c;
144 }
145
146 /// Read data from the fifo into `dst`, returns number of items copied.
147 pub fn read(self: *Self, dst: []T) usize {
148 var dst_left = dst;
149
150 while (dst_left.len > 0) {
151 const slice = self.readableSlice(0);
152 if (slice.len == 0) break;
153 const n = @min(slice.len, dst_left.len);
154 @memcpy(dst_left[0..n], slice[0..n]);
155 self.discard(n);
156 dst_left = dst_left[n..];
157 }
158
159 return dst.len - dst_left.len;
160 }
161
162 /// Same as `read` except it returns an error union
163 /// The purpose of this function existing is to match `std.io.Reader` API.
164 fn readFn(self: *Self, dest: []u8) error{}!usize {
165 return self.read(dest);
166 }
167
168 /// Returns number of items available in fifo
169 pub fn writableLength(self: Self) usize {
170 return self.buf.len - self.count;
171 }
172
173 /// Returns the first section of writable buffer.
174 /// Note that this may be of length 0
175 pub fn writableSlice(self: Self, offset: usize) []T {
176 if (offset > self.buf.len) return &[_]T{};
177
178 const tail = self.head + offset + self.count;
179 if (tail < self.buf.len) {
180 return self.buf[tail..];
181 } else {
182 return self.buf[tail - self.buf.len ..][0 .. self.writableLength() - offset];
183 }
184 }
185
186 /// Returns a writable buffer of at least `size` items, allocating memory as needed.
187 /// Use `fifo.update` once you've written data to it.
188 pub fn writableWithSize(self: *Self, size: usize) ![]T {
189 try self.ensureUnusedCapacity(size);
190
191 // try to avoid realigning buffer
192 var slice = self.writableSlice(0);
193 if (slice.len < size) {
194 self.realign();
195 slice = self.writableSlice(0);
196 }
197 return slice;
198 }
199
200 /// Update the tail location of the buffer (usually follows use of writable/writableWithSize)
201 pub fn update(self: *Self, count: usize) void {
202 assert(self.count + count <= self.buf.len);
203 self.count += count;
204 }
205
206 /// Appends the data in `src` to the fifo.
207 /// You must have ensured there is enough space.
208 pub fn writeAssumeCapacity(self: *Self, src: []const T) void {
209 assert(self.writableLength() >= src.len);
210
211 var src_left = src;
212 while (src_left.len > 0) {
213 const writable_slice = self.writableSlice(0);
214 assert(writable_slice.len != 0);
215 const n = @min(writable_slice.len, src_left.len);
216 @memcpy(writable_slice[0..n], src_left[0..n]);
217 self.update(n);
218 src_left = src_left[n..];
219 }
220 }
221
222 /// Write a single item to the fifo
223 pub fn writeItem(self: *Self, item: T) !void {
224 try self.ensureUnusedCapacity(1);
225 return self.writeItemAssumeCapacity(item);
226 }
227
228 pub fn writeItemAssumeCapacity(self: *Self, item: T) void {
229 var tail = self.head + self.count;
230 tail &= self.buf.len - 1;
231 self.buf[tail] = item;
232 self.update(1);
233 }
234
235 /// Appends the data in `src` to the fifo.
236 /// Allocates more memory as necessary
237 pub fn write(self: *Self, src: []const T) !void {
238 try self.ensureUnusedCapacity(src.len);
239
240 return self.writeAssumeCapacity(src);
241 }
242
243 /// Same as `write` except it returns the number of bytes written, which is always the same
244 /// as `bytes.len`. The purpose of this function existing is to match `std.io.Writer` API.
245 fn appendWrite(self: *Self, bytes: []const u8) error{OutOfMemory}!usize {
246 try self.write(bytes);
247 return bytes.len;
248 }
249
250 /// Make `count` items available before the current read location
251 fn rewind(self: *Self, count: usize) void {
252 assert(self.writableLength() >= count);
253
254 var head = self.head + (self.buf.len - count);
255 head &= self.buf.len - 1;
256 self.head = head;
257 self.count += count;
258 }
259
260 /// Place data back into the read stream
261 pub fn unget(self: *Self, src: []const T) !void {
262 try self.ensureUnusedCapacity(src.len);
263
264 self.rewind(src.len);
265
266 const slice = self.readableSliceMut(0);
267 if (src.len < slice.len) {
268 @memcpy(slice[0..src.len], src);
269 } else {
270 @memcpy(slice, src[0..slice.len]);
271 const slice2 = self.readableSliceMut(slice.len);
272 @memcpy(slice2[0 .. src.len - slice.len], src[slice.len..]);
273 }
274 }
275
276 /// Returns the item at `offset`.
277 /// Asserts offset is within bounds.
278 pub fn peekItem(self: Self, offset: usize) T {
279 assert(offset < self.count);
280
281 var index = self.head + offset;
282 index &= self.buf.len - 1;
283 return self.buf[index];
284 }
285
286 pub fn toOwnedSlice(self: *Self) Allocator.Error![]T {
287 if (self.head != 0) self.realign();
288 assert(self.head == 0);
289 assert(self.count <= self.buf.len);
290 const allocator = self.allocator;
291 if (allocator.resize(self.buf, self.count)) {
292 const result = self.buf[0..self.count];
293 self.* = Self.init(allocator);
294 return result;
295 }
296 const new_memory = try allocator.dupe(T, self.buf[0..self.count]);
297 allocator.free(self.buf);
298 self.* = Self.init(allocator);
299 return new_memory;
300 }
301 };
302}
303
304test "LinearFifo(u8, .Dynamic) discard(0) from empty buffer should not error on overflow" {
305 var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator);
306 defer fifo.deinit();
307
308 // If overflow is not explicitly allowed this will crash in debug / safe mode
309 fifo.discard(0);
310}
311
312test "LinearFifo(u8, .Dynamic)" {
313 var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator);
314 defer fifo.deinit();
315
316 try fifo.write("HELLO");
317 try testing.expectEqual(@as(usize, 5), fifo.readableLength());
318 try testing.expectEqualSlices(u8, "HELLO", fifo.readableSlice(0));
319
320 {
321 var i: usize = 0;
322 while (i < 5) : (i += 1) {
323 try fifo.write(&[_]u8{fifo.peekItem(i)});
324 }
325 try testing.expectEqual(@as(usize, 10), fifo.readableLength());
326 try testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0));
327 }
328
329 {
330 try testing.expectEqual(@as(u8, 'H'), fifo.readItem().?);
331 try testing.expectEqual(@as(u8, 'E'), fifo.readItem().?);
332 try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
333 try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
334 try testing.expectEqual(@as(u8, 'O'), fifo.readItem().?);
335 }
336 try testing.expectEqual(@as(usize, 5), fifo.readableLength());
337
338 { // Writes that wrap around
339 try testing.expectEqual(@as(usize, 11), fifo.writableLength());
340 try testing.expectEqual(@as(usize, 6), fifo.writableSlice(0).len);
341 fifo.writeAssumeCapacity("6<chars<11");
342 try testing.expectEqualSlices(u8, "HELLO6<char", fifo.readableSlice(0));
343 try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(11));
344 try testing.expectEqualSlices(u8, "11", fifo.readableSlice(13));
345 try testing.expectEqualSlices(u8, "", fifo.readableSlice(15));
346 fifo.discard(11);
347 try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(0));
348 fifo.discard(4);
349 try testing.expectEqual(@as(usize, 0), fifo.readableLength());
350 }
351
352 {
353 const buf = try fifo.writableWithSize(12);
354 try testing.expectEqual(@as(usize, 12), buf.len);
355 var i: u8 = 0;
356 while (i < 10) : (i += 1) {
357 buf[i] = i + 'a';
358 }
359 fifo.update(10);
360 try testing.expectEqualSlices(u8, "abcdefghij", fifo.readableSlice(0));
361 }
362
363 {
364 try fifo.unget("prependedstring");
365 var result: [30]u8 = undefined;
366 try testing.expectEqualSlices(u8, "prependedstringabcdefghij", result[0..fifo.read(&result)]);
367 try fifo.unget("b");
368 try fifo.unget("a");
369 try testing.expectEqualSlices(u8, "ab", result[0..fifo.read(&result)]);
370 }
371
372 fifo.shrink(0);
373
374 {
375 try fifo.writer().print("{s}, {s}!", .{ "Hello", "World" });
376 var result: [30]u8 = undefined;
377 try testing.expectEqualSlices(u8, "Hello, World!", result[0..fifo.read(&result)]);
378 try testing.expectEqual(@as(usize, 0), fifo.readableLength());
379 }
380
381 {
382 try fifo.writer().writeAll("This is a test");
383 var result: [30]u8 = undefined;
384 try testing.expectEqualSlices(u8, "This", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
385 try testing.expectEqualSlices(u8, "is", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
386 try testing.expectEqualSlices(u8, "a", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
387 try testing.expectEqualSlices(u8, "test", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
388 }
389
390 {
391 try fifo.ensureTotalCapacity(1);
392 var in_fbs = std.io.fixedBufferStream("pump test");
393 var out_buf: [50]u8 = undefined;
394 var out_fbs = std.io.fixedBufferStream(&out_buf);
395 try fifo.pump(in_fbs.reader(), out_fbs.writer());
396 try testing.expectEqualSlices(u8, in_fbs.buffer, out_fbs.getWritten());
397 }
398}
399
400test LinearFifo {
401 inline for ([_]type{ u1, u8, u16, u64 }) |T| {
402 const FifoType = LinearFifo(T);
403 var fifo: FifoType = .init(testing.allocator);
404 defer fifo.deinit();
405
406 try fifo.write(&[_]T{ 0, 1, 1, 0, 1 });
407 try testing.expectEqual(@as(usize, 5), fifo.readableLength());
408
409 {
410 try testing.expectEqual(@as(T, 0), fifo.readItem().?);
411 try testing.expectEqual(@as(T, 1), fifo.readItem().?);
412 try testing.expectEqual(@as(T, 1), fifo.readItem().?);
413 try testing.expectEqual(@as(T, 0), fifo.readItem().?);
414 try testing.expectEqual(@as(T, 1), fifo.readItem().?);
415 try testing.expectEqual(@as(usize, 0), fifo.readableLength());
416 }
417
418 {
419 try fifo.writeItem(1);
420 try fifo.writeItem(1);
421 try fifo.writeItem(1);
422 try testing.expectEqual(@as(usize, 3), fifo.readableLength());
423 }
424
425 {
426 var readBuf: [3]T = undefined;
427 const n = fifo.read(&readBuf);
428 try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items.
429 }
430 }
431}
src/dev.zig+5
......@@ -78,6 +78,7 @@ pub const Env = enum {
7878 .ast_gen,
7979 .sema,
8080 .legalize,
81 .c_compiler,
8182 .llvm_backend,
8283 .c_backend,
8384 .wasm_backend,
......@@ -127,6 +128,7 @@ pub const Env = enum {
127128 .clang_command,
128129 .cc_command,
129130 .translate_c_command,
131 .c_compiler,
130132 => true,
131133 else => false,
132134 },
......@@ -152,6 +154,7 @@ pub const Env = enum {
152154 else => Env.ast_gen.supports(feature),
153155 },
154156 .cbe => switch (feature) {
157 .legalize,
155158 .c_backend,
156159 .c_linker,
157160 => true,
......@@ -248,6 +251,8 @@ pub const Feature = enum {
248251 sema,
249252 legalize,
250253
254 c_compiler,
255
251256 llvm_backend,
252257 c_backend,
253258 wasm_backend,
src/fmt.zig+13-13
......@@ -1,3 +1,11 @@
1const std = @import("std");
2const mem = std.mem;
3const fs = std.fs;
4const process = std.process;
5const Allocator = std.mem.Allocator;
6const Color = std.zig.Color;
7const fatal = std.process.fatal;
8
19const usage_fmt =
210 \\Usage: zig fmt [file]...
311 \\
......@@ -52,7 +60,7 @@ pub fn run(
5260 const arg = args[i];
5361 if (mem.startsWith(u8, arg, "-")) {
5462 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
55 const stdout = std.io.getStdOut().writer();
63 const stdout = std.fs.File.stdout().deprecatedWriter();
5664 try stdout.writeAll(usage_fmt);
5765 return process.cleanExit();
5866 } else if (mem.eql(u8, arg, "--color")) {
......@@ -93,7 +101,7 @@ pub fn run(
93101 fatal("cannot use --stdin with positional arguments", .{});
94102 }
95103
96 const stdin = std.io.getStdIn();
104 const stdin: fs.File = .stdin();
97105 const source_code = std.zig.readSourceFileToEndAlloc(gpa, stdin, null) catch |err| {
98106 fatal("unable to read stdin: {}", .{err});
99107 };
......@@ -146,7 +154,7 @@ pub fn run(
146154 process.exit(code);
147155 }
148156
149 return std.io.getStdOut().writeAll(formatted);
157 return std.fs.File.stdout().writeAll(formatted);
150158 }
151159
152160 if (input_files.items.len == 0) {
......@@ -363,7 +371,7 @@ fn fmtPathFile(
363371 return;
364372
365373 if (check_mode) {
366 const stdout = std.io.getStdOut().writer();
374 const stdout = std.fs.File.stdout().deprecatedWriter();
367375 try stdout.print("{s}\n", .{file_path});
368376 fmt.any_error = true;
369377 } else {
......@@ -372,15 +380,7 @@ fn fmtPathFile(
372380
373381 try af.file.writeAll(fmt.out_buffer.items);
374382 try af.finish();
375 const stdout = std.io.getStdOut().writer();
383 const stdout = std.fs.File.stdout().deprecatedWriter();
376384 try stdout.print("{s}\n", .{file_path});
377385 }
378386}
379
380const std = @import("std");
381const mem = std.mem;
382const fs = std.fs;
383const process = std.process;
384const Allocator = std.mem.Allocator;
385const Color = std.zig.Color;
386const fatal = std.process.fatal;
src/libs/freebsd.zig+2-2
......@@ -497,13 +497,13 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
497497 .lt => continue,
498498 .gt => {
499499 // TODO Expose via compile error mechanism instead of log.
500 log.warn("invalid target FreeBSD libc version: {}", .{target_version});
500 log.warn("invalid target FreeBSD libc version: {f}", .{target_version});
501501 return error.InvalidTargetLibCVersion;
502502 },
503503 }
504504 } else blk: {
505505 const latest_index = metadata.all_versions.len - 1;
506 log.warn("zig cannot build new FreeBSD libc version {}; providing instead {}", .{
506 log.warn("zig cannot build new FreeBSD libc version {f}; providing instead {f}", .{
507507 target_version, metadata.all_versions[latest_index],
508508 });
509509 break :blk latest_index;
src/libs/glibc.zig+2-2
......@@ -736,13 +736,13 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
736736 .lt => continue,
737737 .gt => {
738738 // TODO Expose via compile error mechanism instead of log.
739 log.warn("invalid target glibc version: {}", .{target_version});
739 log.warn("invalid target glibc version: {f}", .{target_version});
740740 return error.InvalidTargetGLibCVersion;
741741 },
742742 }
743743 } else blk: {
744744 const latest_index = metadata.all_versions.len - 1;
745 log.warn("zig cannot build new glibc version {}; providing instead {}", .{
745 log.warn("zig cannot build new glibc version {f}; providing instead {f}", .{
746746 target_version, metadata.all_versions[latest_index],
747747 });
748748 break :blk latest_index;
src/libs/libtsan.zig+1-1
......@@ -268,7 +268,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
268268 const skip_linker_dependencies = !target.os.tag.isDarwin();
269269 const linker_allow_shlib_undefined = target.os.tag.isDarwin();
270270 const install_name = if (target.os.tag.isDarwin())
271 try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename})
271 try std.fmt.allocPrintSentinel(arena, "@rpath/{s}", .{basename}, 0)
272272 else
273273 null;
274274 // Workaround for https://github.com/llvm/llvm-project/issues/97627
src/libs/mingw.zig+3-3
......@@ -306,7 +306,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
306306 if (comp.verbose_cc) print: {
307307 std.debug.lockStdErr();
308308 defer std.debug.unlockStdErr();
309 const stderr = std.io.getStdErr().writer();
309 const stderr = std.fs.File.stderr().deprecatedWriter();
310310 nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print;
311311 nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print;
312312 nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print;
......@@ -326,7 +326,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
326326
327327 for (aro_comp.diagnostics.list.items) |diagnostic| {
328328 if (diagnostic.kind == .@"fatal error" or diagnostic.kind == .@"error") {
329 aro.Diagnostics.render(&aro_comp, std.io.tty.detectConfig(std.io.getStdErr()));
329 aro.Diagnostics.render(&aro_comp, std.io.tty.detectConfig(std.fs.File.stderr()));
330330 return error.AroPreprocessorFailed;
331331 }
332332 }
......@@ -335,7 +335,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
335335 // new scope to ensure definition file is written before passing the path to WriteImportLibrary
336336 const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true });
337337 defer def_final_file.close();
338 try pp.prettyPrintTokens(def_final_file.writer(), .result_only);
338 try pp.prettyPrintTokens(def_final_file.deprecatedWriter(), .result_only);
339339 }
340340
341341 const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
src/libs/netbsd.zig+2-2
......@@ -442,13 +442,13 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
442442 .lt => continue,
443443 .gt => {
444444 // TODO Expose via compile error mechanism instead of log.
445 log.warn("invalid target NetBSD libc version: {}", .{target_version});
445 log.warn("invalid target NetBSD libc version: {f}", .{target_version});
446446 return error.InvalidTargetLibCVersion;
447447 },
448448 }
449449 } else blk: {
450450 const latest_index = metadata.all_versions.len - 1;
451 log.warn("zig cannot build new NetBSD libc version {}; providing instead {}", .{
451 log.warn("zig cannot build new NetBSD libc version {f}; providing instead {f}", .{
452452 target_version, metadata.all_versions[latest_index],
453453 });
454454 break :blk latest_index;
src/link.zig+30-28
......@@ -323,7 +323,7 @@ pub const Diags = struct {
323323 const main_msg = try m;
324324 errdefer gpa.free(main_msg);
325325 try diags.msgs.ensureUnusedCapacity(gpa, 1);
326 const note = try std.fmt.allocPrint(gpa, "while parsing {}", .{path});
326 const note = try std.fmt.allocPrint(gpa, "while parsing {f}", .{path});
327327 errdefer gpa.free(note);
328328 const notes = try gpa.create([1]Msg);
329329 errdefer gpa.destroy(notes);
......@@ -838,8 +838,10 @@ pub const File = struct {
838838 const cached_pp_file_path = the_key.status.success.object_path;
839839 cached_pp_file_path.root_dir.handle.copyFile(cached_pp_file_path.sub_path, emit.root_dir.handle, emit.sub_path, .{}) catch |err| {
840840 const diags = &base.comp.link_diags;
841 return diags.fail("failed to copy '{'}' to '{'}': {s}", .{
842 @as(Path, cached_pp_file_path), @as(Path, emit), @errorName(err),
841 return diags.fail("failed to copy '{f}' to '{f}': {s}", .{
842 std.fmt.alt(@as(Path, cached_pp_file_path), .formatEscapeChar),
843 std.fmt.alt(@as(Path, emit), .formatEscapeChar),
844 @errorName(err),
843845 });
844846 };
845847 return;
......@@ -1351,7 +1353,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
13511353 .search_strategy = .paths_first,
13521354 }) catch |archive_err| switch (archive_err) {
13531355 error.LinkFailure => return, // error reported via diags
1354 else => |e| diags.addParseError(dso_path, "failed to parse archive {}: {s}", .{ archive_path, @errorName(e) }),
1356 else => |e| diags.addParseError(dso_path, "failed to parse archive {f}: {s}", .{ archive_path, @errorName(e) }),
13551357 };
13561358 },
13571359 error.LinkFailure => return, // error reported via diags
......@@ -1874,7 +1876,7 @@ pub fn resolveInputs(
18741876 )) |lib_result| {
18751877 switch (lib_result) {
18761878 .ok => {},
1877 .no_match => fatal("{}: file not found", .{pq.path}),
1879 .no_match => fatal("{f}: file not found", .{pq.path}),
18781880 }
18791881 }
18801882 continue;
......@@ -1928,10 +1930,10 @@ fn resolveLibInput(
19281930 .root_dir = lib_directory,
19291931 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.tbd", .{lib_name}),
19301932 };
1931 try checked_paths.writer(gpa).print("\n {}", .{test_path});
1933 try checked_paths.writer(gpa).print("\n {f}", .{test_path});
19321934 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
19331935 error.FileNotFound => break :tbd,
1934 else => |e| fatal("unable to search for tbd library '{}': {s}", .{ test_path, @errorName(e) }),
1936 else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }),
19351937 };
19361938 errdefer file.close();
19371939 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
......@@ -1947,7 +1949,7 @@ fn resolveLibInput(
19471949 },
19481950 }),
19491951 };
1950 try checked_paths.writer(gpa).print("\n {}", .{test_path});
1952 try checked_paths.writer(gpa).print("\n {f}", .{test_path});
19511953 switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
19521954 .path = test_path,
19531955 .query = name_query.query,
......@@ -1964,10 +1966,10 @@ fn resolveLibInput(
19641966 .root_dir = lib_directory,
19651967 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}),
19661968 };
1967 try checked_paths.writer(gpa).print("\n {}", .{test_path});
1969 try checked_paths.writer(gpa).print("\n {f}", .{test_path});
19681970 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
19691971 error.FileNotFound => break :so,
1970 else => |e| fatal("unable to search for so library '{}': {s}", .{
1972 else => |e| fatal("unable to search for so library '{f}': {s}", .{
19711973 test_path, @errorName(e),
19721974 }),
19731975 };
......@@ -1982,10 +1984,10 @@ fn resolveLibInput(
19821984 .root_dir = lib_directory,
19831985 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}),
19841986 };
1985 try checked_paths.writer(gpa).print("\n {}", .{test_path});
1987 try checked_paths.writer(gpa).print("\n {f}", .{test_path});
19861988 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
19871989 error.FileNotFound => break :mingw,
1988 else => |e| fatal("unable to search for static library '{}': {s}", .{ test_path, @errorName(e) }),
1990 else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }),
19891991 };
19901992 errdefer file.close();
19911993 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
......@@ -2037,7 +2039,7 @@ fn resolvePathInput(
20372039 .shared_library => return try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, pq, .dynamic, color),
20382040 .object => {
20392041 var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
2040 fatal("failed to open object {}: {s}", .{ pq.path, @errorName(err) });
2042 fatal("failed to open object {f}: {s}", .{ pq.path, @errorName(err) });
20412043 errdefer file.close();
20422044 try resolved_inputs.append(gpa, .{ .object = .{
20432045 .path = pq.path,
......@@ -2049,7 +2051,7 @@ fn resolvePathInput(
20492051 },
20502052 .res => {
20512053 var file = pq.path.root_dir.handle.openFile(pq.path.sub_path, .{}) catch |err|
2052 fatal("failed to open windows resource {}: {s}", .{ pq.path, @errorName(err) });
2054 fatal("failed to open windows resource {f}: {s}", .{ pq.path, @errorName(err) });
20532055 errdefer file.close();
20542056 try resolved_inputs.append(gpa, .{ .res = .{
20552057 .path = pq.path,
......@@ -2057,7 +2059,7 @@ fn resolvePathInput(
20572059 } });
20582060 return null;
20592061 },
2060 else => fatal("{}: unrecognized file extension", .{pq.path}),
2062 else => fatal("{f}: unrecognized file extension", .{pq.path}),
20612063 }
20622064}
20632065
......@@ -2086,14 +2088,14 @@ fn resolvePathInputLib(
20862088 }) {
20872089 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
20882090 error.FileNotFound => return .no_match,
2089 else => |e| fatal("unable to search for {s} library '{'}': {s}", .{
2090 @tagName(link_mode), test_path, @errorName(e),
2091 else => |e| fatal("unable to search for {s} library '{f}': {s}", .{
2092 @tagName(link_mode), std.fmt.alt(test_path, .formatEscapeChar), @errorName(e),
20912093 }),
20922094 };
20932095 errdefer file.close();
20942096 try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len));
2095 const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{'}': {s}", .{
2096 test_path, @errorName(err),
2097 const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{f}': {s}", .{
2098 std.fmt.alt(test_path, .formatEscapeChar), @errorName(err),
20972099 });
20982100 const buf = ld_script_bytes.items[0..n];
20992101 if (mem.startsWith(u8, buf, std.elf.MAGIC) or mem.startsWith(u8, buf, std.elf.ARMAG)) {
......@@ -2101,14 +2103,14 @@ fn resolvePathInputLib(
21012103 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
21022104 }
21032105 const stat = file.stat() catch |err|
2104 fatal("failed to stat {}: {s}", .{ test_path, @errorName(err) });
2106 fatal("failed to stat {f}: {s}", .{ test_path, @errorName(err) });
21052107 const size = std.math.cast(u32, stat.size) orelse
2106 fatal("{}: linker script too big", .{test_path});
2108 fatal("{f}: linker script too big", .{test_path});
21072109 try ld_script_bytes.resize(gpa, size);
21082110 const buf2 = ld_script_bytes.items[n..];
21092111 const n2 = file.preadAll(buf2, n) catch |err|
2110 fatal("failed to read {}: {s}", .{ test_path, @errorName(err) });
2111 if (n2 != buf2.len) fatal("failed to read {}: unexpected end of file", .{test_path});
2112 fatal("failed to read {f}: {s}", .{ test_path, @errorName(err) });
2113 if (n2 != buf2.len) fatal("failed to read {f}: unexpected end of file", .{test_path});
21122114 var diags = Diags.init(gpa);
21132115 defer diags.deinit();
21142116 const ld_script_result = LdScript.parse(gpa, &diags, test_path, ld_script_bytes.items);
......@@ -2128,7 +2130,7 @@ fn resolvePathInputLib(
21282130 }
21292131
21302132 var ld_script = ld_script_result catch |err|
2131 fatal("{}: failed to parse linker script: {s}", .{ test_path, @errorName(err) });
2133 fatal("{f}: failed to parse linker script: {s}", .{ test_path, @errorName(err) });
21322134 defer ld_script.deinit(gpa);
21332135
21342136 try unresolved_inputs.ensureUnusedCapacity(gpa, ld_script.args.len);
......@@ -2159,7 +2161,7 @@ fn resolvePathInputLib(
21592161
21602162 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
21612163 error.FileNotFound => return .no_match,
2162 else => |e| fatal("unable to search for {s} library {}: {s}", .{
2164 else => |e| fatal("unable to search for {s} library {f}: {s}", .{
21632165 @tagName(link_mode), test_path, @errorName(e),
21642166 }),
21652167 };
......@@ -2192,19 +2194,19 @@ pub fn openDso(path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso
21922194
21932195pub fn openObjectInput(diags: *Diags, path: Path) error{LinkFailure}!Input {
21942196 return .{ .object = openObject(path, false, false) catch |err| {
2195 return diags.failParse(path, "failed to open {}: {s}", .{ path, @errorName(err) });
2197 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
21962198 } };
21972199}
21982200
21992201pub fn openArchiveInput(diags: *Diags, path: Path, must_link: bool, hidden: bool) error{LinkFailure}!Input {
22002202 return .{ .archive = openObject(path, must_link, hidden) catch |err| {
2201 return diags.failParse(path, "failed to open {}: {s}", .{ path, @errorName(err) });
2203 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
22022204 } };
22032205}
22042206
22052207pub fn openDsoInput(diags: *Diags, path: Path, needed: bool, weak: bool, reexport: bool) error{LinkFailure}!Input {
22062208 return .{ .dso = openDso(path, needed, weak, reexport) catch |err| {
2207 return diags.failParse(path, "failed to open {}: {s}", .{ path, @errorName(err) });
2209 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) });
22082210 } };
22092211}
22102212
src/link/C.zig+177-153
......@@ -25,34 +25,34 @@ base: link.File,
2525/// This linker backend does not try to incrementally link output C source code.
2626/// Instead, it tracks all declarations in this table, and iterates over it
2727/// in the flush function, stitching pre-rendered pieces of C code together.
28navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvBlock) = .empty,
28navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvBlock),
2929/// All the string bytes of rendered C code, all squished into one array.
3030/// While in progress, a separate buffer is used, and then when finished, the
3131/// buffer is copied into this one.
32string_bytes: std.ArrayListUnmanaged(u8) = .empty,
32string_bytes: std.ArrayListUnmanaged(u8),
3333/// Tracks all the anonymous decls that are used by all the decls so they can
3434/// be rendered during flush().
35uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock) = .empty,
35uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock),
3636/// Sparse set of uavs that are overaligned. Underaligned anon decls are
3737/// lowered the same as ABI-aligned anon decls. The keys here are a subset of
3838/// the keys of `uavs`.
39aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .empty,
39aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
4040
41exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock) = .empty,
42exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock) = .empty,
41exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock),
42exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock),
4343
4444/// Optimization, `updateDecl` reuses this buffer rather than creating a new
4545/// one with every call.
46fwd_decl_buf: std.ArrayListUnmanaged(u8) = .empty,
46fwd_decl_buf: []u8,
4747/// Optimization, `updateDecl` reuses this buffer rather than creating a new
4848/// one with every call.
49code_buf: std.ArrayListUnmanaged(u8) = .empty,
50/// Optimization, `flush` reuses this buffer rather than creating a new
49code_header_buf: []u8,
50/// Optimization, `updateDecl` reuses this buffer rather than creating a new
5151/// one with every call.
52lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .empty,
52code_buf: []u8,
5353/// Optimization, `flush` reuses this buffer rather than creating a new
5454/// one with every call.
55lazy_code_buf: std.ArrayListUnmanaged(u8) = .empty,
55scratch_buf: []u32,
5656
5757/// A reference into `string_bytes`.
5858const String = extern struct {
......@@ -63,15 +63,23 @@ const String = extern struct {
6363 .start = 0,
6464 .len = 0,
6565 };
66
67 fn concat(lhs: String, rhs: String) String {
68 assert(lhs.start + lhs.len == rhs.start);
69 return .{
70 .start = lhs.start,
71 .len = lhs.len + rhs.len,
72 };
73 }
6674};
6775
6876/// Per-declaration data.
6977pub const AvBlock = struct {
70 code: String = String.empty,
71 fwd_decl: String = String.empty,
78 fwd_decl: String = .empty,
79 code: String = .empty,
7280 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
7381 /// over each `Decl` and generate the definition for each used `CType` once.
74 ctype_pool: codegen.CType.Pool = codegen.CType.Pool.empty,
82 ctype_pool: codegen.CType.Pool = .empty,
7583 /// May contain string references to ctype_pool
7684 lazy_fns: codegen.LazyFnMap = .{},
7785
......@@ -84,7 +92,7 @@ pub const AvBlock = struct {
8492
8593/// Per-exported-symbol data.
8694pub const ExportedBlock = struct {
87 fwd_decl: String = String.empty,
95 fwd_decl: String = .empty,
8896};
8997
9098pub fn getString(this: C, s: String) []const u8 {
......@@ -147,6 +155,16 @@ pub fn createEmpty(
147155 .file = file,
148156 .build_id = options.build_id,
149157 },
158 .navs = .empty,
159 .string_bytes = .empty,
160 .uavs = .empty,
161 .aligned_uavs = .empty,
162 .exported_navs = .empty,
163 .exported_uavs = .empty,
164 .fwd_decl_buf = &.{},
165 .code_header_buf = &.{},
166 .code_buf = &.{},
167 .scratch_buf = &.{},
150168 };
151169
152170 return c_file;
......@@ -170,10 +188,10 @@ pub fn deinit(self: *C) void {
170188 self.exported_uavs.deinit(gpa);
171189
172190 self.string_bytes.deinit(gpa);
173 self.fwd_decl_buf.deinit(gpa);
174 self.code_buf.deinit(gpa);
175 self.lazy_fwd_decl_buf.deinit(gpa);
176 self.lazy_code_buf.deinit(gpa);
191 gpa.free(self.fwd_decl_buf);
192 gpa.free(self.code_header_buf);
193 gpa.free(self.code_buf);
194 gpa.free(self.scratch_buf);
177195}
178196
179197pub fn updateFunc(
......@@ -194,20 +212,17 @@ pub fn updateFunc(
194212 .ctype_pool = mir.c.ctype_pool.move(),
195213 .lazy_fns = mir.c.lazy_fns.move(),
196214 };
197 gop.value_ptr.code = try self.addString(mir.c.code);
198215 gop.value_ptr.fwd_decl = try self.addString(mir.c.fwd_decl);
216 const code_header = try self.addString(mir.c.code_header);
217 const code = try self.addString(mir.c.code);
218 gop.value_ptr.code = code_header.concat(code);
199219 try self.addUavsFromCodegen(&mir.c.uavs);
200220}
201221
202fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
222fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) link.File.FlushError!void {
203223 const gpa = self.base.comp.gpa;
204224 const uav = self.uavs.keys()[i];
205225
206 const fwd_decl = &self.fwd_decl_buf;
207 const code = &self.code_buf;
208 fwd_decl.clearRetainingCapacity();
209 code.clearRetainingCapacity();
210
211226 var object: codegen.Object = .{
212227 .dg = .{
213228 .gpa = gpa,
......@@ -217,21 +232,24 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
217232 .pass = .{ .uav = uav },
218233 .is_naked_fn = false,
219234 .expected_block = null,
220 .fwd_decl = fwd_decl.toManaged(gpa),
221 .ctype_pool = codegen.CType.Pool.empty,
222 .scratch = .{},
235 .fwd_decl = undefined,
236 .ctype_pool = .empty,
237 .scratch = .initBuffer(self.scratch_buf),
223238 .uavs = .empty,
224239 },
225 .code = code.toManaged(gpa),
226 .indent_writer = undefined, // set later so we can get a pointer to object.code
240 .code_header = undefined,
241 .code = undefined,
242 .indent_counter = 0,
227243 };
228 object.indent_writer = .{ .underlying_writer = object.code.writer() };
244 object.dg.fwd_decl = .initOwnedSlice(gpa, self.fwd_decl_buf);
245 object.code = .initOwnedSlice(gpa, self.code_buf);
229246 defer {
230247 object.dg.uavs.deinit(gpa);
231 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
232248 object.dg.ctype_pool.deinit(object.dg.gpa);
233 object.dg.scratch.deinit(gpa);
234 code.* = object.code.moveToUnmanaged();
249
250 self.fwd_decl_buf = object.dg.fwd_decl.toArrayList().allocatedSlice();
251 self.code_buf = object.code.toArrayList().allocatedSlice();
252 self.scratch_buf = object.dg.scratch.allocatedSlice();
235253 }
236254 try object.dg.ctype_pool.init(gpa);
237255
......@@ -243,15 +261,15 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void {
243261 //try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
244262 //return;
245263 },
246 else => |e| return e,
264 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
247265 };
248266
249267 try self.addUavsFromCodegen(&object.dg.uavs);
250268
251269 object.dg.ctype_pool.freeUnusedCapacity(gpa);
252270 self.uavs.values()[i] = .{
253 .code = try self.addString(object.code.items),
254 .fwd_decl = try self.addString(object.dg.fwd_decl.items),
271 .fwd_decl = try self.addString(object.dg.fwd_decl.getWritten()),
272 .code = try self.addString(object.code.getWritten()),
255273 .ctype_pool = object.dg.ctype_pool.move(),
256274 };
257275}
......@@ -277,12 +295,8 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
277295 errdefer _ = self.navs.pop();
278296 if (!gop.found_existing) gop.value_ptr.* = .{};
279297 const ctype_pool = &gop.value_ptr.ctype_pool;
280 const fwd_decl = &self.fwd_decl_buf;
281 const code = &self.code_buf;
282298 try ctype_pool.init(gpa);
283299 ctype_pool.clearRetainingCapacity();
284 fwd_decl.clearRetainingCapacity();
285 code.clearRetainingCapacity();
286300
287301 var object: codegen.Object = .{
288302 .dg = .{
......@@ -293,22 +307,25 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
293307 .pass = .{ .nav = nav_index },
294308 .is_naked_fn = false,
295309 .expected_block = null,
296 .fwd_decl = fwd_decl.toManaged(gpa),
310 .fwd_decl = undefined,
297311 .ctype_pool = ctype_pool.*,
298 .scratch = .{},
312 .scratch = .initBuffer(self.scratch_buf),
299313 .uavs = .empty,
300314 },
301 .code = code.toManaged(gpa),
302 .indent_writer = undefined, // set later so we can get a pointer to object.code
315 .code_header = undefined,
316 .code = undefined,
317 .indent_counter = 0,
303318 };
304 object.indent_writer = .{ .underlying_writer = object.code.writer() };
319 object.dg.fwd_decl = .initOwnedSlice(gpa, self.fwd_decl_buf);
320 object.code = .initOwnedSlice(gpa, self.code_buf);
305321 defer {
306322 object.dg.uavs.deinit(gpa);
307 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
308323 ctype_pool.* = object.dg.ctype_pool.move();
309324 ctype_pool.freeUnusedCapacity(gpa);
310 object.dg.scratch.deinit(gpa);
311 code.* = object.code.moveToUnmanaged();
325
326 self.fwd_decl_buf = object.dg.fwd_decl.toArrayList().allocatedSlice();
327 self.code_buf = object.code.toArrayList().allocatedSlice();
328 self.scratch_buf = object.dg.scratch.allocatedSlice();
312329 }
313330
314331 codegen.genDecl(&object) catch |err| switch (err) {
......@@ -316,10 +333,10 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
316333 error.CodegenFail => return,
317334 error.OutOfMemory => |e| return e,
318335 },
319 else => |e| return e,
336 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
320337 };
321 gop.value_ptr.code = try self.addString(object.code.items);
322 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);
338 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.getWritten());
339 gop.value_ptr.code = try self.addString(object.code.getWritten());
323340 try self.addUavsFromCodegen(&object.dg.uavs);
324341}
325342
......@@ -331,19 +348,14 @@ pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedIn
331348 _ = ti_id;
332349}
333350
334fn abiDefines(self: *C, target: *const std.Target) !std.ArrayList(u8) {
335 const gpa = self.base.comp.gpa;
336 var defines = std.ArrayList(u8).init(gpa);
337 errdefer defines.deinit();
338 const writer = defines.writer();
351fn abiDefines(w: *std.io.Writer, target: *const std.Target) !void {
339352 switch (target.abi) {
340 .msvc, .itanium => try writer.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
353 .msvc, .itanium => try w.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
341354 else => {},
342355 }
343 try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
356 try w.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
344357 target.cMaxIntAlignment(),
345358 });
346 return defines;
347359}
348360
349361pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
......@@ -374,37 +386,47 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
374386 // emit-h is in `flushEmitH` below.
375387
376388 var f: Flush = .{
377 .ctype_pool = codegen.CType.Pool.empty,
378 .lazy_ctype_pool = codegen.CType.Pool.empty,
389 .ctype_pool = .empty,
390 .ctype_global_from_decl_map = .empty,
391 .ctypes = .empty,
392
393 .lazy_ctype_pool = .empty,
394 .lazy_fns = .empty,
395 .lazy_fwd_decl = .empty,
396 .lazy_code = .empty,
397
398 .all_buffers = .empty,
399 .file_size = 0,
379400 };
380401 defer f.deinit(gpa);
381402
382 const abi_defines = try self.abiDefines(zcu.getTarget());
383 defer abi_defines.deinit();
403 var abi_defines_aw: std.io.Writer.Allocating = .init(gpa);
404 defer abi_defines_aw.deinit();
405 abiDefines(&abi_defines_aw.writer, zcu.getTarget()) catch |err| switch (err) {
406 error.WriteFailed => return error.OutOfMemory,
407 };
384408
385409 // Covers defines, zig.h, ctypes, asm, lazy fwd.
386410 try f.all_buffers.ensureUnusedCapacity(gpa, 5);
387411
388 f.appendBufAssumeCapacity(abi_defines.items);
412 f.appendBufAssumeCapacity(abi_defines_aw.getWritten());
389413 f.appendBufAssumeCapacity(zig_h);
390414
391415 const ctypes_index = f.all_buffers.items.len;
392416 f.all_buffers.items.len += 1;
393417
394 {
395 var asm_buf = f.asm_buf.toManaged(gpa);
396 defer f.asm_buf = asm_buf.moveToUnmanaged();
397 try codegen.genGlobalAsm(zcu, asm_buf.writer());
398 f.appendBufAssumeCapacity(asm_buf.items);
399 }
418 var asm_aw: std.io.Writer.Allocating = .init(gpa);
419 defer asm_aw.deinit();
420 codegen.genGlobalAsm(zcu, &asm_aw.writer) catch |err| switch (err) {
421 error.WriteFailed => return error.OutOfMemory,
422 };
423 f.appendBufAssumeCapacity(asm_aw.getWritten());
400424
401425 const lazy_index = f.all_buffers.items.len;
402426 f.all_buffers.items.len += 1;
403427
404 self.lazy_fwd_decl_buf.clearRetainingCapacity();
405 self.lazy_code_buf.clearRetainingCapacity();
406428 try f.lazy_ctype_pool.init(gpa);
407 try self.flushErrDecls(pt, &f.lazy_ctype_pool);
429 try self.flushErrDecls(pt, &f);
408430
409431 // Unlike other backends, the .c code we are emitting has order-dependent decls.
410432 // `CType`s, forward decls, and non-functions first.
......@@ -462,22 +484,15 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
462484 }
463485 }
464486
465 f.all_buffers.items[ctypes_index] = .{
466 .base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
467 .len = f.ctypes_buf.items.len,
468 };
469 f.file_size += f.ctypes_buf.items.len;
487 f.all_buffers.items[ctypes_index] = f.ctypes.items;
488 f.file_size += f.ctypes.items.len;
470489
471 const lazy_fwd_decl_len = self.lazy_fwd_decl_buf.items.len;
472 f.all_buffers.items[lazy_index] = .{
473 .base = if (lazy_fwd_decl_len > 0) self.lazy_fwd_decl_buf.items.ptr else "",
474 .len = lazy_fwd_decl_len,
475 };
476 f.file_size += lazy_fwd_decl_len;
490 f.all_buffers.items[lazy_index] = f.lazy_fwd_decl.items;
491 f.file_size += f.lazy_fwd_decl.items.len;
477492
478493 // Now the code.
479494 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.uavs.count() + self.navs.count()) * 2);
480 f.appendBufAssumeCapacity(self.lazy_code_buf.items);
495 f.appendBufAssumeCapacity(f.lazy_code.items);
481496 for (self.uavs.keys(), self.uavs.values()) |uav, av_block| f.appendCodeAssumeCapacity(
482497 if (self.exported_uavs.contains(uav)) .default else switch (ip.indexToKey(uav)) {
483498 .@"extern" => .zig_extern,
......@@ -493,31 +508,35 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
493508
494509 const file = self.base.file.?;
495510 file.setEndPos(f.file_size) catch |err| return diags.fail("failed to allocate file: {s}", .{@errorName(err)});
496 file.pwritevAll(f.all_buffers.items, 0) catch |err| return diags.fail("failed to write to '{'}': {s}", .{
497 self.base.emit, @errorName(err),
498 });
511 var fw = file.writer(&.{});
512 var w = &fw.interface;
513 w.writeVecAll(f.all_buffers.items) catch |err| switch (err) {
514 error.WriteFailed => return diags.fail("failed to write to '{f}': {s}", .{
515 std.fmt.alt(self.base.emit, .formatEscapeChar), @errorName(fw.err.?),
516 }),
517 };
499518}
500519
501520const Flush = struct {
502521 ctype_pool: codegen.CType.Pool,
503 ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType) = .empty,
504 ctypes_buf: std.ArrayListUnmanaged(u8) = .empty,
522 ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType),
523 ctypes: std.ArrayListUnmanaged(u8),
505524
506525 lazy_ctype_pool: codegen.CType.Pool,
507 lazy_fns: LazyFns = .{},
508
509 asm_buf: std.ArrayListUnmanaged(u8) = .empty,
526 lazy_fns: LazyFns,
527 lazy_fwd_decl: std.ArrayListUnmanaged(u8),
528 lazy_code: std.ArrayListUnmanaged(u8),
510529
511530 /// We collect a list of buffers to write, and write them all at once with pwritev 😎
512 all_buffers: std.ArrayListUnmanaged(std.posix.iovec_const) = .empty,
531 all_buffers: std.ArrayListUnmanaged([]const u8),
513532 /// Keeps track of the total bytes of `all_buffers`.
514 file_size: u64 = 0,
533 file_size: u64,
515534
516535 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);
517536
518537 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
519538 if (buf.len == 0) return;
520 f.all_buffers.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len });
539 f.all_buffers.appendAssumeCapacity(buf);
521540 f.file_size += buf.len;
522541 }
523542
......@@ -532,14 +551,15 @@ const Flush = struct {
532551 }
533552
534553 fn deinit(f: *Flush, gpa: Allocator) void {
535 f.all_buffers.deinit(gpa);
536 f.asm_buf.deinit(gpa);
537 f.lazy_fns.deinit(gpa);
538 f.lazy_ctype_pool.deinit(gpa);
539 f.ctypes_buf.deinit(gpa);
554 f.ctype_pool.deinit(gpa);
540555 assert(f.ctype_global_from_decl_map.items.len == 0);
541556 f.ctype_global_from_decl_map.deinit(gpa);
542 f.ctype_pool.deinit(gpa);
557 f.ctypes.deinit(gpa);
558 f.lazy_ctype_pool.deinit(gpa);
559 f.lazy_fns.deinit(gpa);
560 f.lazy_fwd_decl.deinit(gpa);
561 f.lazy_code.deinit(gpa);
562 f.all_buffers.deinit(gpa);
543563 }
544564};
545565
......@@ -562,9 +582,9 @@ fn flushCTypes(
562582 try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);
563583 defer global_from_decl_map.clearRetainingCapacity();
564584
565 var ctypes_buf = f.ctypes_buf.toManaged(gpa);
566 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
567 const writer = ctypes_buf.writer();
585 var ctypes_aw: std.io.Writer.Allocating = .fromArrayList(gpa, &f.ctypes);
586 const ctypes_bw = &ctypes_aw.writer;
587 defer f.ctypes = ctypes_aw.toArrayList();
568588
569589 for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {
570590 const PoolAdapter = struct {
......@@ -591,26 +611,25 @@ fn flushCTypes(
591611 PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },
592612 );
593613 global_from_decl_map.appendAssumeCapacity(global_ctype);
594 try codegen.genTypeDecl(
614 codegen.genTypeDecl(
595615 zcu,
596 writer,
616 ctypes_bw,
597617 global_ctype_pool,
598618 global_ctype,
599619 pass,
600620 decl_ctype_pool,
601621 decl_ctype,
602622 found_existing,
603 );
623 ) catch |err| switch (err) {
624 error.WriteFailed => return error.OutOfMemory,
625 };
604626 }
605627}
606628
607fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) FlushDeclError!void {
629fn flushErrDecls(self: *C, pt: Zcu.PerThread, f: *Flush) FlushDeclError!void {
608630 const gpa = self.base.comp.gpa;
609631
610 const fwd_decl = &self.lazy_fwd_decl_buf;
611 const code = &self.lazy_code_buf;
612
613 var object = codegen.Object{
632 var object: codegen.Object = .{
614633 .dg = .{
615634 .gpa = gpa,
616635 .pt = pt,
......@@ -619,27 +638,30 @@ fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) F
619638 .pass = .flush,
620639 .is_naked_fn = false,
621640 .expected_block = null,
622 .fwd_decl = fwd_decl.toManaged(gpa),
623 .ctype_pool = ctype_pool.*,
624 .scratch = .{},
641 .fwd_decl = undefined,
642 .ctype_pool = f.lazy_ctype_pool,
643 .scratch = .initBuffer(self.scratch_buf),
625644 .uavs = .empty,
626645 },
627 .code = code.toManaged(gpa),
628 .indent_writer = undefined, // set later so we can get a pointer to object.code
646 .code_header = undefined,
647 .code = undefined,
648 .indent_counter = 0,
629649 };
630 object.indent_writer = .{ .underlying_writer = object.code.writer() };
650 object.dg.fwd_decl = .fromArrayList(gpa, &f.lazy_fwd_decl);
651 object.code = .fromArrayList(gpa, &f.lazy_code);
631652 defer {
632653 object.dg.uavs.deinit(gpa);
633 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
634 ctype_pool.* = object.dg.ctype_pool.move();
635 ctype_pool.freeUnusedCapacity(gpa);
636 object.dg.scratch.deinit(gpa);
637 code.* = object.code.moveToUnmanaged();
654 f.lazy_ctype_pool = object.dg.ctype_pool.move();
655 f.lazy_ctype_pool.freeUnusedCapacity(gpa);
656
657 f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
658 f.lazy_code = object.code.toArrayList();
659 self.scratch_buf = object.dg.scratch.allocatedSlice();
638660 }
639661
640662 codegen.genErrDecls(&object) catch |err| switch (err) {
641663 error.AnalysisFail => unreachable,
642 else => |e| return e,
664 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
643665 };
644666
645667 try self.addUavsFromCodegen(&object.dg.uavs);
......@@ -649,16 +671,13 @@ fn flushLazyFn(
649671 self: *C,
650672 pt: Zcu.PerThread,
651673 mod: *Module,
652 ctype_pool: *codegen.CType.Pool,
674 f: *Flush,
653675 lazy_ctype_pool: *const codegen.CType.Pool,
654676 lazy_fn: codegen.LazyFnMap.Entry,
655677) FlushDeclError!void {
656678 const gpa = self.base.comp.gpa;
657679
658 const fwd_decl = &self.lazy_fwd_decl_buf;
659 const code = &self.lazy_code_buf;
660
661 var object = codegen.Object{
680 var object: codegen.Object = .{
662681 .dg = .{
663682 .gpa = gpa,
664683 .pt = pt,
......@@ -667,29 +686,32 @@ fn flushLazyFn(
667686 .pass = .flush,
668687 .is_naked_fn = false,
669688 .expected_block = null,
670 .fwd_decl = fwd_decl.toManaged(gpa),
671 .ctype_pool = ctype_pool.*,
672 .scratch = .{},
689 .fwd_decl = undefined,
690 .ctype_pool = f.lazy_ctype_pool,
691 .scratch = .initBuffer(self.scratch_buf),
673692 .uavs = .empty,
674693 },
675 .code = code.toManaged(gpa),
676 .indent_writer = undefined, // set later so we can get a pointer to object.code
694 .code_header = undefined,
695 .code = undefined,
696 .indent_counter = 0,
677697 };
678 object.indent_writer = .{ .underlying_writer = object.code.writer() };
698 object.dg.fwd_decl = .fromArrayList(gpa, &f.lazy_fwd_decl);
699 object.code = .fromArrayList(gpa, &f.lazy_code);
679700 defer {
680701 // If this assert trips just handle the anon_decl_deps the same as
681702 // `updateFunc()` does.
682703 assert(object.dg.uavs.count() == 0);
683 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
684 ctype_pool.* = object.dg.ctype_pool.move();
685 ctype_pool.freeUnusedCapacity(gpa);
686 object.dg.scratch.deinit(gpa);
687 code.* = object.code.moveToUnmanaged();
704 f.lazy_ctype_pool = object.dg.ctype_pool.move();
705 f.lazy_ctype_pool.freeUnusedCapacity(gpa);
706
707 f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
708 f.lazy_code = object.code.toArrayList();
709 self.scratch_buf = object.dg.scratch.allocatedSlice();
688710 }
689711
690712 codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {
691713 error.AnalysisFail => unreachable,
692 else => |e| return e,
714 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
693715 };
694716}
695717
......@@ -709,7 +731,7 @@ fn flushLazyFns(
709731 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
710732 if (gop.found_existing) continue;
711733 gop.value_ptr.* = {};
712 try self.flushLazyFn(pt, mod, &f.lazy_ctype_pool, lazy_ctype_pool, entry);
734 try self.flushLazyFn(pt, mod, f, lazy_ctype_pool, entry);
713735 }
714736}
715737
......@@ -802,8 +824,6 @@ pub fn updateExports(
802824 },
803825 };
804826 const ctype_pool = &decl_block.ctype_pool;
805 const fwd_decl = &self.fwd_decl_buf;
806 fwd_decl.clearRetainingCapacity();
807827 var dg: codegen.DeclGen = .{
808828 .gpa = gpa,
809829 .pt = pt,
......@@ -812,20 +832,24 @@ pub fn updateExports(
812832 .pass = pass,
813833 .is_naked_fn = false,
814834 .expected_block = null,
815 .fwd_decl = fwd_decl.toManaged(gpa),
835 .fwd_decl = undefined,
816836 .ctype_pool = decl_block.ctype_pool,
817 .scratch = .{},
837 .scratch = .initBuffer(self.scratch_buf),
818838 .uavs = .empty,
819839 };
840 dg.fwd_decl = .initOwnedSlice(gpa, self.fwd_decl_buf);
820841 defer {
821842 assert(dg.uavs.count() == 0);
822 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
823843 ctype_pool.* = dg.ctype_pool.move();
824844 ctype_pool.freeUnusedCapacity(gpa);
825 dg.scratch.deinit(gpa);
845
846 self.fwd_decl_buf = dg.fwd_decl.toArrayList().allocatedSlice();
847 self.scratch_buf = dg.scratch.allocatedSlice();
826848 }
827 try codegen.genExports(&dg, exported, export_indices);
828 exported_block.* = .{ .fwd_decl = try self.addString(dg.fwd_decl.items) };
849 codegen.genExports(&dg, exported, export_indices) catch |err| switch (err) {
850 error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
851 };
852 exported_block.* = .{ .fwd_decl = try self.addString(dg.fwd_decl.getWritten()) };
829853}
830854
831855pub fn deleteExport(
src/link/Coff.zig+26-41
......@@ -830,8 +830,8 @@ fn debugMem(allocator: Allocator, handle: std.process.Child.Id, pvaddr: std.os.w
830830 const buffer = try allocator.alloc(u8, code.len);
831831 defer allocator.free(buffer);
832832 const memread = try std.os.windows.ReadProcessMemory(handle, pvaddr, buffer);
833 log.debug("to write: {x}", .{std.fmt.fmtSliceHexLower(code)});
834 log.debug("in memory: {x}", .{std.fmt.fmtSliceHexLower(memread)});
833 log.debug("to write: {x}", .{code});
834 log.debug("in memory: {x}", .{memread});
835835}
836836
837837fn writeMemProtected(handle: std.process.Child.Id, pvaddr: std.os.windows.LPVOID, code: []const u8) !void {
......@@ -1213,7 +1213,7 @@ fn updateLazySymbolAtom(
12131213 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;
12141214 defer code_buffer.deinit(gpa);
12151215
1216 const name = try allocPrint(gpa, "__lazy_{s}_{}", .{
1216 const name = try allocPrint(gpa, "__lazy_{s}_{f}", .{
12171217 @tagName(sym.kind),
12181218 Type.fromInterned(sym.ty).fmt(pt),
12191219 });
......@@ -1333,7 +1333,7 @@ fn updateNavCode(
13331333 const ip = &zcu.intern_pool;
13341334 const nav = ip.getNav(nav_index);
13351335
1336 log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
1336 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
13371337
13381338 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
13391339 const required_alignment = switch (pt.navAlignment(nav_index)) {
......@@ -1361,7 +1361,7 @@ fn updateNavCode(
13611361 error.OutOfMemory => return error.OutOfMemory,
13621362 else => |e| return coff.base.cgFail(nav_index, "failed to grow atom: {s}", .{@errorName(e)}),
13631363 };
1364 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr });
1364 log.debug("growing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), sym.value, vaddr });
13651365 log.debug(" (required alignment 0x{x}", .{required_alignment});
13661366
13671367 if (vaddr != sym.value) {
......@@ -1389,7 +1389,7 @@ fn updateNavCode(
13891389 else => |e| return coff.base.cgFail(nav_index, "failed to allocate atom: {s}", .{@errorName(e)}),
13901390 };
13911391 errdefer coff.freeAtom(atom_index);
1392 log.debug("allocated atom for {} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr });
1392 log.debug("allocated atom for {f} at 0x{x}", .{ nav.fqn.fmt(ip), vaddr });
13931393 coff.getAtomPtr(atom_index).size = code_len;
13941394 sym.value = vaddr;
13951395
......@@ -1454,7 +1454,7 @@ pub fn updateExports(
14541454
14551455 for (export_indices) |export_idx| {
14561456 const exp = export_idx.ptr(zcu);
1457 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&zcu.intern_pool)});
1457 log.debug("adding new export '{f}'", .{exp.opts.name.fmt(&zcu.intern_pool)});
14581458
14591459 if (exp.opts.section.toSlice(&zcu.intern_pool)) |section_name| {
14601460 if (!mem.eql(u8, section_name, ".text")) {
......@@ -1530,7 +1530,7 @@ pub fn deleteExport(
15301530 const gpa = coff.base.comp.gpa;
15311531 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
15321532 const sym = coff.getSymbolPtr(sym_loc);
1533 log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)});
1533 log.debug("deleting export '{f}'", .{name.fmt(&zcu.intern_pool)});
15341534 assert(sym.storage_class == .EXTERNAL and sym.section_number != .UNDEFINED);
15351535 sym.* = .{
15361536 .name = [_]u8{0} ** 8,
......@@ -1748,7 +1748,7 @@ pub fn getNavVAddr(
17481748 const zcu = pt.zcu;
17491749 const ip = &zcu.intern_pool;
17501750 const nav = ip.getNav(nav_index);
1751 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
1751 log.debug("getNavVAddr {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
17521752 const sym_index = if (nav.getExtern(ip)) |e|
17531753 try coff.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip))
17541754 else
......@@ -2588,7 +2588,7 @@ fn logSymtab(coff: *Coff) void {
25882588 .DEBUG => unreachable, // TODO
25892589 else => @intFromEnum(sym.section_number),
25902590 };
2591 log.debug(" %{d}: {?s} @{x} in {s}({d}), {s}", .{
2591 log.debug(" %{d}: {s} @{x} in {s}({d}), {s}", .{
25922592 sym_id,
25932593 coff.getSymbolName(.{ .sym_index = @as(u32, @intCast(sym_id)), .file = null }),
25942594 sym.value,
......@@ -2605,7 +2605,7 @@ fn logSymtab(coff: *Coff) void {
26052605 }
26062606
26072607 log.debug("GOT entries:", .{});
2608 log.debug("{}", .{coff.got_table});
2608 log.debug("{f}", .{coff.got_table});
26092609}
26102610
26112611fn logSections(coff: *Coff) void {
......@@ -2625,7 +2625,7 @@ fn logImportTables(coff: *const Coff) void {
26252625 log.debug("import tables:", .{});
26262626 for (coff.import_tables.keys(), 0..) |off, i| {
26272627 const itable = coff.import_tables.values()[i];
2628 log.debug("{}", .{itable.fmtDebug(.{
2628 log.debug("{f}", .{itable.fmtDebug(.{
26292629 .coff = coff,
26302630 .index = i,
26312631 .name_off = off,
......@@ -3061,40 +3061,25 @@ const ImportTable = struct {
30613061 return base_vaddr + index * @sizeOf(u64);
30623062 }
30633063
3064 const FormatContext = struct {
3064 const Format = struct {
30653065 itab: ImportTable,
30663066 ctx: Context,
3067 };
30683067
3069 fn format(itab: ImportTable, comptime unused_format_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
3070 _ = itab;
3071 _ = unused_format_string;
3072 _ = options;
3073 _ = writer;
3074 @compileError("do not format ImportTable directly; use itab.fmtDebug()");
3075 }
3076
3077 fn format2(
3078 fmt_ctx: FormatContext,
3079 comptime unused_format_string: []const u8,
3080 options: fmt.FormatOptions,
3081 writer: anytype,
3082 ) @TypeOf(writer).Error!void {
3083 _ = options;
3084 comptime assert(unused_format_string.len == 0);
3085 const lib_name = fmt_ctx.ctx.coff.temp_strtab.getAssumeExists(fmt_ctx.ctx.name_off);
3086 const base_vaddr = getBaseAddress(fmt_ctx.ctx);
3087 try writer.print("IAT({s}.dll) @{x}:", .{ lib_name, base_vaddr });
3088 for (fmt_ctx.itab.entries.items, 0..) |entry, i| {
3089 try writer.print("\n {d}@{?x} => {s}", .{
3090 i,
3091 fmt_ctx.itab.getImportAddress(entry, fmt_ctx.ctx),
3092 fmt_ctx.ctx.coff.getSymbolName(entry),
3093 });
3068 fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
3069 const lib_name = f.ctx.coff.temp_strtab.getAssumeExists(f.ctx.name_off);
3070 const base_vaddr = getBaseAddress(f.ctx);
3071 try writer.print("IAT({s}.dll) @{x}:", .{ lib_name, base_vaddr });
3072 for (f.itab.entries.items, 0..) |entry, i| {
3073 try writer.print("\n {d}@{?x} => {s}", .{
3074 i,
3075 f.itab.getImportAddress(entry, f.ctx),
3076 f.ctx.coff.getSymbolName(entry),
3077 });
3078 }
30943079 }
3095 }
3080 };
30963081
3097 fn fmtDebug(itab: ImportTable, ctx: Context) fmt.Formatter(format2) {
3082 fn fmtDebug(itab: ImportTable, ctx: Context) fmt.Formatter(Format, Format.default) {
30983083 return .{ .data = .{ .itab = itab, .ctx = ctx } };
30993084 }
31003085
src/link/Dwarf.zig+12-12
......@@ -973,7 +973,7 @@ const Entry = struct {
973973 else
974974 .main;
975975 if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry)
976 log.err("missing Type({}({d}))", .{
976 log.err("missing Type({f}({d}))", .{
977977 Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }),
978978 @intFromEnum(ty),
979979 });
......@@ -981,7 +981,7 @@ const Entry = struct {
981981 for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
982982 const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFile(ip)).mod.?) catch unreachable;
983983 if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry)
984 log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) });
984 log.err("missing Nav({f}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) });
985985 }
986986 }
987987 @panic("missing dwarf relocation target");
......@@ -1957,7 +1957,7 @@ pub const WipNav = struct {
19571957 .{ .debug_output = .{ .dwarf = wip_nav } },
19581958 );
19591959 if (old_len + bytes != wip_nav.debug_info.items.len) {
1960 std.debug.print("{} [{}]: {} != {}\n", .{ ty.fmt(wip_nav.pt), ty.toIntern(), bytes, wip_nav.debug_info.items.len - old_len });
1960 std.debug.print("{f} [{}]: {} != {}\n", .{ ty.fmt(wip_nav.pt), ty.toIntern(), bytes, wip_nav.debug_info.items.len - old_len });
19611961 unreachable;
19621962 }
19631963 }
......@@ -2427,7 +2427,7 @@ fn initWipNavInner(
24272427 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
24282428 const file = zcu.fileByIndex(inst_info.file);
24292429 const decl = file.zir.?.getDeclaration(inst_info.inst);
2430 log.debug("initWipNav({s}:{d}:{d} %{d} = {})", .{
2430 log.debug("initWipNav({s}:{d}:{d} %{d} = {f})", .{
24312431 file.sub_file_path,
24322432 decl.src_line + 1,
24332433 decl.src_column + 1,
......@@ -2632,7 +2632,7 @@ pub fn finishWipNavFunc(
26322632 const ip = &zcu.intern_pool;
26332633 const nav = ip.getNav(nav_index);
26342634 assert(wip_nav.func != .none);
2635 log.debug("finishWipNavFunc({})", .{nav.fqn.fmt(ip)});
2635 log.debug("finishWipNavFunc({f})", .{nav.fqn.fmt(ip)});
26362636
26372637 {
26382638 const external_relocs = &dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
......@@ -2733,7 +2733,7 @@ pub fn finishWipNav(
27332733 const zcu = pt.zcu;
27342734 const ip = &zcu.intern_pool;
27352735 const nav = ip.getNav(nav_index);
2736 log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});
2736 log.debug("finishWipNav({f})", .{nav.fqn.fmt(ip)});
27372737
27382738 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
27392739 if (wip_nav.debug_line.items.len > 0) {
......@@ -2765,7 +2765,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
27652765 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
27662766 const file = zcu.fileByIndex(inst_info.file);
27672767 const decl = file.zir.?.getDeclaration(inst_info.inst);
2768 log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {})", .{
2768 log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {f})", .{
27692769 file.sub_file_path,
27702770 decl.src_line + 1,
27712771 decl.src_column + 1,
......@@ -3215,7 +3215,7 @@ fn updateLazyType(
32153215 const ty: Type = .fromInterned(type_index);
32163216 switch (type_index) {
32173217 .generic_poison_type => log.debug("updateLazyType({s})", .{"anytype"}),
3218 else => log.debug("updateLazyType({})", .{ty.fmt(pt)}),
3218 else => log.debug("updateLazyType({f})", .{ty.fmt(pt)}),
32193219 }
32203220
32213221 var wip_nav: WipNav = .{
......@@ -3243,7 +3243,7 @@ fn updateLazyType(
32433243 const diw = wip_nav.debug_info.writer(dwarf.gpa);
32443244 const name = switch (type_index) {
32453245 .generic_poison_type => "",
3246 else => try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)}),
3246 else => try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)}),
32473247 };
32483248 defer dwarf.gpa.free(name);
32493249
......@@ -3718,7 +3718,7 @@ fn updateLazyValue(
37183718 const zcu = pt.zcu;
37193719 const ip = &zcu.intern_pool;
37203720 assert(ip.typeOf(value_index) != .type_type);
3721 log.debug("updateLazyValue(@as({}, {}))", .{
3721 log.debug("updateLazyValue(@as({f}, {f}))", .{
37223722 Value.fromInterned(value_index).typeOf(zcu).fmt(pt),
37233723 Value.fromInterned(value_index).fmtValue(pt),
37243724 });
......@@ -4110,7 +4110,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
41104110 const ip = &zcu.intern_pool;
41114111 const ty: Type = .fromInterned(type_index);
41124112 const ty_src_loc = ty.srcLoc(zcu);
4113 log.debug("updateContainerType({})", .{ty.fmt(pt)});
4113 log.debug("updateContainerType({f})", .{ty.fmt(pt)});
41144114
41154115 const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip).?;
41164116 const file = zcu.fileByIndex(inst_info.file);
......@@ -4239,7 +4239,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
42394239 };
42404240 defer wip_nav.deinit();
42414241 const diw = wip_nav.debug_info.writer(dwarf.gpa);
4242 const name = try std.fmt.allocPrint(dwarf.gpa, "{}", .{ty.fmt(pt)});
4242 const name = try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)});
42434243 defer dwarf.gpa.free(name);
42444244
42454245 switch (ip.indexToKey(type_index)) {
src/link/Elf.zig+36-72
......@@ -702,7 +702,7 @@ pub fn allocateChunk(self: *Elf, args: struct {
702702 shdr.sh_addr + res.value,
703703 shdr.sh_offset + res.value,
704704 });
705 log.debug(" placement {}, {s}", .{
705 log.debug(" placement {f}, {s}", .{
706706 res.placement,
707707 if (self.atom(res.placement)) |atom_ptr| atom_ptr.name(self) else "",
708708 });
......@@ -869,7 +869,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
869869 // Dump the state for easy debugging.
870870 // State can be dumped via `--debug-log link_state`.
871871 if (build_options.enable_logging) {
872 state_log.debug("{}", .{self.dumpState()});
872 state_log.debug("{f}", .{self.dumpState()});
873873 }
874874
875875 // Beyond this point, everything has been allocated a virtual address and we can resolve
......@@ -3544,7 +3544,7 @@ pub fn addRelaDyn(self: *Elf, opts: RelaDyn) !void {
35443544}
35453545
35463546pub fn addRelaDynAssumeCapacity(self: *Elf, opts: RelaDyn) void {
3547 relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
3547 relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{
35483548 relocation.fmtRelocType(opts.type, self.getTarget().cpu.arch),
35493549 opts.offset,
35503550 opts.sym,
......@@ -3791,7 +3791,7 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
37913791 for (refs.items[0..nrefs]) |ref| {
37923792 const atom_ptr = self.atom(ref).?;
37933793 const file_ptr = atom_ptr.file(self).?;
3794 err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
3794 err.addNote("referenced by {f}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
37953795 }
37963796
37973797 if (refs.items.len > max_notes) {
......@@ -3813,12 +3813,12 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor
38133813
38143814 var err = try diags.addErrorWithNotes(nnotes + 1);
38153815 try err.addMsg("duplicate symbol definition: {s}", .{sym.name(self)});
3816 err.addNote("defined by {}", .{sym.file(self).?.fmtPath()});
3816 err.addNote("defined by {f}", .{sym.file(self).?.fmtPath()});
38173817
38183818 var inote: usize = 0;
38193819 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
38203820 const file_ptr = self.file(notes.items[inote]).?;
3821 err.addNote("defined by {}", .{file_ptr.fmtPath()});
3821 err.addNote("defined by {f}", .{file_ptr.fmtPath()});
38223822 }
38233823
38243824 if (notes.items.len > max_notes) {
......@@ -3847,7 +3847,7 @@ pub fn addFileError(
38473847 const diags = &self.base.comp.link_diags;
38483848 var err = try diags.addErrorWithNotes(1);
38493849 try err.addMsg(format, args);
3850 err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});
3850 err.addNote("while parsing {f}", .{self.file(file_index).?.fmtPath()});
38513851}
38523852
38533853pub fn failFile(
......@@ -3860,28 +3860,21 @@ pub fn failFile(
38603860 return error.LinkFailure;
38613861}
38623862
3863const FormatShdrCtx = struct {
3863const FormatShdr = struct {
38643864 elf_file: *Elf,
38653865 shdr: elf.Elf64_Shdr,
38663866};
38673867
3868fn fmtShdr(self: *Elf, shdr: elf.Elf64_Shdr) std.fmt.Formatter(formatShdr) {
3868fn fmtShdr(self: *Elf, shdr: elf.Elf64_Shdr) std.fmt.Formatter(FormatShdr, formatShdr) {
38693869 return .{ .data = .{
38703870 .shdr = shdr,
38713871 .elf_file = self,
38723872 } };
38733873}
38743874
3875fn formatShdr(
3876 ctx: FormatShdrCtx,
3877 comptime unused_fmt_string: []const u8,
3878 options: std.fmt.FormatOptions,
3879 writer: anytype,
3880) !void {
3881 _ = options;
3882 _ = unused_fmt_string;
3875fn formatShdr(ctx: FormatShdr, writer: *std.io.Writer) std.io.Writer.Error!void {
38833876 const shdr = ctx.shdr;
3884 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({})", .{
3877 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({f})", .{
38853878 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
38863879 shdr.sh_addr, shdr.sh_addralign,
38873880 shdr.sh_size, shdr.sh_entsize,
......@@ -3889,18 +3882,11 @@ fn formatShdr(
38893882 });
38903883}
38913884
3892pub fn fmtShdrFlags(sh_flags: u64) std.fmt.Formatter(formatShdrFlags) {
3885pub fn fmtShdrFlags(sh_flags: u64) std.fmt.Formatter(u64, formatShdrFlags) {
38933886 return .{ .data = sh_flags };
38943887}
38953888
3896fn formatShdrFlags(
3897 sh_flags: u64,
3898 comptime unused_fmt_string: []const u8,
3899 options: std.fmt.FormatOptions,
3900 writer: anytype,
3901) !void {
3902 _ = unused_fmt_string;
3903 _ = options;
3889fn formatShdrFlags(sh_flags: u64, writer: *std.io.Writer) std.io.Writer.Error!void {
39043890 if (elf.SHF_WRITE & sh_flags != 0) {
39053891 try writer.writeAll("W");
39063892 }
......@@ -3945,26 +3931,19 @@ fn formatShdrFlags(
39453931 }
39463932}
39473933
3948const FormatPhdrCtx = struct {
3934const FormatPhdr = struct {
39493935 elf_file: *Elf,
39503936 phdr: elf.Elf64_Phdr,
39513937};
39523938
3953fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Formatter(formatPhdr) {
3939fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Formatter(FormatPhdr, formatPhdr) {
39543940 return .{ .data = .{
39553941 .phdr = phdr,
39563942 .elf_file = self,
39573943 } };
39583944}
39593945
3960fn formatPhdr(
3961 ctx: FormatPhdrCtx,
3962 comptime unused_fmt_string: []const u8,
3963 options: std.fmt.FormatOptions,
3964 writer: anytype,
3965) !void {
3966 _ = options;
3967 _ = unused_fmt_string;
3946fn formatPhdr(ctx: FormatPhdr, writer: *std.io.Writer) std.io.Writer.Error!void {
39683947 const phdr = ctx.phdr;
39693948 const write = phdr.p_flags & elf.PF_W != 0;
39703949 const read = phdr.p_flags & elf.PF_R != 0;
......@@ -3991,24 +3970,16 @@ fn formatPhdr(
39913970 });
39923971}
39933972
3994pub fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) {
3973pub fn dumpState(self: *Elf) std.fmt.Formatter(*Elf, fmtDumpState) {
39953974 return .{ .data = self };
39963975}
39973976
3998fn fmtDumpState(
3999 self: *Elf,
4000 comptime unused_fmt_string: []const u8,
4001 options: std.fmt.FormatOptions,
4002 writer: anytype,
4003) !void {
4004 _ = unused_fmt_string;
4005 _ = options;
4006
3977fn fmtDumpState(self: *Elf, writer: *std.io.Writer) std.io.Writer.Error!void {
40073978 const shared_objects = self.shared_objects.values();
40083979
40093980 if (self.zigObjectPtr()) |zig_object| {
40103981 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename });
4011 try writer.print("{}{}", .{
3982 try writer.print("{f}{f}", .{
40123983 zig_object.fmtAtoms(self),
40133984 zig_object.fmtSymtab(self),
40143985 });
......@@ -4017,10 +3988,10 @@ fn fmtDumpState(
40173988
40183989 for (self.objects.items) |index| {
40193990 const object = self.file(index).?.object;
4020 try writer.print("object({d}) : {}", .{ index, object.fmtPath() });
3991 try writer.print("object({d}) : {f}", .{ index, object.fmtPath() });
40213992 if (!object.alive) try writer.writeAll(" : [*]");
40223993 try writer.writeByte('\n');
4023 try writer.print("{}{}{}{}{}\n", .{
3994 try writer.print("{f}{f}{f}{f}{f}\n", .{
40243995 object.fmtAtoms(self),
40253996 object.fmtCies(self),
40263997 object.fmtFdes(self),
......@@ -4031,51 +4002,51 @@ fn fmtDumpState(
40314002
40324003 for (shared_objects) |index| {
40334004 const shared_object = self.file(index).?.shared_object;
4034 try writer.print("shared_object({d}) : {} : needed({})", .{
4005 try writer.print("shared_object({d}) : {f} : needed({})", .{
40354006 index, shared_object.path, shared_object.needed,
40364007 });
40374008 if (!shared_object.alive) try writer.writeAll(" : [*]");
40384009 try writer.writeByte('\n');
4039 try writer.print("{}\n", .{shared_object.fmtSymtab(self)});
4010 try writer.print("{f}\n", .{shared_object.fmtSymtab(self)});
40404011 }
40414012
40424013 if (self.linker_defined_index) |index| {
40434014 const linker_defined = self.file(index).?.linker_defined;
40444015 try writer.print("linker_defined({d}) : (linker defined)\n", .{index});
4045 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});
4016 try writer.print("{f}\n", .{linker_defined.fmtSymtab(self)});
40464017 }
40474018
40484019 const slice = self.sections.slice();
40494020 {
40504021 try writer.writeAll("atom lists\n");
40514022 for (slice.items(.shdr), slice.items(.atom_list_2), 0..) |shdr, atom_list, shndx| {
4052 try writer.print("shdr({d}) : {s} : {}\n", .{ shndx, self.getShString(shdr.sh_name), atom_list.fmt(self) });
4023 try writer.print("shdr({d}) : {s} : {f}\n", .{ shndx, self.getShString(shdr.sh_name), atom_list.fmt(self) });
40534024 }
40544025 }
40554026
40564027 if (self.requiresThunks()) {
40574028 try writer.writeAll("thunks\n");
40584029 for (self.thunks.items, 0..) |th, index| {
4059 try writer.print("thunk({d}) : {}\n", .{ index, th.fmt(self) });
4030 try writer.print("thunk({d}) : {f}\n", .{ index, th.fmt(self) });
40604031 }
40614032 }
40624033
4063 try writer.print("{}\n", .{self.got.fmt(self)});
4064 try writer.print("{}\n", .{self.plt.fmt(self)});
4034 try writer.print("{f}\n", .{self.got.fmt(self)});
4035 try writer.print("{f}\n", .{self.plt.fmt(self)});
40654036
40664037 try writer.writeAll("Output groups\n");
40674038 for (self.group_sections.items) |cg| {
4068 try writer.print(" shdr({d}) : GROUP({})\n", .{ cg.shndx, cg.cg_ref });
4039 try writer.print(" shdr({d}) : GROUP({f})\n", .{ cg.shndx, cg.cg_ref });
40694040 }
40704041
40714042 try writer.writeAll("\nOutput merge sections\n");
40724043 for (self.merge_sections.items) |msec| {
4073 try writer.print(" shdr({d}) : {}\n", .{ msec.output_section_index, msec.fmt(self) });
4044 try writer.print(" shdr({d}) : {f}\n", .{ msec.output_section_index, msec.fmt(self) });
40744045 }
40754046
40764047 try writer.writeAll("\nOutput shdrs\n");
40774048 for (slice.items(.shdr), slice.items(.phndx), 0..) |shdr, phndx, shndx| {
4078 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{
4049 try writer.print(" shdr({d}) : phdr({d}) : {f}\n", .{
40794050 shndx,
40804051 phndx,
40814052 self.fmtShdr(shdr),
......@@ -4083,7 +4054,7 @@ fn fmtDumpState(
40834054 }
40844055 try writer.writeAll("\nOutput phdrs\n");
40854056 for (self.phdrs.items, 0..) |phdr, phndx| {
4086 try writer.print(" phdr({d}) : {}\n", .{ phndx, self.fmtPhdr(phdr) });
4057 try writer.print(" phdr({d}) : {f}\n", .{ phndx, self.fmtPhdr(phdr) });
40874058 }
40884059}
40894060
......@@ -4221,15 +4192,8 @@ pub const Ref = struct {
42214192 return ref.index == other.index and ref.file == other.file;
42224193 }
42234194
4224 pub fn format(
4225 ref: Ref,
4226 comptime unused_fmt_string: []const u8,
4227 options: std.fmt.FormatOptions,
4228 writer: anytype,
4229 ) !void {
4230 _ = unused_fmt_string;
4231 _ = options;
4232 try writer.print("ref({},{})", .{ ref.index, ref.file });
4195 pub fn format(ref: Ref, writer: *std.io.Writer) std.io.Writer.Error!void {
4196 try writer.print("ref({d},{d})", .{ ref.index, ref.file });
42334197 }
42344198};
42354199
......@@ -4424,7 +4388,7 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
44244388 for (atom_list.atoms.keys()[start..i]) |ref| {
44254389 const atom_ptr = elf_file.atom(ref).?;
44264390 const file_ptr = atom_ptr.file(elf_file).?;
4427 log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) });
4391 log.debug("atom({f}) {s}", .{ ref, atom_ptr.name(elf_file) });
44284392 for (atom_ptr.relocs(elf_file)) |rel| {
44294393 const is_reachable = switch (cpu_arch) {
44304394 .aarch64 => r: {
......@@ -4453,7 +4417,7 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
44534417
44544418 thunk_ptr.value = try advance(atom_list, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));
44554419
4456 log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) });
4420 log.debug("thunk({d}) : {f}", .{ thunk_index, thunk_ptr.fmt(elf_file) });
44574421 }
44584422}
44594423
src/link/Elf/Archive.zig+17-44
......@@ -44,8 +44,8 @@ pub fn parse(
4444 pos += @sizeOf(elf.ar_hdr);
4545
4646 if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) {
47 return diags.failParse(path, "invalid archive header delimiter: {s}", .{
48 std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
47 return diags.failParse(path, "invalid archive header delimiter: {f}", .{
48 std.ascii.hexEscape(&hdr.ar_fmag, .lower),
4949 });
5050 }
5151
......@@ -83,7 +83,7 @@ pub fn parse(
8383 .alive = false,
8484 };
8585
86 log.debug("extracting object '{}' from archive '{}'", .{
86 log.debug("extracting object '{f}' from archive '{f}'", .{
8787 @as(Path, object.path), @as(Path, path),
8888 });
8989
......@@ -201,48 +201,28 @@ pub const ArSymtab = struct {
201201 }
202202 }
203203
204 pub fn format(
205 ar: ArSymtab,
206 comptime unused_fmt_string: []const u8,
207 options: std.fmt.FormatOptions,
208 writer: anytype,
209 ) !void {
210 _ = ar;
211 _ = unused_fmt_string;
212 _ = options;
213 _ = writer;
214 @compileError("do not format ar symtab directly; use fmt instead");
215 }
216
217 const FormatContext = struct {
204 const Format = struct {
218205 ar: ArSymtab,
219206 elf_file: *Elf,
207
208 fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
209 const ar = f.ar;
210 const elf_file = f.elf_file;
211 for (ar.symtab.items, 0..) |entry, i| {
212 const name = ar.strtab.getAssumeExists(entry.off);
213 const file = elf_file.file(entry.file_index).?;
214 try writer.print(" {d}: {s} in file({d})({f})\n", .{ i, name, entry.file_index, file.fmtPath() });
215 }
216 }
220217 };
221218
222 pub fn fmt(ar: ArSymtab, elf_file: *Elf) std.fmt.Formatter(format2) {
219 pub fn fmt(ar: ArSymtab, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
223220 return .{ .data = .{
224221 .ar = ar,
225222 .elf_file = elf_file,
226223 } };
227224 }
228225
229 fn format2(
230 ctx: FormatContext,
231 comptime unused_fmt_string: []const u8,
232 options: std.fmt.FormatOptions,
233 writer: anytype,
234 ) !void {
235 _ = unused_fmt_string;
236 _ = options;
237 const ar = ctx.ar;
238 const elf_file = ctx.elf_file;
239 for (ar.symtab.items, 0..) |entry, i| {
240 const name = ar.strtab.getAssumeExists(entry.off);
241 const file = elf_file.file(entry.file_index).?;
242 try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file_index, file.fmtPath() });
243 }
244 }
245
246226 const Entry = struct {
247227 /// Offset into the string table.
248228 off: u32,
......@@ -280,15 +260,8 @@ pub const ArStrtab = struct {
280260 try writer.writeAll(ar.buffer.items);
281261 }
282262
283 pub fn format(
284 ar: ArStrtab,
285 comptime unused_fmt_string: []const u8,
286 options: std.fmt.FormatOptions,
287 writer: anytype,
288 ) !void {
289 _ = unused_fmt_string;
290 _ = options;
291 try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)});
263 pub fn format(ar: ArStrtab, writer: *std.io.Writer) std.io.Writer.Error!void {
264 try writer.print("{f}", .{std.ascii.hexEscape(ar.buffer.items, .lower)});
292265 }
293266};
294267
src/link/Elf/Atom.zig+57-79
......@@ -142,7 +142,7 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
142142}
143143
144144pub fn free(self: *Atom, elf_file: *Elf) void {
145 log.debug("freeAtom atom({}) ({s})", .{ self.ref(), self.name(elf_file) });
145 log.debug("freeAtom atom({f}) ({s})", .{ self.ref(), self.name(elf_file) });
146146
147147 const comp = elf_file.base.comp;
148148 const gpa = comp.gpa;
......@@ -243,7 +243,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
243243 },
244244 }
245245
246 relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
246 relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{
247247 relocation.fmtRelocType(rel.r_type(), cpu_arch),
248248 r_offset,
249249 r_sym,
......@@ -316,7 +316,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
316316 };
317317 // Violation of One Definition Rule for COMDATs.
318318 // TODO convert into an error
319 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
319 log.debug("{f}: {s}: {s} refers to a discarded COMDAT section", .{
320320 file_ptr.fmtPath(),
321321 self.name(elf_file),
322322 sym_name,
......@@ -519,11 +519,11 @@ fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 {
519519fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) RelocError!void {
520520 const diags = &elf_file.base.comp.link_diags;
521521 var err = try diags.addErrorWithNotes(1);
522 try err.addMsg("fatal linker error: unhandled relocation type {} at offset 0x{x}", .{
522 try err.addMsg("fatal linker error: unhandled relocation type {f} at offset 0x{x}", .{
523523 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
524524 rel.r_offset,
525525 });
526 err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
526 err.addNote("in {f}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
527527 return error.RelocFailure;
528528}
529529
......@@ -539,7 +539,7 @@ fn reportTextRelocError(
539539 rel.r_offset,
540540 symbol.name(elf_file),
541541 });
542 err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
542 err.addNote("in {f}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
543543 return error.RelocFailure;
544544}
545545
......@@ -555,7 +555,7 @@ fn reportPicError(
555555 rel.r_offset,
556556 symbol.name(elf_file),
557557 });
558 err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
558 err.addNote("in {f}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
559559 err.addNote("recompile with -fPIC", .{});
560560 return error.RelocFailure;
561561}
......@@ -572,7 +572,7 @@ fn reportNoPicError(
572572 rel.r_offset,
573573 symbol.name(elf_file),
574574 });
575 err.addNote("in {}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
575 err.addNote("in {f}:{s}", .{ self.file(elf_file).?.fmtPath(), self.name(elf_file) });
576576 err.addNote("recompile with -fno-PIC", .{});
577577 return error.RelocFailure;
578578}
......@@ -652,7 +652,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
652652 // Address of the dynamic thread pointer.
653653 const DTP = elf_file.dtpAddress();
654654
655 relocs_log.debug(" {s}: {x}: [{x} => {x}] GOT({x}) ({s})", .{
655 relocs_log.debug(" {f}: {x}: [{x} => {x}] GOT({x}) ({s})", .{
656656 relocation.fmtRelocType(rel.r_type(), cpu_arch),
657657 r_offset,
658658 P,
......@@ -823,7 +823,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
823823 };
824824 // Violation of One Definition Rule for COMDATs.
825825 // TODO convert into an error
826 log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
826 log.debug("{f}: {s}: {s} refers to a discarded COMDAT section", .{
827827 file_ptr.fmtPath(),
828828 self.name(elf_file),
829829 sym_name,
......@@ -855,7 +855,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
855855
856856 const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP };
857857
858 relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{
858 relocs_log.debug(" {f}: {x}: [{x} => {x}] ({s})", .{
859859 relocation.fmtRelocType(rel.r_type(), cpu_arch),
860860 rel.r_offset,
861861 P,
......@@ -904,65 +904,45 @@ pub fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void {
904904 atom.file(elf_file).?.setAtomExtra(atom.extra_index, extras);
905905}
906906
907pub fn format(
908 atom: Atom,
909 comptime unused_fmt_string: []const u8,
910 options: std.fmt.FormatOptions,
911 writer: anytype,
912) !void {
913 _ = atom;
914 _ = unused_fmt_string;
915 _ = options;
916 _ = writer;
917 @compileError("do not format Atom directly");
918}
919
920pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(format2) {
907pub fn fmt(atom: Atom, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
921908 return .{ .data = .{
922909 .atom = atom,
923910 .elf_file = elf_file,
924911 } };
925912}
926913
927const FormatContext = struct {
914const Format = struct {
928915 atom: Atom,
929916 elf_file: *Elf,
930};
931917
932fn format2(
933 ctx: FormatContext,
934 comptime unused_fmt_string: []const u8,
935 options: std.fmt.FormatOptions,
936 writer: anytype,
937) !void {
938 _ = options;
939 _ = unused_fmt_string;
940 const atom = ctx.atom;
941 const elf_file = ctx.elf_file;
942 try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({}) : next({})", .{
943 atom.atom_index, atom.name(elf_file), atom.address(elf_file),
944 atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size,
945 atom.prev_atom_ref, atom.next_atom_ref,
946 });
947 if (atom.file(elf_file)) |atom_file| switch (atom_file) {
948 .object => |object| {
949 if (atom.fdes(object).len > 0) {
950 try writer.writeAll(" : fdes{ ");
951 const extras = atom.extra(elf_file);
952 for (atom.fdes(object), extras.fde_start..) |fde, i| {
953 try writer.print("{d}", .{i});
954 if (!fde.alive) try writer.writeAll("([*])");
955 if (i - extras.fde_start < extras.fde_count - 1) try writer.writeAll(", ");
918 fn default(f: Format, w: *std.io.Writer) std.io.Writer.Error!void {
919 const atom = f.atom;
920 const elf_file = f.elf_file;
921 try w.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({f}) : next({f})", .{
922 atom.atom_index, atom.name(elf_file), atom.address(elf_file),
923 atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size,
924 atom.prev_atom_ref, atom.next_atom_ref,
925 });
926 if (atom.file(elf_file)) |atom_file| switch (atom_file) {
927 .object => |object| {
928 if (atom.fdes(object).len > 0) {
929 try w.writeAll(" : fdes{ ");
930 const extras = atom.extra(elf_file);
931 for (atom.fdes(object), extras.fde_start..) |fde, i| {
932 try w.print("{d}", .{i});
933 if (!fde.alive) try w.writeAll("([*])");
934 if (i - extras.fde_start < extras.fde_count - 1) try w.writeAll(", ");
935 }
936 try w.writeAll(" }");
956937 }
957 try writer.writeAll(" }");
958 }
959 },
960 else => {},
961 };
962 if (!atom.alive) {
963 try writer.writeAll(" : [*]");
938 },
939 else => {},
940 };
941 if (!atom.alive) {
942 try w.writeAll(" : [*]");
943 }
964944 }
965}
945};
966946
967947pub const Index = u32;
968948
......@@ -1189,7 +1169,7 @@ const x86_64 = struct {
11891169 x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..], t) catch {
11901170 var err = try diags.addErrorWithNotes(1);
11911171 try err.addMsg("could not relax {s}", .{@tagName(r_type)});
1192 err.addNote("in {}:{s} at offset 0x{x}", .{
1172 err.addNote("in {f}:{s} at offset 0x{x}", .{
11931173 atom.file(elf_file).?.fmtPath(),
11941174 atom.name(elf_file),
11951175 rel.r_offset,
......@@ -1285,7 +1265,7 @@ const x86_64 = struct {
12851265 }, t),
12861266 else => return error.RelaxFailure,
12871267 };
1288 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
1268 relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding });
12891269 const nop: Instruction = try .new(.none, .nop, &.{}, t);
12901270 try encode(&.{ nop, inst }, code);
12911271 }
......@@ -1296,7 +1276,7 @@ const x86_64 = struct {
12961276 switch (old_inst.encoding.mnemonic) {
12971277 .mov => {
12981278 const inst: Instruction = try .new(old_inst.prefix, .lea, &old_inst.ops, t);
1299 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
1279 relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding });
13001280 try encode(&.{inst}, code);
13011281 },
13021282 else => return error.RelaxFailure,
......@@ -1330,11 +1310,11 @@ const x86_64 = struct {
13301310
13311311 else => {
13321312 var err = try diags.addErrorWithNotes(1);
1333 try err.addMsg("TODO: rewrite {} when followed by {}", .{
1313 try err.addMsg("TODO: rewrite {f} when followed by {f}", .{
13341314 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
13351315 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
13361316 });
1337 err.addNote("in {}:{s} at offset 0x{x}", .{
1317 err.addNote("in {f}:{s} at offset 0x{x}", .{
13381318 self.file(elf_file).?.fmtPath(),
13391319 self.name(elf_file),
13401320 rels[0].r_offset,
......@@ -1386,11 +1366,11 @@ const x86_64 = struct {
13861366
13871367 else => {
13881368 var err = try diags.addErrorWithNotes(1);
1389 try err.addMsg("TODO: rewrite {} when followed by {}", .{
1369 try err.addMsg("TODO: rewrite {f} when followed by {f}", .{
13901370 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
13911371 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
13921372 });
1393 err.addNote("in {}:{s} at offset 0x{x}", .{
1373 err.addNote("in {f}:{s} at offset 0x{x}", .{
13941374 self.file(elf_file).?.fmtPath(),
13951375 self.name(elf_file),
13961376 rels[0].r_offset,
......@@ -1410,7 +1390,8 @@ const x86_64 = struct {
14101390 // TODO: hack to force imm32s in the assembler
14111391 .{ .imm = .s(-129) },
14121392 }, t) catch return false;
1413 inst.encode(std.io.null_writer, .{}) catch return false;
1393 var trash: std.io.Writer.Discarding = .init(&.{});
1394 inst.encode(&trash.writer, .{}) catch return false;
14141395 return true;
14151396 },
14161397 else => return false,
......@@ -1427,7 +1408,7 @@ const x86_64 = struct {
14271408 // TODO: hack to force imm32s in the assembler
14281409 .{ .imm = .s(-129) },
14291410 }, t) catch unreachable;
1430 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
1411 relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding });
14311412 encode(&.{inst}, code) catch unreachable;
14321413 },
14331414 else => unreachable,
......@@ -1444,7 +1425,7 @@ const x86_64 = struct {
14441425 // TODO: hack to force imm32s in the assembler
14451426 .{ .imm = .s(-129) },
14461427 }, target);
1447 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
1428 relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding });
14481429 try encode(&.{inst}, code);
14491430 },
14501431 else => return error.RelaxFailure,
......@@ -1476,7 +1457,7 @@ const x86_64 = struct {
14761457 std.mem.writeInt(i32, insts[12..][0..4], value, .little);
14771458 try stream.seekBy(-4);
14781459 try writer.writeAll(&insts);
1479 relocs_log.debug(" relaxing {} and {}", .{
1460 relocs_log.debug(" relaxing {f} and {f}", .{
14801461 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
14811462 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
14821463 });
......@@ -1484,11 +1465,11 @@ const x86_64 = struct {
14841465
14851466 else => {
14861467 var err = try diags.addErrorWithNotes(1);
1487 try err.addMsg("fatal linker error: rewrite {} when followed by {}", .{
1468 try err.addMsg("fatal linker error: rewrite {f} when followed by {f}", .{
14881469 relocation.fmtRelocType(rels[0].r_type(), .x86_64),
14891470 relocation.fmtRelocType(rels[1].r_type(), .x86_64),
14901471 });
1491 err.addNote("in {}:{s} at offset 0x{x}", .{
1472 err.addNote("in {f}:{s} at offset 0x{x}", .{
14921473 self.file(elf_file).?.fmtPath(),
14931474 self.name(elf_file),
14941475 rels[0].r_offset,
......@@ -1505,11 +1486,8 @@ const x86_64 = struct {
15051486 }
15061487
15071488 fn encode(insts: []const Instruction, code: []u8) !void {
1508 var stream = std.io.fixedBufferStream(code);
1509 const writer = stream.writer();
1510 for (insts) |inst| {
1511 try inst.encode(writer, .{});
1512 }
1489 var stream: std.io.Writer = .fixed(code);
1490 for (insts) |inst| try inst.encode(&stream, .{});
15131491 }
15141492
15151493 const bits = @import("../../arch/x86_64/bits.zig");
......@@ -1675,7 +1653,7 @@ const aarch64 = struct {
16751653 // TODO: relax
16761654 var err = try diags.addErrorWithNotes(1);
16771655 try err.addMsg("TODO: relax ADR_GOT_PAGE", .{});
1678 err.addNote("in {}:{s} at offset 0x{x}", .{
1656 err.addNote("in {f}:{s} at offset 0x{x}", .{
16791657 atom.file(elf_file).?.fmtPath(),
16801658 atom.name(elf_file),
16811659 r_offset,
......@@ -1965,7 +1943,7 @@ const riscv = struct {
19651943 // TODO: implement searching forward
19661944 var err = try diags.addErrorWithNotes(1);
19671945 try err.addMsg("TODO: find HI20 paired reloc scanning forward", .{});
1968 err.addNote("in {}:{s} at offset 0x{x}", .{
1946 err.addNote("in {f}:{s} at offset 0x{x}", .{
19691947 atom.file(elf_file).?.fmtPath(),
19701948 atom.name(elf_file),
19711949 rel.r_offset,
src/link/Elf/AtomList.zig+24-39
......@@ -108,7 +108,7 @@ pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_fi
108108 const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow;
109109 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
110110
111 log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
111 log.debug(" atom({f}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
112112
113113 const object = atom_ptr.file(elf_file).?.object;
114114 const code = try object.codeDecompressAlloc(elf_file, ref.index);
......@@ -144,7 +144,7 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *E
144144 const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow;
145145 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
146146
147 log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
147 log.debug(" atom({f}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
148148
149149 const object = atom_ptr.file(elf_file).?.object;
150150 const code = try object.codeDecompressAlloc(elf_file, ref.index);
......@@ -167,44 +167,29 @@ pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom {
167167 return elf_file.atom(list.atoms.keys()[list.atoms.keys().len - 1]).?;
168168}
169169
170pub fn format(
171 list: AtomList,
172 comptime unused_fmt_string: []const u8,
173 options: std.fmt.FormatOptions,
174 writer: anytype,
175) !void {
176 _ = list;
177 _ = unused_fmt_string;
178 _ = options;
179 _ = writer;
180 @compileError("do not format AtomList directly");
181}
182
183const FormatCtx = struct { AtomList, *Elf };
184
185pub fn fmt(list: AtomList, elf_file: *Elf) std.fmt.Formatter(format2) {
186 return .{ .data = .{ list, elf_file } };
187}
188
189fn format2(
190 ctx: FormatCtx,
191 comptime unused_fmt_string: []const u8,
192 options: std.fmt.FormatOptions,
193 writer: anytype,
194) !void {
195 _ = unused_fmt_string;
196 _ = options;
197 const list, const elf_file = ctx;
198 try writer.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{
199 list.address(elf_file), list.output_section_index,
200 list.alignment.toByteUnits() orelse 0, list.size,
201 });
202 try writer.writeAll(" : atoms{ ");
203 for (list.atoms.keys(), 0..) |ref, i| {
204 try writer.print("{}", .{ref});
205 if (i < list.atoms.keys().len - 1) try writer.writeAll(", ");
170const Format = struct {
171 atom_list: AtomList,
172 elf_file: *Elf,
173
174 fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
175 const list = f.atom_list;
176 try writer.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{
177 list.address(f.elf_file),
178 list.output_section_index,
179 list.alignment.toByteUnits() orelse 0,
180 list.size,
181 });
182 try writer.writeAll(" : atoms{ ");
183 for (list.atoms.keys(), 0..) |ref, i| {
184 try writer.print("{f}", .{ref});
185 if (i < list.atoms.keys().len - 1) try writer.writeAll(", ");
186 }
187 try writer.writeAll(" }");
206188 }
207 try writer.writeAll(" }");
189};
190
191pub fn fmt(atom_list: AtomList, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
192 return .{ .data = .{ .atom_list = atom_list, .elf_file = elf_file } };
208193}
209194
210195const assert = std.debug.assert;
src/link/Elf/LinkerDefined.zig+16-23
......@@ -147,9 +147,9 @@ pub fn initStartStopSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
147147 for (slice.items(.shdr)) |shdr| {
148148 // TODO use getOrPut for incremental so that we don't create duplicates
149149 if (elf_file.getStartStopBasename(shdr)) |name| {
150 const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
150 const start_name = try std.fmt.allocPrintSentinel(gpa, "__start_{s}", .{name}, 0);
151151 defer gpa.free(start_name);
152 const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
152 const stop_name = try std.fmt.allocPrintSentinel(gpa, "__stop_{s}", .{name}, 0);
153153 defer gpa.free(stop_name);
154154
155155 for (&[_][]const u8{ start_name, stop_name }) |nn| {
......@@ -437,38 +437,31 @@ pub fn setSymbolExtra(self: *LinkerDefined, index: u32, extra: Symbol.Extra) voi
437437 }
438438}
439439
440pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
440pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(Format, Format.symtab) {
441441 return .{ .data = .{
442442 .self = self,
443443 .elf_file = elf_file,
444444 } };
445445}
446446
447const FormatContext = struct {
447const Format = struct {
448448 self: *LinkerDefined,
449449 elf_file: *Elf,
450};
451450
452fn formatSymtab(
453 ctx: FormatContext,
454 comptime unused_fmt_string: []const u8,
455 options: std.fmt.FormatOptions,
456 writer: anytype,
457) !void {
458 _ = unused_fmt_string;
459 _ = options;
460 const self = ctx.self;
461 const elf_file = ctx.elf_file;
462 try writer.writeAll(" globals\n");
463 for (self.symbols.items, 0..) |sym, i| {
464 const ref = self.resolveSymbol(@intCast(i), elf_file);
465 if (elf_file.symbol(ref)) |ref_sym| {
466 try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
467 } else {
468 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
451 fn symtab(ctx: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
452 const self = ctx.self;
453 const elf_file = ctx.elf_file;
454 try writer.writeAll(" globals\n");
455 for (self.symbols.items, 0..) |sym, i| {
456 const ref = self.resolveSymbol(@intCast(i), elf_file);
457 if (elf_file.symbol(ref)) |ref_sym| {
458 try writer.print(" {f}\n", .{ref_sym.fmt(elf_file)});
459 } else {
460 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
461 }
469462 }
470463 }
471}
464};
472465
473466const assert = std.debug.assert;
474467const elf = std.elf;
src/link/Elf/Merge.zig+31-71
......@@ -157,54 +157,34 @@ pub const Section = struct {
157157 }
158158 };
159159
160 pub fn format(
161 msec: Section,
162 comptime unused_fmt_string: []const u8,
163 options: std.fmt.FormatOptions,
164 writer: anytype,
165 ) !void {
166 _ = msec;
167 _ = unused_fmt_string;
168 _ = options;
169 _ = writer;
170 @compileError("do not format directly");
171 }
172
173 pub fn fmt(msec: Section, elf_file: *Elf) std.fmt.Formatter(format2) {
160 pub fn fmt(msec: Section, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
174161 return .{ .data = .{
175162 .msec = msec,
176163 .elf_file = elf_file,
177164 } };
178165 }
179166
180 const FormatContext = struct {
167 const Format = struct {
181168 msec: Section,
182169 elf_file: *Elf,
183 };
184170
185 pub fn format2(
186 ctx: FormatContext,
187 comptime unused_fmt_string: []const u8,
188 options: std.fmt.FormatOptions,
189 writer: anytype,
190 ) !void {
191 _ = options;
192 _ = unused_fmt_string;
193 const msec = ctx.msec;
194 const elf_file = ctx.elf_file;
195 try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{
196 msec.name(elf_file),
197 msec.address(elf_file),
198 msec.size,
199 msec.alignment.toByteUnits() orelse 0,
200 msec.entsize,
201 msec.type,
202 msec.flags,
203 });
204 for (msec.subsections.items) |msub| {
205 try writer.print(" {}\n", .{msub.fmt(elf_file)});
171 pub fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
172 const msec = f.msec;
173 const elf_file = f.elf_file;
174 try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{
175 msec.name(elf_file),
176 msec.address(elf_file),
177 msec.size,
178 msec.alignment.toByteUnits() orelse 0,
179 msec.entsize,
180 msec.type,
181 msec.flags,
182 });
183 for (msec.subsections.items) |msub| {
184 try writer.print(" {f}\n", .{msub.fmt(elf_file)});
185 }
206186 }
207 }
187 };
208188
209189 pub const Index = u32;
210190};
......@@ -231,48 +211,28 @@ pub const Subsection = struct {
231211 return msec.bytes.items[msub.string_index..][0..msub.size];
232212 }
233213
234 pub fn format(
235 msub: Subsection,
236 comptime unused_fmt_string: []const u8,
237 options: std.fmt.FormatOptions,
238 writer: anytype,
239 ) !void {
240 _ = msub;
241 _ = unused_fmt_string;
242 _ = options;
243 _ = writer;
244 @compileError("do not format directly");
245 }
246
247 pub fn fmt(msub: Subsection, elf_file: *Elf) std.fmt.Formatter(format2) {
214 pub fn fmt(msub: Subsection, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
248215 return .{ .data = .{
249216 .msub = msub,
250217 .elf_file = elf_file,
251218 } };
252219 }
253220
254 const FormatContext = struct {
221 const Format = struct {
255222 msub: Subsection,
256223 elf_file: *Elf,
257 };
258224
259 pub fn format2(
260 ctx: FormatContext,
261 comptime unused_fmt_string: []const u8,
262 options: std.fmt.FormatOptions,
263 writer: anytype,
264 ) !void {
265 _ = options;
266 _ = unused_fmt_string;
267 const msub = ctx.msub;
268 const elf_file = ctx.elf_file;
269 try writer.print("@{x} : align({x}) : size({x})", .{
270 msub.address(elf_file),
271 msub.alignment,
272 msub.size,
273 });
274 if (!msub.alive) try writer.writeAll(" : [*]");
275 }
225 pub fn default(ctx: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
226 const msub = ctx.msub;
227 const elf_file = ctx.elf_file;
228 try writer.print("@{x} : align({x}) : size({x})", .{
229 msub.address(elf_file),
230 msub.alignment,
231 msub.size,
232 });
233 if (!msub.alive) try writer.writeAll(" : [*]");
234 }
235 };
276236
277237 pub const Index = u32;
278238};
src/link/Elf/Object.zig+75-133
......@@ -281,7 +281,7 @@ fn initAtoms(
281281 elf.SHT_GROUP => {
282282 if (shdr.sh_info >= self.symtab.items.len) {
283283 // TODO convert into an error
284 log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()});
284 log.debug("{f}: invalid symbol index in sh_info", .{self.fmtPath()});
285285 continue;
286286 }
287287 const group_info_sym = self.symtab.items[shdr.sh_info];
......@@ -488,10 +488,7 @@ fn parseEhFrame(
488488 if (cie.offset == cie_ptr) break @as(u32, @intCast(cie_index));
489489 } else {
490490 // TODO convert into an error
491 log.debug("{s}: no matching CIE found for FDE at offset {x}", .{
492 self.fmtPath(),
493 fde.offset,
494 });
491 log.debug("{f}: no matching CIE found for FDE at offset {x}", .{ self.fmtPath(), fde.offset });
495492 continue;
496493 };
497494 fde.cie_index = cie_index;
......@@ -582,7 +579,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
582579 if (sym.flags.import) {
583580 if (sym.type(elf_file) != elf.STT_FUNC)
584581 // TODO convert into an error
585 log.debug("{s}: {s}: CIE referencing external data reference", .{
582 log.debug("{f}: {s}: CIE referencing external data reference", .{
586583 self.fmtPath(), sym.name(elf_file),
587584 });
588585 sym.flags.needs_plt = true;
......@@ -796,7 +793,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
796793 if (!isNull(data[end .. end + sh_entsize])) {
797794 var err = try diags.addErrorWithNotes(1);
798795 try err.addMsg("string not null terminated", .{});
799 err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
796 err.addNote("in {f}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
800797 return error.LinkFailure;
801798 }
802799 end += sh_entsize;
......@@ -811,7 +808,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
811808 if (shdr.sh_size % sh_entsize != 0) {
812809 var err = try diags.addErrorWithNotes(1);
813810 try err.addMsg("size not a multiple of sh_entsize", .{});
814 err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
811 err.addNote("in {f}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
815812 return error.LinkFailure;
816813 }
817814
......@@ -889,7 +886,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
889886 var err = try diags.addErrorWithNotes(2);
890887 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});
891888 err.addNote("for symbol {s}", .{sym.name(elf_file)});
892 err.addNote("in {}", .{self.fmtPath()});
889 err.addNote("in {f}", .{self.fmtPath()});
893890 return error.LinkFailure;
894891 };
895892
......@@ -914,7 +911,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{
914911 const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
915912 var err = try diags.addErrorWithNotes(1);
916913 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});
917 err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
914 err.addNote("in {f}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
918915 return error.LinkFailure;
919916 };
920917
......@@ -1432,171 +1429,116 @@ pub fn group(self: *Object, index: Elf.Group.Index) *Elf.Group {
14321429 return &self.groups.items[index];
14331430}
14341431
1435pub fn format(
1436 self: *Object,
1437 comptime unused_fmt_string: []const u8,
1438 options: std.fmt.FormatOptions,
1439 writer: anytype,
1440) !void {
1441 _ = self;
1442 _ = unused_fmt_string;
1443 _ = options;
1444 _ = writer;
1445 @compileError("do not format objects directly");
1446}
1447
1448pub fn fmtSymtab(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
1432pub fn fmtSymtab(self: *Object, elf_file: *Elf) std.fmt.Formatter(Format, Format.symtab) {
14491433 return .{ .data = .{
14501434 .object = self,
14511435 .elf_file = elf_file,
14521436 } };
14531437}
14541438
1455const FormatContext = struct {
1439const Format = struct {
14561440 object: *Object,
14571441 elf_file: *Elf,
1458};
14591442
1460fn formatSymtab(
1461 ctx: FormatContext,
1462 comptime unused_fmt_string: []const u8,
1463 options: std.fmt.FormatOptions,
1464 writer: anytype,
1465) !void {
1466 _ = unused_fmt_string;
1467 _ = options;
1468 const object = ctx.object;
1469 const elf_file = ctx.elf_file;
1470 try writer.writeAll(" locals\n");
1471 for (object.locals()) |sym| {
1472 try writer.print(" {}\n", .{sym.fmt(elf_file)});
1443 fn symtab(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
1444 const object = f.object;
1445 const elf_file = f.elf_file;
1446 try writer.writeAll(" locals\n");
1447 for (object.locals()) |sym| {
1448 try writer.print(" {f}\n", .{sym.fmt(elf_file)});
1449 }
1450 try writer.writeAll(" globals\n");
1451 for (object.globals(), 0..) |sym, i| {
1452 const first_global = object.first_global.?;
1453 const ref = object.resolveSymbol(@intCast(i + first_global), elf_file);
1454 if (elf_file.symbol(ref)) |ref_sym| {
1455 try writer.print(" {f}\n", .{ref_sym.fmt(elf_file)});
1456 } else {
1457 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
1458 }
1459 }
14731460 }
1474 try writer.writeAll(" globals\n");
1475 for (object.globals(), 0..) |sym, i| {
1476 const first_global = object.first_global.?;
1477 const ref = object.resolveSymbol(@intCast(i + first_global), elf_file);
1478 if (elf_file.symbol(ref)) |ref_sym| {
1479 try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
1480 } else {
1481 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
1461
1462 fn atoms(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
1463 const object = f.object;
1464 try writer.writeAll(" atoms\n");
1465 for (object.atoms_indexes.items) |atom_index| {
1466 const atom_ptr = object.atom(atom_index) orelse continue;
1467 try writer.print(" {f}\n", .{atom_ptr.fmt(f.elf_file)});
1468 }
1469 }
1470
1471 fn cies(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
1472 const object = f.object;
1473 try writer.writeAll(" cies\n");
1474 for (object.cies.items, 0..) |cie, i| {
1475 try writer.print(" cie({d}) : {f}\n", .{ i, cie.fmt(f.elf_file) });
14821476 }
14831477 }
1484}
14851478
1486pub fn fmtAtoms(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatAtoms) {
1479 fn fdes(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
1480 const object = f.object;
1481 try writer.writeAll(" fdes\n");
1482 for (object.fdes.items, 0..) |fde, i| {
1483 try writer.print(" fde({d}) : {f}\n", .{ i, fde.fmt(f.elf_file) });
1484 }
1485 }
1486
1487 fn groups(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
1488 const object = f.object;
1489 const elf_file = f.elf_file;
1490 try writer.writeAll(" groups\n");
1491 for (object.groups.items, 0..) |g, g_index| {
1492 try writer.print(" {s}({d})", .{ if (g.is_comdat) "COMDAT" else "GROUP", g_index });
1493 if (!g.alive) try writer.writeAll(" : [*]");
1494 try writer.writeByte('\n');
1495 const g_members = g.members(elf_file);
1496 for (g_members) |shndx| {
1497 const atom_index = object.atoms_indexes.items[shndx];
1498 const atom_ptr = object.atom(atom_index) orelse continue;
1499 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) });
1500 }
1501 }
1502 }
1503};
1504
1505pub fn fmtAtoms(self: *Object, elf_file: *Elf) std.fmt.Formatter(Format, Format.atoms) {
14871506 return .{ .data = .{
14881507 .object = self,
14891508 .elf_file = elf_file,
14901509 } };
14911510}
14921511
1493fn formatAtoms(
1494 ctx: FormatContext,
1495 comptime unused_fmt_string: []const u8,
1496 options: std.fmt.FormatOptions,
1497 writer: anytype,
1498) !void {
1499 _ = unused_fmt_string;
1500 _ = options;
1501 const object = ctx.object;
1502 try writer.writeAll(" atoms\n");
1503 for (object.atoms_indexes.items) |atom_index| {
1504 const atom_ptr = object.atom(atom_index) orelse continue;
1505 try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
1506 }
1507}
1508
1509pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) {
1512pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(Format, Format.cies) {
15101513 return .{ .data = .{
15111514 .object = self,
15121515 .elf_file = elf_file,
15131516 } };
15141517}
15151518
1516fn formatCies(
1517 ctx: FormatContext,
1518 comptime unused_fmt_string: []const u8,
1519 options: std.fmt.FormatOptions,
1520 writer: anytype,
1521) !void {
1522 _ = unused_fmt_string;
1523 _ = options;
1524 const object = ctx.object;
1525 try writer.writeAll(" cies\n");
1526 for (object.cies.items, 0..) |cie, i| {
1527 try writer.print(" cie({d}) : {}\n", .{ i, cie.fmt(ctx.elf_file) });
1528 }
1529}
1530
1531pub fn fmtFdes(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatFdes) {
1519pub fn fmtFdes(self: *Object, elf_file: *Elf) std.fmt.Formatter(Format, Format.fdes) {
15321520 return .{ .data = .{
15331521 .object = self,
15341522 .elf_file = elf_file,
15351523 } };
15361524}
15371525
1538fn formatFdes(
1539 ctx: FormatContext,
1540 comptime unused_fmt_string: []const u8,
1541 options: std.fmt.FormatOptions,
1542 writer: anytype,
1543) !void {
1544 _ = unused_fmt_string;
1545 _ = options;
1546 const object = ctx.object;
1547 try writer.writeAll(" fdes\n");
1548 for (object.fdes.items, 0..) |fde, i| {
1549 try writer.print(" fde({d}) : {}\n", .{ i, fde.fmt(ctx.elf_file) });
1550 }
1551}
1552
1553pub fn fmtGroups(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatGroups) {
1526pub fn fmtGroups(self: *Object, elf_file: *Elf) std.fmt.Formatter(Format, Format.groups) {
15541527 return .{ .data = .{
15551528 .object = self,
15561529 .elf_file = elf_file,
15571530 } };
15581531}
15591532
1560fn formatGroups(
1561 ctx: FormatContext,
1562 comptime unused_fmt_string: []const u8,
1563 options: std.fmt.FormatOptions,
1564 writer: anytype,
1565) !void {
1566 _ = unused_fmt_string;
1567 _ = options;
1568 const object = ctx.object;
1569 const elf_file = ctx.elf_file;
1570 try writer.writeAll(" groups\n");
1571 for (object.groups.items, 0..) |g, g_index| {
1572 try writer.print(" {s}({d})", .{ if (g.is_comdat) "COMDAT" else "GROUP", g_index });
1573 if (!g.alive) try writer.writeAll(" : [*]");
1574 try writer.writeByte('\n');
1575 const g_members = g.members(elf_file);
1576 for (g_members) |shndx| {
1577 const atom_index = object.atoms_indexes.items[shndx];
1578 const atom_ptr = object.atom(atom_index) orelse continue;
1579 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) });
1580 }
1581 }
1582}
1583
1584pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) {
1533pub fn fmtPath(self: Object) std.fmt.Formatter(Object, formatPath) {
15851534 return .{ .data = self };
15861535}
15871536
1588fn formatPath(
1589 object: Object,
1590 comptime unused_fmt_string: []const u8,
1591 options: std.fmt.FormatOptions,
1592 writer: anytype,
1593) !void {
1594 _ = unused_fmt_string;
1595 _ = options;
1537fn formatPath(object: Object, writer: *std.io.Writer) std.io.Writer.Error!void {
15961538 if (object.archive) |ar| {
1597 try writer.print("{}({})", .{ ar.path, object.path });
1539 try writer.print("{f}({f})", .{ ar.path, object.path });
15981540 } else {
1599 try writer.print("{}", .{object.path});
1541 try writer.print("{f}", .{object.path});
16001542 }
16011543}
16021544
src/link/Elf/SharedObject.zig+14-34
......@@ -509,51 +509,31 @@ pub fn setSymbolExtra(self: *SharedObject, index: u32, extra: Symbol.Extra) void
509509 }
510510}
511511
512pub fn format(
513 self: SharedObject,
514 comptime unused_fmt_string: []const u8,
515 options: std.fmt.FormatOptions,
516 writer: anytype,
517) !void {
518 _ = self;
519 _ = unused_fmt_string;
520 _ = options;
521 _ = writer;
522 @compileError("unreachable");
523}
524
525pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
512pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(Format, Format.symtab) {
526513 return .{ .data = .{
527514 .shared = self,
528515 .elf_file = elf_file,
529516 } };
530517}
531518
532const FormatContext = struct {
519const Format = struct {
533520 shared: SharedObject,
534521 elf_file: *Elf,
535};
536522
537fn formatSymtab(
538 ctx: FormatContext,
539 comptime unused_fmt_string: []const u8,
540 options: std.fmt.FormatOptions,
541 writer: anytype,
542) !void {
543 _ = unused_fmt_string;
544 _ = options;
545 const shared = ctx.shared;
546 const elf_file = ctx.elf_file;
547 try writer.writeAll(" globals\n");
548 for (shared.symbols.items, 0..) |sym, i| {
549 const ref = shared.resolveSymbol(@intCast(i), elf_file);
550 if (elf_file.symbol(ref)) |ref_sym| {
551 try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
552 } else {
553 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
523 fn symtab(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
524 const shared = f.shared;
525 const elf_file = f.elf_file;
526 try writer.writeAll(" globals\n");
527 for (shared.symbols.items, 0..) |sym, i| {
528 const ref = shared.resolveSymbol(@intCast(i), elf_file);
529 if (elf_file.symbol(ref)) |ref_sym| {
530 try writer.print(" {f}\n", .{ref_sym.fmt(elf_file)});
531 } else {
532 try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
533 }
554534 }
555535 }
556}
536};
557537
558538const SharedObject = @This();
559539
src/link/Elf/Symbol.zig+50-77
......@@ -316,99 +316,72 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
316316 out.st_size = esym.st_size;
317317}
318318
319pub fn format(
320 symbol: Symbol,
321 comptime unused_fmt_string: []const u8,
322 options: std.fmt.FormatOptions,
323 writer: anytype,
324) !void {
325 _ = symbol;
326 _ = unused_fmt_string;
327 _ = options;
328 _ = writer;
329 @compileError("do not format Symbol directly");
330}
331
332const FormatContext = struct {
319const Format = struct {
333320 symbol: Symbol,
334321 elf_file: *Elf,
322
323 fn name(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
324 const elf_file = f.elf_file;
325 const symbol = f.symbol;
326 try writer.writeAll(symbol.name(elf_file));
327 switch (symbol.version_index.VERSION) {
328 @intFromEnum(elf.VER_NDX.LOCAL), @intFromEnum(elf.VER_NDX.GLOBAL) => {},
329 else => {
330 const file_ptr = symbol.file(elf_file).?;
331 assert(file_ptr == .shared_object);
332 const shared_object = file_ptr.shared_object;
333 try writer.print("@{s}", .{shared_object.versionString(symbol.version_index)});
334 },
335 }
336 }
337
338 fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
339 const symbol = f.symbol;
340 const elf_file = f.elf_file;
341 try writer.print("%{d} : {f} : @{x}", .{
342 symbol.esym_index,
343 symbol.fmtName(elf_file),
344 symbol.address(.{ .plt = false, .trampoline = false }, elf_file),
345 });
346 if (symbol.file(elf_file)) |file_ptr| {
347 if (symbol.isAbs(elf_file)) {
348 if (symbol.elfSym(elf_file).st_shndx == elf.SHN_UNDEF) {
349 try writer.writeAll(" : undef");
350 } else {
351 try writer.writeAll(" : absolute");
352 }
353 } else if (symbol.outputShndx(elf_file)) |shndx| {
354 try writer.print(" : shdr({d})", .{shndx});
355 }
356 if (symbol.atom(elf_file)) |atom_ptr| {
357 try writer.print(" : atom({d})", .{atom_ptr.atom_index});
358 }
359 var buf: [2]u8 = .{'_'} ** 2;
360 if (symbol.flags.@"export") buf[0] = 'E';
361 if (symbol.flags.import) buf[1] = 'I';
362 try writer.print(" : {s}", .{&buf});
363 if (symbol.flags.weak) try writer.writeAll(" : weak");
364 switch (file_ptr) {
365 inline else => |x| try writer.print(" : {s}({d})", .{ @tagName(file_ptr), x.index }),
366 }
367 } else try writer.writeAll(" : unresolved");
368 }
335369};
336370
337pub fn fmtName(symbol: Symbol, elf_file: *Elf) std.fmt.Formatter(formatName) {
371pub fn fmtName(symbol: Symbol, elf_file: *Elf) std.fmt.Formatter(Format, Format.name) {
338372 return .{ .data = .{
339373 .symbol = symbol,
340374 .elf_file = elf_file,
341375 } };
342376}
343377
344fn formatName(
345 ctx: FormatContext,
346 comptime unused_fmt_string: []const u8,
347 options: std.fmt.FormatOptions,
348 writer: anytype,
349) !void {
350 _ = options;
351 _ = unused_fmt_string;
352 const elf_file = ctx.elf_file;
353 const symbol = ctx.symbol;
354 try writer.writeAll(symbol.name(elf_file));
355 switch (symbol.version_index.VERSION) {
356 @intFromEnum(elf.VER_NDX.LOCAL), @intFromEnum(elf.VER_NDX.GLOBAL) => {},
357 else => {
358 const file_ptr = symbol.file(elf_file).?;
359 assert(file_ptr == .shared_object);
360 const shared_object = file_ptr.shared_object;
361 try writer.print("@{s}", .{shared_object.versionString(symbol.version_index)});
362 },
363 }
364}
365
366pub fn fmt(symbol: Symbol, elf_file: *Elf) std.fmt.Formatter(format2) {
378pub fn fmt(symbol: Symbol, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
367379 return .{ .data = .{
368380 .symbol = symbol,
369381 .elf_file = elf_file,
370382 } };
371383}
372384
373fn format2(
374 ctx: FormatContext,
375 comptime unused_fmt_string: []const u8,
376 options: std.fmt.FormatOptions,
377 writer: anytype,
378) !void {
379 _ = options;
380 _ = unused_fmt_string;
381 const symbol = ctx.symbol;
382 const elf_file = ctx.elf_file;
383 try writer.print("%{d} : {s} : @{x}", .{
384 symbol.esym_index,
385 symbol.fmtName(elf_file),
386 symbol.address(.{ .plt = false, .trampoline = false }, elf_file),
387 });
388 if (symbol.file(elf_file)) |file_ptr| {
389 if (symbol.isAbs(elf_file)) {
390 if (symbol.elfSym(elf_file).st_shndx == elf.SHN_UNDEF) {
391 try writer.writeAll(" : undef");
392 } else {
393 try writer.writeAll(" : absolute");
394 }
395 } else if (symbol.outputShndx(elf_file)) |shndx| {
396 try writer.print(" : shdr({d})", .{shndx});
397 }
398 if (symbol.atom(elf_file)) |atom_ptr| {
399 try writer.print(" : atom({d})", .{atom_ptr.atom_index});
400 }
401 var buf: [2]u8 = .{'_'} ** 2;
402 if (symbol.flags.@"export") buf[0] = 'E';
403 if (symbol.flags.import) buf[1] = 'I';
404 try writer.print(" : {s}", .{&buf});
405 if (symbol.flags.weak) try writer.writeAll(" : weak");
406 switch (file_ptr) {
407 inline else => |x| try writer.print(" : {s}({d})", .{ @tagName(file_ptr), x.index }),
408 }
409 } else try writer.writeAll(" : unresolved");
410}
411
412385pub const Flags = packed struct {
413386 /// Whether the symbol is imported at runtime.
414387 import: bool = false,
src/link/Elf/Thunk.zig+11-31
......@@ -65,47 +65,27 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize {
6565 };
6666}
6767
68pub fn format(
69 thunk: Thunk,
70 comptime unused_fmt_string: []const u8,
71 options: std.fmt.FormatOptions,
72 writer: anytype,
73) !void {
74 _ = thunk;
75 _ = unused_fmt_string;
76 _ = options;
77 _ = writer;
78 @compileError("do not format Thunk directly");
79}
80
81pub fn fmt(thunk: Thunk, elf_file: *Elf) std.fmt.Formatter(format2) {
68pub fn fmt(thunk: Thunk, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
8269 return .{ .data = .{
8370 .thunk = thunk,
8471 .elf_file = elf_file,
8572 } };
8673}
8774
88const FormatContext = struct {
75const Format = struct {
8976 thunk: Thunk,
9077 elf_file: *Elf,
91};
9278
93fn format2(
94 ctx: FormatContext,
95 comptime unused_fmt_string: []const u8,
96 options: std.fmt.FormatOptions,
97 writer: anytype,
98) !void {
99 _ = options;
100 _ = unused_fmt_string;
101 const thunk = ctx.thunk;
102 const elf_file = ctx.elf_file;
103 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) });
104 for (thunk.symbols.keys()) |ref| {
105 const sym = elf_file.symbol(ref).?;
106 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value });
79 fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
80 const thunk = f.thunk;
81 const elf_file = f.elf_file;
82 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) });
83 for (thunk.symbols.keys()) |ref| {
84 const sym = elf_file.symbol(ref).?;
85 try writer.print(" {f} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value });
86 }
10787 }
108}
88};
10989
11090pub const Index = u32;
11191
src/link/Elf/ZigObject.zig+46-60
......@@ -803,9 +803,9 @@ pub fn initRelaSections(self: *ZigObject, elf_file: *Elf) !void {
803803 const out_shndx = atom_ptr.output_section_index;
804804 const out_shdr = elf_file.sections.items(.shdr)[out_shndx];
805805 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
806 const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{
806 const rela_sect_name = try std.fmt.allocPrintSentinel(gpa, ".rela{s}", .{
807807 elf_file.getShString(out_shdr.sh_name),
808 });
808 }, 0);
809809 defer gpa.free(rela_sect_name);
810810 _ = elf_file.sectionByName(rela_sect_name) orelse
811811 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 {
824824 const out_shndx = atom_ptr.output_section_index;
825825 const out_shdr = elf_file.sections.items(.shdr)[out_shndx];
826826 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
827 const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{
827 const rela_sect_name = try std.fmt.allocPrintSentinel(gpa, ".rela{s}", .{
828828 elf_file.getShString(out_shdr.sh_name),
829 });
829 }, 0);
830830 defer gpa.free(rela_sect_name);
831831 const out_rela_shndx = elf_file.sectionByName(rela_sect_name).?;
832832 const out_rela_shdr = &elf_file.sections.items(.shdr)[out_rela_shndx];
......@@ -925,7 +925,7 @@ pub fn getNavVAddr(
925925 const zcu = pt.zcu;
926926 const ip = &zcu.intern_pool;
927927 const nav = ip.getNav(nav_index);
928 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
928 log.debug("getNavVAddr {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
929929 const this_sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
930930 elf_file,
931931 nav.name.toSlice(ip),
......@@ -1268,7 +1268,7 @@ fn updateNavCode(
12681268 const ip = &zcu.intern_pool;
12691269 const nav = ip.getNav(nav_index);
12701270
1271 log.debug("updateNavCode {}({d})", .{ nav.fqn.fmt(ip), nav_index });
1271 log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
12721272
12731273 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
12741274 const required_alignment = switch (pt.navAlignment(nav_index)) {
......@@ -1302,7 +1302,7 @@ fn updateNavCode(
13021302 self.allocateAtom(atom_ptr, true, elf_file) catch |err|
13031303 return elf_file.base.cgFail(nav_index, "failed to allocate atom: {s}", .{@errorName(err)});
13041304
1305 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });
1305 log.debug("growing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });
13061306 if (old_vaddr != atom_ptr.value) {
13071307 sym.value = 0;
13081308 esym.st_value = 0;
......@@ -1347,7 +1347,7 @@ fn updateNavCode(
13471347 const file_offset = atom_ptr.offset(elf_file);
13481348 elf_file.base.file.?.pwriteAll(code, file_offset) catch |err|
13491349 return elf_file.base.cgFail(nav_index, "failed to write to output file: {s}", .{@errorName(err)});
1350 log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len });
1350 log.debug("writing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len });
13511351 }
13521352}
13531353
......@@ -1365,7 +1365,7 @@ fn updateTlv(
13651365 const gpa = zcu.gpa;
13661366 const nav = ip.getNav(nav_index);
13671367
1368 log.debug("updateTlv {}({d})", .{ nav.fqn.fmt(ip), nav_index });
1368 log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
13691369
13701370 const required_alignment = pt.navAlignment(nav_index);
13711371
......@@ -1424,7 +1424,7 @@ pub fn updateFunc(
14241424 const gpa = elf_file.base.comp.gpa;
14251425 const func = zcu.funcInfo(func_index);
14261426
1427 log.debug("updateFunc {}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav });
1427 log.debug("updateFunc {f}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav });
14281428
14291429 const sym_index = try self.getOrCreateMetadataForNav(zcu, func.owner_nav);
14301430 self.atom(self.symbol(sym_index).ref.index).?.freeRelocs(self);
......@@ -1447,7 +1447,7 @@ pub fn updateFunc(
14471447 const code = code_buffer.items;
14481448
14491449 const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code);
1450 log.debug("setting shdr({x},{s}) for {}", .{
1450 log.debug("setting shdr({x},{s}) for {f}", .{
14511451 shndx,
14521452 elf_file.getShString(elf_file.sections.items(.shdr)[shndx].sh_name),
14531453 ip.getNav(func.owner_nav).fqn.fmt(ip),
......@@ -1529,7 +1529,7 @@ pub fn updateNav(
15291529 const ip = &zcu.intern_pool;
15301530 const nav = ip.getNav(nav_index);
15311531
1532 log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index });
1532 log.debug("updateNav {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
15331533
15341534 const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
15351535 .func => .none,
......@@ -1576,7 +1576,7 @@ pub fn updateNav(
15761576 const code = code_buffer.items;
15771577
15781578 const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code);
1579 log.debug("setting shdr({x},{s}) for {}", .{
1579 log.debug("setting shdr({x},{s}) for {f}", .{
15801580 shndx,
15811581 elf_file.getShString(elf_file.sections.items(.shdr)[shndx].sh_name),
15821582 nav.fqn.fmt(ip),
......@@ -1622,7 +1622,7 @@ fn updateLazySymbol(
16221622 defer code_buffer.deinit(gpa);
16231623
16241624 const name_str_index = blk: {
1625 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1625 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{
16261626 @tagName(sym.kind),
16271627 Type.fromInterned(sym.ty).fmt(pt),
16281628 });
......@@ -1941,7 +1941,7 @@ pub fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, requires_padding: bool, e
19411941 .requires_padding = requires_padding,
19421942 });
19431943 atom_ptr.value = @intCast(alloc_res.value);
1944 log.debug("allocated {s} at {x}\n placement {?}", .{
1944 log.debug("allocated {s} at {x}\n placement {f}", .{
19451945 atom_ptr.name(elf_file),
19461946 atom_ptr.offset(elf_file),
19471947 alloc_res.placement,
......@@ -1986,7 +1986,7 @@ pub fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, requires_padding: bool, e
19861986 atom_ptr.next_atom_ref = .{ .index = 0, .file = 0 };
19871987 }
19881988
1989 log.debug(" prev {?}, next {?}", .{ atom_ptr.prev_atom_ref, atom_ptr.next_atom_ref });
1989 log.debug(" prev {f}, next {f}", .{ atom_ptr.prev_atom_ref, atom_ptr.next_atom_ref });
19901990}
19911991
19921992pub fn resetShdrIndexes(self: *ZigObject, backlinks: []const u32) void {
......@@ -2195,60 +2195,46 @@ pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void {
21952195 }
21962196}
21972197
2198pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
2199 return .{ .data = .{
2200 .self = self,
2201 .elf_file = elf_file,
2202 } };
2203}
2204
2205const FormatContext = struct {
2198const Format = struct {
22062199 self: *ZigObject,
22072200 elf_file: *Elf,
2208};
22092201
2210fn formatSymtab(
2211 ctx: FormatContext,
2212 comptime unused_fmt_string: []const u8,
2213 options: std.fmt.FormatOptions,
2214 writer: anytype,
2215) !void {
2216 _ = unused_fmt_string;
2217 _ = options;
2218 const self = ctx.self;
2219 const elf_file = ctx.elf_file;
2220 try writer.writeAll(" locals\n");
2221 for (self.local_symbols.items) |index| {
2222 const local = self.symbols.items[index];
2223 try writer.print(" {}\n", .{local.fmt(elf_file)});
2202 fn symtab(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
2203 const self = f.self;
2204 const elf_file = f.elf_file;
2205 try writer.writeAll(" locals\n");
2206 for (self.local_symbols.items) |index| {
2207 const local = self.symbols.items[index];
2208 try writer.print(" {f}\n", .{local.fmt(elf_file)});
2209 }
2210 try writer.writeAll(" globals\n");
2211 for (f.self.global_symbols.items) |index| {
2212 const global = self.symbols.items[index];
2213 try writer.print(" {f}\n", .{global.fmt(elf_file)});
2214 }
22242215 }
2225 try writer.writeAll(" globals\n");
2226 for (ctx.self.global_symbols.items) |index| {
2227 const global = self.symbols.items[index];
2228 try writer.print(" {}\n", .{global.fmt(elf_file)});
2216
2217 fn atoms(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
2218 try writer.writeAll(" atoms\n");
2219 for (f.self.atoms_indexes.items) |atom_index| {
2220 const atom_ptr = f.self.atom(atom_index) orelse continue;
2221 try writer.print(" {f}\n", .{atom_ptr.fmt(f.elf_file)});
2222 }
22292223 }
2230}
2224};
22312225
2232pub fn fmtAtoms(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatAtoms) {
2226pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(Format, Format.symtab) {
22332227 return .{ .data = .{
22342228 .self = self,
22352229 .elf_file = elf_file,
22362230 } };
22372231}
22382232
2239fn formatAtoms(
2240 ctx: FormatContext,
2241 comptime unused_fmt_string: []const u8,
2242 options: std.fmt.FormatOptions,
2243 writer: anytype,
2244) !void {
2245 _ = unused_fmt_string;
2246 _ = options;
2247 try writer.writeAll(" atoms\n");
2248 for (ctx.self.atoms_indexes.items) |atom_index| {
2249 const atom_ptr = ctx.self.atom(atom_index) orelse continue;
2250 try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
2251 }
2233pub fn fmtAtoms(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(Format, Format.atoms) {
2234 return .{ .data = .{
2235 .self = self,
2236 .elf_file = elf_file,
2237 } };
22522238}
22532239
22542240const ElfSym = struct {
......@@ -2285,7 +2271,7 @@ fn checkNavAllocated(pt: Zcu.PerThread, index: InternPool.Nav.Index, meta: AvMet
22852271 const zcu = pt.zcu;
22862272 const ip = &zcu.intern_pool;
22872273 const nav = ip.getNav(index);
2288 log.err("NAV {}({d}) assigned symbol {d} but not allocated!", .{
2274 log.err("NAV {f}({d}) assigned symbol {d} but not allocated!", .{
22892275 nav.fqn.fmt(ip),
22902276 index,
22912277 meta.symbol_index,
......@@ -2298,7 +2284,7 @@ fn checkUavAllocated(pt: Zcu.PerThread, index: InternPool.Index, meta: AvMetadat
22982284 const zcu = pt.zcu;
22992285 const uav = Value.fromInterned(index);
23002286 const ty = uav.typeOf(zcu);
2301 log.err("UAV {}({d}) assigned symbol {d} but not allocated!", .{
2287 log.err("UAV {f}({d}) assigned symbol {d} but not allocated!", .{
23022288 ty.fmt(pt),
23032289 index,
23042290 meta.symbol_index,
src/link/Elf/eh_frame.zig+34-74
......@@ -47,52 +47,32 @@ pub const Fde = struct {
4747 return object.relocs.items[fde.rel_index..][0..fde.rel_num];
4848 }
4949
50 pub fn format(
51 fde: Fde,
52 comptime unused_fmt_string: []const u8,
53 options: std.fmt.FormatOptions,
54 writer: anytype,
55 ) !void {
56 _ = fde;
57 _ = unused_fmt_string;
58 _ = options;
59 _ = writer;
60 @compileError("do not format FDEs directly");
61 }
62
63 pub fn fmt(fde: Fde, elf_file: *Elf) std.fmt.Formatter(format2) {
50 pub fn fmt(fde: Fde, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
6451 return .{ .data = .{
6552 .fde = fde,
6653 .elf_file = elf_file,
6754 } };
6855 }
6956
70 const FdeFormatContext = struct {
57 const Format = struct {
7158 fde: Fde,
7259 elf_file: *Elf,
73 };
7460
75 fn format2(
76 ctx: FdeFormatContext,
77 comptime unused_fmt_string: []const u8,
78 options: std.fmt.FormatOptions,
79 writer: anytype,
80 ) !void {
81 _ = unused_fmt_string;
82 _ = options;
83 const fde = ctx.fde;
84 const elf_file = ctx.elf_file;
85 const base_addr = fde.address(elf_file);
86 const object = elf_file.file(fde.file_index).?.object;
87 const atom_name = fde.atom(object).name(elf_file);
88 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
89 base_addr + fde.out_offset,
90 fde.calcSize(),
91 fde.cie_index,
92 atom_name,
93 });
94 if (!fde.alive) try writer.writeAll(" : [*]");
95 }
61 fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
62 const fde = f.fde;
63 const elf_file = f.elf_file;
64 const base_addr = fde.address(elf_file);
65 const object = elf_file.file(fde.file_index).?.object;
66 const atom_name = fde.atom(object).name(elf_file);
67 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
68 base_addr + fde.out_offset,
69 fde.calcSize(),
70 fde.cie_index,
71 atom_name,
72 });
73 if (!fde.alive) try writer.writeAll(" : [*]");
74 }
75 };
9676};
9777
9878pub const Cie = struct {
......@@ -150,48 +130,28 @@ pub const Cie = struct {
150130 return true;
151131 }
152132
153 pub fn format(
154 cie: Cie,
155 comptime unused_fmt_string: []const u8,
156 options: std.fmt.FormatOptions,
157 writer: anytype,
158 ) !void {
159 _ = cie;
160 _ = unused_fmt_string;
161 _ = options;
162 _ = writer;
163 @compileError("do not format CIEs directly");
164 }
165
166 pub fn fmt(cie: Cie, elf_file: *Elf) std.fmt.Formatter(format2) {
133 pub fn fmt(cie: Cie, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
167134 return .{ .data = .{
168135 .cie = cie,
169136 .elf_file = elf_file,
170137 } };
171138 }
172139
173 const CieFormatContext = struct {
140 const Format = struct {
174141 cie: Cie,
175142 elf_file: *Elf,
176 };
177143
178 fn format2(
179 ctx: CieFormatContext,
180 comptime unused_fmt_string: []const u8,
181 options: std.fmt.FormatOptions,
182 writer: anytype,
183 ) !void {
184 _ = unused_fmt_string;
185 _ = options;
186 const cie = ctx.cie;
187 const elf_file = ctx.elf_file;
188 const base_addr = cie.address(elf_file);
189 try writer.print("@{x} : size({x})", .{
190 base_addr + cie.out_offset,
191 cie.calcSize(),
192 });
193 if (!cie.alive) try writer.writeAll(" : [*]");
194 }
144 fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
145 const cie = f.cie;
146 const elf_file = f.elf_file;
147 const base_addr = cie.address(elf_file);
148 try writer.print("@{x} : size({x})", .{
149 base_addr + cie.out_offset,
150 cie.calcSize(),
151 });
152 if (!cie.alive) try writer.writeAll(" : [*]");
153 }
154 };
195155};
196156
197157pub const Iterator = struct {
......@@ -316,7 +276,7 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file:
316276 const S = math.cast(i64, sym.address(.{}, elf_file)) orelse return error.Overflow;
317277 const A = rel.r_addend;
318278
319 relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{
279 relocs_log.debug(" {f}: {x}: [{x} => {x}] ({s})", .{
320280 relocation.fmtRelocType(rel.r_type(), cpu_arch),
321281 offset,
322282 P,
......@@ -438,7 +398,7 @@ fn emitReloc(elf_file: *Elf, r_offset: u64, sym: *const Symbol, rel: elf.Elf64_R
438398 },
439399 }
440400
441 relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
401 relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{
442402 relocation.fmtRelocType(r_type, cpu_arch),
443403 r_offset,
444404 r_sym,
......@@ -607,11 +567,11 @@ const riscv = struct {
607567fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {
608568 const diags = &elf_file.base.comp.link_diags;
609569 var err = try diags.addErrorWithNotes(1);
610 try err.addMsg("invalid relocation type {} at offset 0x{x}", .{
570 try err.addMsg("invalid relocation type {f} at offset 0x{x}", .{
611571 relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
612572 rel.r_offset,
613573 });
614 err.addNote("in {}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()});
574 err.addNote("in {f}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()});
615575 return error.RelocFailure;
616576}
617577
src/link/Elf/file.zig+4-11
......@@ -10,23 +10,16 @@ pub const File = union(enum) {
1010 };
1111 }
1212
13 pub fn fmtPath(file: File) std.fmt.Formatter(formatPath) {
13 pub fn fmtPath(file: File) std.fmt.Formatter(File, formatPath) {
1414 return .{ .data = file };
1515 }
1616
17 fn formatPath(
18 file: File,
19 comptime unused_fmt_string: []const u8,
20 options: std.fmt.FormatOptions,
21 writer: anytype,
22 ) !void {
23 _ = unused_fmt_string;
24 _ = options;
17 fn formatPath(file: File, writer: *std.io.Writer) std.io.Writer.Error!void {
2518 switch (file) {
2619 .zig_object => |zo| try writer.writeAll(zo.basename),
2720 .linker_defined => try writer.writeAll("(linker defined)"),
28 .object => |x| try writer.print("{}", .{x.fmtPath()}),
29 .shared_object => |x| try writer.print("{}", .{@as(Path, x.path)}),
21 .object => |x| try writer.print("{f}", .{x.fmtPath()}),
22 .shared_object => |x| try writer.print("{f}", .{@as(Path, x.path)}),
3023 }
3124 }
3225
src/link/Elf/gc.zig+6-13
......@@ -111,7 +111,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
111111 const target_sym = elf_file.symbol(ref) orelse continue;
112112 const target_atom = target_sym.atom(elf_file) orelse continue;
113113 target_atom.alive = true;
114 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
114 gc_track_live_log.debug("{f}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
115115 if (markAtom(target_atom)) markLive(target_atom, elf_file);
116116 }
117117 }
......@@ -128,7 +128,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
128128 }
129129 const target_atom = target_sym.atom(elf_file) orelse continue;
130130 target_atom.alive = true;
131 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
131 gc_track_live_log.debug("{f}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
132132 if (markAtom(target_atom)) markLive(target_atom, elf_file);
133133 }
134134}
......@@ -163,14 +163,14 @@ fn prune(elf_file: *Elf) void {
163163}
164164
165165pub fn dumpPrunedAtoms(elf_file: *Elf) !void {
166 const stderr = std.io.getStdErr().writer();
166 const stderr = std.fs.File.stderr().deprecatedWriter();
167167 for (elf_file.objects.items) |index| {
168168 const file = elf_file.file(index).?;
169169 for (file.atoms()) |atom_index| {
170170 const atom = file.atom(atom_index) orelse continue;
171171 if (!atom.alive)
172172 // TODO should we simply print to stderr?
173 try stderr.print("link: removing unused section '{s}' in file '{}'\n", .{
173 try stderr.print("link: removing unused section '{s}' in file '{f}'\n", .{
174174 atom.name(elf_file),
175175 atom.file(elf_file).?.fmtPath(),
176176 });
......@@ -185,15 +185,8 @@ const Level = struct {
185185 self.value += 1;
186186 }
187187
188 pub fn format(
189 self: *const @This(),
190 comptime unused_fmt_string: []const u8,
191 options: std.fmt.FormatOptions,
192 writer: anytype,
193 ) !void {
194 _ = unused_fmt_string;
195 _ = options;
196 try writer.writeByteNTimes(' ', self.value);
188 pub fn format(self: *const @This(), w: *std.io.Writer) std.io.Writer.Error!void {
189 try w.splatByteAll(' ', self.value);
197190 }
198191};
199192
src/link/Elf/relocatable.zig+4-4
......@@ -31,7 +31,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
3131 try elf_file.allocateNonAllocSections();
3232
3333 if (build_options.enable_logging) {
34 state_log.debug("{}", .{elf_file.dumpState()});
34 state_log.debug("{f}", .{elf_file.dumpState()});
3535 }
3636
3737 try elf_file.writeMergeSections();
......@@ -96,8 +96,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
9696 };
9797
9898 if (build_options.enable_logging) {
99 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(elf_file)});
100 state_log.debug("ar_strtab\n{}\n", .{ar_strtab});
99 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)});
100 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
101101 }
102102
103103 var buffer = std.ArrayList(u8).init(gpa);
......@@ -170,7 +170,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void {
170170 try elf_file.allocateNonAllocSections();
171171
172172 if (build_options.enable_logging) {
173 state_log.debug("{}", .{elf_file.dumpState()});
173 state_log.debug("{f}", .{elf_file.dumpState()});
174174 }
175175
176176 try writeAtoms(elf_file);
src/link/Elf/relocation.zig+2-9
......@@ -141,21 +141,14 @@ const FormatRelocTypeCtx = struct {
141141 cpu_arch: std.Target.Cpu.Arch,
142142};
143143
144pub fn fmtRelocType(r_type: u32, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatRelocType) {
144pub fn fmtRelocType(r_type: u32, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(FormatRelocTypeCtx, formatRelocType) {
145145 return .{ .data = .{
146146 .r_type = r_type,
147147 .cpu_arch = cpu_arch,
148148 } };
149149}
150150
151fn formatRelocType(
152 ctx: FormatRelocTypeCtx,
153 comptime unused_fmt_string: []const u8,
154 options: std.fmt.FormatOptions,
155 writer: anytype,
156) !void {
157 _ = unused_fmt_string;
158 _ = options;
151fn formatRelocType(ctx: FormatRelocTypeCtx, writer: *std.io.Writer) std.io.Writer.Error!void {
159152 const r_type = ctx.r_type;
160153 switch (ctx.cpu_arch) {
161154 .x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}),
src/link/Elf/synthetic_sections.zig+37-51
......@@ -606,37 +606,30 @@ pub const GotSection = struct {
606606 }
607607 }
608608
609 const FormatCtx = struct {
609 const Format = struct {
610610 got: GotSection,
611611 elf_file: *Elf,
612
613 pub fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
614 const got = f.got;
615 const elf_file = f.elf_file;
616 try writer.writeAll("GOT\n");
617 for (got.entries.items) |entry| {
618 const symbol = elf_file.symbol(entry.ref).?;
619 try writer.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
620 entry.cell_index,
621 entry.address(elf_file),
622 entry.ref,
623 symbol.address(.{}, elf_file),
624 symbol.name(elf_file),
625 });
626 }
627 }
612628 };
613629
614 pub fn fmt(got: GotSection, elf_file: *Elf) std.fmt.Formatter(format2) {
630 pub fn fmt(got: GotSection, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
615631 return .{ .data = .{ .got = got, .elf_file = elf_file } };
616632 }
617
618 pub fn format2(
619 ctx: FormatCtx,
620 comptime unused_fmt_string: []const u8,
621 options: std.fmt.FormatOptions,
622 writer: anytype,
623 ) !void {
624 _ = options;
625 _ = unused_fmt_string;
626 const got = ctx.got;
627 const elf_file = ctx.elf_file;
628 try writer.writeAll("GOT\n");
629 for (got.entries.items) |entry| {
630 const symbol = elf_file.symbol(entry.ref).?;
631 try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{
632 entry.cell_index,
633 entry.address(elf_file),
634 entry.ref,
635 symbol.address(.{}, elf_file),
636 symbol.name(elf_file),
637 });
638 }
639 }
640633};
641634
642635pub const PltSection = struct {
......@@ -703,7 +696,7 @@ pub const PltSection = struct {
703696 const r_sym: u64 = extra.dynamic;
704697 const r_type = relocation.encode(.jump_slot, cpu_arch);
705698
706 relocs_log.debug(" {s}: [{x} => {d}({s})] + 0", .{
699 relocs_log.debug(" {f}: [{x} => {d}({s})] + 0", .{
707700 relocation.fmtRelocType(r_type, cpu_arch),
708701 r_offset,
709702 r_sym,
......@@ -749,38 +742,31 @@ pub const PltSection = struct {
749742 }
750743 }
751744
752 const FormatCtx = struct {
745 const Format = struct {
753746 plt: PltSection,
754747 elf_file: *Elf,
748
749 pub fn default(f: Format, writer: *std.io.Writer) std.io.Writer.Error!void {
750 const plt = f.plt;
751 const elf_file = f.elf_file;
752 try writer.writeAll("PLT\n");
753 for (plt.symbols.items, 0..) |ref, i| {
754 const symbol = elf_file.symbol(ref).?;
755 try writer.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
756 i,
757 symbol.pltAddress(elf_file),
758 ref,
759 symbol.address(.{}, elf_file),
760 symbol.name(elf_file),
761 });
762 }
763 }
755764 };
756765
757 pub fn fmt(plt: PltSection, elf_file: *Elf) std.fmt.Formatter(format2) {
766 pub fn fmt(plt: PltSection, elf_file: *Elf) std.fmt.Formatter(Format, Format.default) {
758767 return .{ .data = .{ .plt = plt, .elf_file = elf_file } };
759768 }
760769
761 pub fn format2(
762 ctx: FormatCtx,
763 comptime unused_fmt_string: []const u8,
764 options: std.fmt.FormatOptions,
765 writer: anytype,
766 ) !void {
767 _ = options;
768 _ = unused_fmt_string;
769 const plt = ctx.plt;
770 const elf_file = ctx.elf_file;
771 try writer.writeAll("PLT\n");
772 for (plt.symbols.items, 0..) |ref, i| {
773 const symbol = elf_file.symbol(ref).?;
774 try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{
775 i,
776 symbol.pltAddress(elf_file),
777 ref,
778 symbol.address(.{}, elf_file),
779 symbol.name(elf_file),
780 });
781 }
782 }
783
784770 const x86_64 = struct {
785771 fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {
786772 const shdrs = elf_file.sections.items(.shdr);
src/link/LdScript.zig+2-2
......@@ -41,8 +41,8 @@ pub fn parse(
4141 try line_col.append(gpa, .{ .line = line, .column = column });
4242 switch (tok.id) {
4343 .invalid => {
44 return diags.failParse(path, "invalid token in LD script: '{s}' ({d}:{d})", .{
45 std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,
44 return diags.failParse(path, "invalid token in LD script: '{f}' ({d}:{d})", .{
45 std.ascii.hexEscape(tok.get(data), .lower), line, column,
4646 });
4747 },
4848 .new_line => {
src/link/Lld.zig+12-16
......@@ -294,7 +294,7 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void {
294294 break :p try comp.resolveEmitPathFlush(arena, .temp, base.zcu_object_basename.?);
295295 } else null;
296296
297 log.debug("zcu_obj_path={?}", .{zcu_obj_path});
297 log.debug("zcu_obj_path={?f}", .{zcu_obj_path});
298298
299299 const compiler_rt_path: ?Cache.Path = if (comp.compiler_rt_strat == .obj)
300300 comp.compiler_rt_obj.?.full_object_path
......@@ -437,7 +437,7 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {
437437 try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb_basename}));
438438 }
439439 if (comp.version) |version| {
440 try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor }));
440 try argv.append(try allocPrint(arena, "-VERSION:{d}.{d}", .{ version.major, version.minor }));
441441 }
442442
443443 if (target_util.llvmMachineAbi(target)) |mabi| {
......@@ -507,7 +507,7 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {
507507
508508 if (comp.emit_implib) |raw_emit_path| {
509509 const path = try comp.resolveEmitPathFlush(arena, .temp, raw_emit_path);
510 try argv.append(try allocPrint(arena, "-IMPLIB:{}", .{path}));
510 try argv.append(try allocPrint(arena, "-IMPLIB:{f}", .{path}));
511511 }
512512
513513 if (comp.config.link_libc) {
......@@ -533,7 +533,7 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {
533533 },
534534 .object, .archive => |obj| {
535535 if (obj.must_link) {
536 argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{}", .{@as(Cache.Path, obj.path)}));
536 argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{f}", .{@as(Cache.Path, obj.path)}));
537537 } else {
538538 argv.appendAssumeCapacity(try obj.path.toString(arena));
539539 }
......@@ -933,9 +933,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
933933 .fast, .uuid, .sha1, .md5 => try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{
934934 @tagName(base.build_id),
935935 })),
936 .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{
937 std.fmt.fmtSliceHexLower(hs.toSlice()),
938 })),
936 .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{x}", .{hs.toSlice()})),
939937 }
940938
941939 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{elf.image_base}));
......@@ -1218,7 +1216,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
12181216 if (target.os.versionRange().gnuLibCVersion().?.order(rem_in) != .lt) continue;
12191217 }
12201218
1221 const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
1219 const lib_path = try std.fmt.allocPrint(arena, "{f}{c}lib{s}.so.{d}", .{
12221220 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
12231221 });
12241222 try argv.append(lib_path);
......@@ -1231,14 +1229,14 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
12311229 }));
12321230 } else if (target.isFreeBSDLibC()) {
12331231 for (freebsd.libs) |lib| {
1234 const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
1232 const lib_path = try std.fmt.allocPrint(arena, "{f}{c}lib{s}.so.{d}", .{
12351233 comp.freebsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
12361234 });
12371235 try argv.append(lib_path);
12381236 }
12391237 } else if (target.isNetBSDLibC()) {
12401238 for (netbsd.libs) |lib| {
1241 const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
1239 const lib_path = try std.fmt.allocPrint(arena, "{f}{c}lib{s}.so.{d}", .{
12421240 comp.netbsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
12431241 });
12441242 try argv.append(lib_path);
......@@ -1511,9 +1509,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
15111509 .fast, .uuid, .sha1 => try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{
15121510 @tagName(base.build_id),
15131511 })),
1514 .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{
1515 std.fmt.fmtSliceHexLower(hs.toSlice()),
1516 })),
1512 .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{x}", .{hs.toSlice()})),
15171513 .md5 => {},
15181514 }
15191515
......@@ -1653,7 +1649,7 @@ fn spawnLld(
16531649 child.stderr_behavior = .Pipe;
16541650
16551651 child.spawn() catch |err| break :term err;
1656 stderr = try child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize));
1652 stderr = try child.stderr.?.deprecatedReader().readAllAlloc(comp.gpa, std.math.maxInt(usize));
16571653 break :term child.wait();
16581654 }) catch |first_err| term: {
16591655 const err = switch (first_err) {
......@@ -1667,7 +1663,7 @@ fn spawnLld(
16671663 log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) });
16681664 {
16691665 defer rsp_file.close();
1670 var rsp_buf = std.io.bufferedWriter(rsp_file.writer());
1666 var rsp_buf = std.io.bufferedWriter(rsp_file.deprecatedWriter());
16711667 const rsp_writer = rsp_buf.writer();
16721668 for (argv[2..]) |arg| {
16731669 try rsp_writer.writeByte('"');
......@@ -1701,7 +1697,7 @@ fn spawnLld(
17011697 rsp_child.stderr_behavior = .Pipe;
17021698
17031699 rsp_child.spawn() catch |err| break :err err;
1704 stderr = try rsp_child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize));
1700 stderr = try rsp_child.stderr.?.deprecatedReader().readAllAlloc(comp.gpa, std.math.maxInt(usize));
17051701 break :term rsp_child.wait() catch |err| break :err err;
17061702 }
17071703 },
src/link/MachO.zig+56-97
......@@ -543,7 +543,7 @@ pub fn flush(
543543 self.allocateSyntheticSymbols();
544544
545545 if (build_options.enable_logging) {
546 state_log.debug("{}", .{self.dumpState()});
546 state_log.debug("{f}", .{self.dumpState()});
547547 }
548548
549549 // Beyond this point, everything has been allocated a virtual address and we can resolve
......@@ -677,12 +677,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
677677
678678 try argv.append("-platform_version");
679679 try argv.append(@tagName(self.platform.os_tag));
680 try argv.append(try std.fmt.allocPrint(arena, "{}", .{self.platform.version}));
680 try argv.append(try std.fmt.allocPrint(arena, "{f}", .{self.platform.version}));
681681
682682 if (self.sdk_version) |ver| {
683683 try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor }));
684684 } else {
685 try argv.append(try std.fmt.allocPrint(arena, "{}", .{self.platform.version}));
685 try argv.append(try std.fmt.allocPrint(arena, "{f}", .{self.platform.version}));
686686 }
687687
688688 if (comp.sysroot) |syslibroot| {
......@@ -863,7 +863,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
863863
864864 const path, const file = input.pathAndFile().?;
865865 // TODO don't classify now, it's too late. The input file has already been classified
866 log.debug("classifying input file {}", .{path});
866 log.debug("classifying input file {f}", .{path});
867867
868868 const fh = try self.addFileHandle(file);
869869 var buffer: [Archive.SARMAG]u8 = undefined;
......@@ -1591,7 +1591,7 @@ fn reportUndefs(self: *MachO) !void {
15911591 const ref = refs.items[inote];
15921592 const file = self.getFile(ref.file).?;
15931593 const atom = ref.getAtom(self).?;
1594 err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });
1594 err.addNote("referenced by {f}:{s}", .{ file.fmtPath(), atom.getName(self) });
15951595 }
15961596
15971597 if (refs.items.len > max_notes) {
......@@ -3791,7 +3791,7 @@ pub fn reportParseError2(
37913791 const diags = &self.base.comp.link_diags;
37923792 var err = try diags.addErrorWithNotes(1);
37933793 try err.addMsg(format, args);
3794 err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()});
3794 err.addNote("while parsing {f}", .{self.getFile(file_index).?.fmtPath()});
37953795}
37963796
37973797fn reportMissingDependencyError(
......@@ -3806,7 +3806,7 @@ fn reportMissingDependencyError(
38063806 var err = try diags.addErrorWithNotes(2 + checked_paths.len);
38073807 try err.addMsg(format, args);
38083808 err.addNote("while resolving {s}", .{path});
3809 err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
3809 err.addNote("a dependency of {f}", .{self.getFile(parent).?.fmtPath()});
38103810 for (checked_paths) |p| {
38113811 err.addNote("tried {s}", .{p});
38123812 }
......@@ -3823,7 +3823,7 @@ fn reportDependencyError(
38233823 var err = try diags.addErrorWithNotes(2);
38243824 try err.addMsg(format, args);
38253825 err.addNote("while parsing {s}", .{path});
3826 err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
3826 err.addNote("a dependency of {f}", .{self.getFile(parent).?.fmtPath()});
38273827}
38283828
38293829fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
......@@ -3853,12 +3853,12 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
38533853
38543854 var err = try diags.addErrorWithNotes(nnotes + 1);
38553855 try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});
3856 err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});
3856 err.addNote("defined by {f}", .{sym.getFile(self).?.fmtPath()});
38573857
38583858 var inote: usize = 0;
38593859 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
38603860 const file = self.getFile(notes.items[inote]).?;
3861 err.addNote("defined by {}", .{file.fmtPath()});
3861 err.addNote("defined by {f}", .{file.fmtPath()});
38623862 }
38633863
38643864 if (notes.items.len > max_notes) {
......@@ -3900,35 +3900,28 @@ pub fn ptraceDetach(self: *MachO, pid: std.posix.pid_t) !void {
39003900 self.hot_state.mach_task = null;
39013901}
39023902
3903pub fn dumpState(self: *MachO) std.fmt.Formatter(fmtDumpState) {
3903pub fn dumpState(self: *MachO) std.fmt.Formatter(*MachO, fmtDumpState) {
39043904 return .{ .data = self };
39053905}
39063906
3907fn fmtDumpState(
3908 self: *MachO,
3909 comptime unused_fmt_string: []const u8,
3910 options: std.fmt.FormatOptions,
3911 writer: anytype,
3912) !void {
3913 _ = options;
3914 _ = unused_fmt_string;
3907fn fmtDumpState(self: *MachO, w: *Writer) Writer.Error!void {
39153908 if (self.getZigObject()) |zo| {
3916 try writer.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename });
3917 try writer.print("{}{}\n", .{
3909 try w.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename });
3910 try w.print("{f}{f}\n", .{
39183911 zo.fmtAtoms(self),
39193912 zo.fmtSymtab(self),
39203913 });
39213914 }
39223915 for (self.objects.items) |index| {
39233916 const object = self.getFile(index).?.object;
3924 try writer.print("object({d}) : {} : has_debug({})", .{
3917 try w.print("object({d}) : {f} : has_debug({})", .{
39253918 index,
39263919 object.fmtPath(),
39273920 object.hasDebugInfo(),
39283921 });
3929 if (!object.alive) try writer.writeAll(" : ([*])");
3930 try writer.writeByte('\n');
3931 try writer.print("{}{}{}{}{}\n", .{
3922 if (!object.alive) try w.writeAll(" : ([*])");
3923 try w.writeByte('\n');
3924 try w.print("{f}{f}{f}{f}{f}\n", .{
39323925 object.fmtAtoms(self),
39333926 object.fmtCies(self),
39343927 object.fmtFdes(self),
......@@ -3938,48 +3931,41 @@ fn fmtDumpState(
39383931 }
39393932 for (self.dylibs.items) |index| {
39403933 const dylib = self.getFile(index).?.dylib;
3941 try writer.print("dylib({d}) : {} : needed({}) : weak({})", .{
3934 try w.print("dylib({d}) : {f} : needed({}) : weak({})", .{
39423935 index,
39433936 @as(Path, dylib.path),
39443937 dylib.needed,
39453938 dylib.weak,
39463939 });
3947 if (!dylib.isAlive(self)) try writer.writeAll(" : ([*])");
3948 try writer.writeByte('\n');
3949 try writer.print("{}\n", .{dylib.fmtSymtab(self)});
3940 if (!dylib.isAlive(self)) try w.writeAll(" : ([*])");
3941 try w.writeByte('\n');
3942 try w.print("{f}\n", .{dylib.fmtSymtab(self)});
39503943 }
39513944 if (self.getInternalObject()) |internal| {
3952 try writer.print("internal({d}) : internal\n", .{internal.index});
3953 try writer.print("{}{}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) });
3945 try w.print("internal({d}) : internal\n", .{internal.index});
3946 try w.print("{f}{f}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) });
39543947 }
3955 try writer.writeAll("thunks\n");
3948 try w.writeAll("thunks\n");
39563949 for (self.thunks.items, 0..) |thunk, index| {
3957 try writer.print("thunk({d}) : {}\n", .{ index, thunk.fmt(self) });
3950 try w.print("thunk({d}) : {f}\n", .{ index, thunk.fmt(self) });
39583951 }
3959 try writer.print("stubs\n{}\n", .{self.stubs.fmt(self)});
3960 try writer.print("objc_stubs\n{}\n", .{self.objc_stubs.fmt(self)});
3961 try writer.print("got\n{}\n", .{self.got.fmt(self)});
3962 try writer.print("tlv_ptr\n{}\n", .{self.tlv_ptr.fmt(self)});
3963 try writer.writeByte('\n');
3964 try writer.print("sections\n{}\n", .{self.fmtSections()});
3965 try writer.print("segments\n{}\n", .{self.fmtSegments()});
3952 try w.print("stubs\n{f}\n", .{self.stubs.fmt(self)});
3953 try w.print("objc_stubs\n{f}\n", .{self.objc_stubs.fmt(self)});
3954 try w.print("got\n{f}\n", .{self.got.fmt(self)});
3955 try w.print("tlv_ptr\n{f}\n", .{self.tlv_ptr.fmt(self)});
3956 try w.writeByte('\n');
3957 try w.print("sections\n{f}\n", .{self.fmtSections()});
3958 try w.print("segments\n{f}\n", .{self.fmtSegments()});
39663959}
39673960
3968fn fmtSections(self: *MachO) std.fmt.Formatter(formatSections) {
3961fn fmtSections(self: *MachO) std.fmt.Formatter(*MachO, formatSections) {
39693962 return .{ .data = self };
39703963}
39713964
3972fn formatSections(
3973 self: *MachO,
3974 comptime unused_fmt_string: []const u8,
3975 options: std.fmt.FormatOptions,
3976 writer: anytype,
3977) !void {
3978 _ = options;
3979 _ = unused_fmt_string;
3965fn formatSections(self: *MachO, w: *Writer) Writer.Error!void {
39803966 const slice = self.sections.slice();
39813967 for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| {
3982 try writer.print(
3968 try w.print(
39833969 "sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x}) : relocs({x};{d})\n",
39843970 .{
39853971 i, seg_id, header.segName(), header.sectName(), header.addr, header.offset,
......@@ -3989,38 +3975,24 @@ fn formatSections(
39893975 }
39903976}
39913977
3992fn fmtSegments(self: *MachO) std.fmt.Formatter(formatSegments) {
3978fn fmtSegments(self: *MachO) std.fmt.Formatter(*MachO, formatSegments) {
39933979 return .{ .data = self };
39943980}
39953981
3996fn formatSegments(
3997 self: *MachO,
3998 comptime unused_fmt_string: []const u8,
3999 options: std.fmt.FormatOptions,
4000 writer: anytype,
4001) !void {
4002 _ = options;
4003 _ = unused_fmt_string;
3982fn formatSegments(self: *MachO, w: *Writer) Writer.Error!void {
40043983 for (self.segments.items, 0..) |seg, i| {
4005 try writer.print("seg({d}) : {s} : @{x}-{x} ({x}-{x})\n", .{
3984 try w.print("seg({d}) : {s} : @{x}-{x} ({x}-{x})\n", .{
40063985 i, seg.segName(), seg.vmaddr, seg.vmaddr + seg.vmsize,
40073986 seg.fileoff, seg.fileoff + seg.filesize,
40083987 });
40093988 }
40103989}
40113990
4012pub fn fmtSectType(tt: u8) std.fmt.Formatter(formatSectType) {
3991pub fn fmtSectType(tt: u8) std.fmt.Formatter(u8, formatSectType) {
40133992 return .{ .data = tt };
40143993}
40153994
4016fn formatSectType(
4017 tt: u8,
4018 comptime unused_fmt_string: []const u8,
4019 options: std.fmt.FormatOptions,
4020 writer: anytype,
4021) !void {
4022 _ = options;
4023 _ = unused_fmt_string;
3995fn formatSectType(tt: u8, w: *Writer) Writer.Error!void {
40243996 const name = switch (tt) {
40253997 macho.S_REGULAR => "REGULAR",
40263998 macho.S_ZEROFILL => "ZEROFILL",
......@@ -4044,9 +4016,9 @@ fn formatSectType(
40444016 macho.S_THREAD_LOCAL_VARIABLE_POINTERS => "THREAD_LOCAL_VARIABLE_POINTERS",
40454017 macho.S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => "THREAD_LOCAL_INIT_FUNCTION_POINTERS",
40464018 macho.S_INIT_FUNC_OFFSETS => "INIT_FUNC_OFFSETS",
4047 else => |x| return writer.print("UNKNOWN({x})", .{x}),
4019 else => |x| return w.print("UNKNOWN({x})", .{x}),
40484020 };
4049 try writer.print("{s}", .{name});
4021 try w.print("{s}", .{name});
40504022}
40514023
40524024const is_hot_update_compatible = switch (builtin.target.os.tag) {
......@@ -4279,34 +4251,27 @@ pub const Platform = struct {
42794251 return false;
42804252 }
42814253
4282 pub fn fmtTarget(plat: Platform, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatTarget) {
4254 pub fn fmtTarget(plat: Platform, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(Format, Format.target) {
42834255 return .{ .data = .{ .platform = plat, .cpu_arch = cpu_arch } };
42844256 }
42854257
4286 const FmtCtx = struct {
4258 const Format = struct {
42874259 platform: Platform,
42884260 cpu_arch: std.Target.Cpu.Arch,
4289 };
42904261
4291 pub fn formatTarget(
4292 ctx: FmtCtx,
4293 comptime unused_fmt_string: []const u8,
4294 options: std.fmt.FormatOptions,
4295 writer: anytype,
4296 ) !void {
4297 _ = unused_fmt_string;
4298 _ = options;
4299 try writer.print("{s}-{s}", .{ @tagName(ctx.cpu_arch), @tagName(ctx.platform.os_tag) });
4300 if (ctx.platform.abi != .none) {
4301 try writer.print("-{s}", .{@tagName(ctx.platform.abi)});
4262 pub fn target(f: Format, w: *Writer) Writer.Error!void {
4263 try w.print("{s}-{s}", .{ @tagName(f.cpu_arch), @tagName(f.platform.os_tag) });
4264 if (f.platform.abi != .none) {
4265 try w.print("-{s}", .{@tagName(f.platform.abi)});
4266 }
43024267 }
4303 }
4268 };
43044269
43054270 /// Caller owns the memory.
43064271 pub fn allocPrintTarget(plat: Platform, gpa: Allocator, cpu_arch: std.Target.Cpu.Arch) error{OutOfMemory}![]u8 {
43074272 var buffer = std.ArrayList(u8).init(gpa);
43084273 defer buffer.deinit();
4309 try buffer.writer().print("{}", .{plat.fmtTarget(cpu_arch)});
4274 try buffer.writer().print("{f}", .{plat.fmtTarget(cpu_arch)});
43104275 return buffer.toOwnedSlice();
43114276 }
43124277
......@@ -4507,15 +4472,8 @@ pub const Ref = struct {
45074472 };
45084473 }
45094474
4510 pub fn format(
4511 ref: Ref,
4512 comptime unused_fmt_string: []const u8,
4513 options: std.fmt.FormatOptions,
4514 writer: anytype,
4515 ) !void {
4516 _ = unused_fmt_string;
4517 _ = options;
4518 try writer.print("%{d} in file({d})", .{ ref.index, ref.file });
4475 pub fn format(ref: Ref, bw: *Writer) Writer.Error!void {
4476 try bw.print("%{d} in file({d})", .{ ref.index, ref.file });
45194477 }
45204478};
45214479
......@@ -5315,7 +5273,7 @@ fn createThunks(macho_file: *MachO, sect_id: u8) !void {
53155273 try scanThunkRelocs(thunk_index, gpa, atoms[start..i], macho_file);
53165274 thunk.value = advanceSection(header, thunk.size(), .@"4");
53175275
5318 log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) });
5276 log.debug("thunk({d}) : {f}", .{ thunk_index, thunk.fmt(macho_file) });
53195277 }
53205278}
53215279
......@@ -5414,6 +5372,7 @@ const macho = std.macho;
54145372const math = std.math;
54155373const mem = std.mem;
54165374const meta = std.meta;
5375const Writer = std.io.Writer;
54175376
54185377const aarch64 = @import("../arch/aarch64/bits.zig");
54195378const bind = @import("MachO/dyld_info/bind.zig");
src/link/MachO/Archive.zig+17-23
......@@ -29,8 +29,8 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
2929 pos += @sizeOf(ar_hdr);
3030
3131 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
32 return diags.failParse(path, "invalid header delimiter: expected '{s}', found '{s}'", .{
33 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
32 return diags.failParse(path, "invalid header delimiter: expected '{f}', found '{f}'", .{
33 std.ascii.hexEscape(ARFMAG, .lower), std.ascii.hexEscape(&hdr.ar_fmag, .lower),
3434 });
3535 }
3636
......@@ -71,7 +71,7 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
7171 .mtime = hdr.date() catch 0,
7272 };
7373
74 log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });
74 log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path });
7575
7676 try self.objects.append(gpa, object);
7777 }
......@@ -230,32 +230,25 @@ pub const ArSymtab = struct {
230230 }
231231 }
232232
233 const FormatContext = struct {
233 const PrintFormat = struct {
234234 ar: ArSymtab,
235235 macho_file: *MachO,
236
237 fn default(f: PrintFormat, bw: *Writer) Writer.Error!void {
238 const ar = f.ar;
239 const macho_file = f.macho_file;
240 for (ar.entries.items, 0..) |entry, i| {
241 const name = ar.strtab.getAssumeExists(entry.off);
242 const file = macho_file.getFile(entry.file).?;
243 try bw.print(" {d}: {s} in file({d})({f})\n", .{ i, name, entry.file, file.fmtPath() });
244 }
245 }
236246 };
237247
238 pub fn fmt(ar: ArSymtab, macho_file: *MachO) std.fmt.Formatter(format2) {
248 pub fn fmt(ar: ArSymtab, macho_file: *MachO) std.fmt.Formatter(PrintFormat, PrintFormat.default) {
239249 return .{ .data = .{ .ar = ar, .macho_file = macho_file } };
240250 }
241251
242 fn format2(
243 ctx: FormatContext,
244 comptime unused_fmt_string: []const u8,
245 options: std.fmt.FormatOptions,
246 writer: anytype,
247 ) !void {
248 _ = unused_fmt_string;
249 _ = options;
250 const ar = ctx.ar;
251 const macho_file = ctx.macho_file;
252 for (ar.entries.items, 0..) |entry, i| {
253 const name = ar.strtab.getAssumeExists(entry.off);
254 const file = macho_file.getFile(entry.file).?;
255 try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file, file.fmtPath() });
256 }
257 }
258
259252 const Entry = struct {
260253 /// Symbol name offset
261254 off: u32,
......@@ -304,8 +297,9 @@ const log = std.log.scoped(.link);
304297const macho = std.macho;
305298const mem = std.mem;
306299const std = @import("std");
307const Allocator = mem.Allocator;
300const Allocator = std.mem.Allocator;
308301const Path = std.Build.Cache.Path;
302const Writer = std.io.Writer;
309303
310304const Archive = @This();
311305const File = @import("file.zig").File;
src/link/MachO/Atom.zig+41-63
......@@ -602,7 +602,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
602602 };
603603 try macho_file.reportParseError2(
604604 file.getIndex(),
605 "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}",
605 "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {f}, target {s}",
606606 .{
607607 name,
608608 self.getAddress(macho_file),
......@@ -653,7 +653,7 @@ fn resolveRelocInner(
653653 const divExact = struct {
654654 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
655655 return math.divExact(u12, num, den) catch {
656 try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {s} at offset 0x{x}", .{
656 try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {f} at offset 0x{x}", .{
657657 atom.getName(ctx),
658658 r.fmtPretty(ctx.getTarget().cpu.arch),
659659 r.offset,
......@@ -664,14 +664,14 @@ fn resolveRelocInner(
664664 }.divExact;
665665
666666 switch (rel.tag) {
667 .local => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] atom({d})", .{
667 .local => relocs_log.debug(" {x}<+{d}>: {f}: [=> {x}] atom({d})", .{
668668 P,
669669 rel_offset,
670670 rel.fmtPretty(cpu_arch),
671671 S + A - SUB,
672672 rel.getTargetAtom(self, macho_file).atom_index,
673673 }),
674 .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ({s})", .{
674 .@"extern" => relocs_log.debug(" {x}<+{d}>: {f}: [=> {x}] G({x}) ({s})", .{
675675 P,
676676 rel_offset,
677677 rel.fmtPretty(cpu_arch),
......@@ -900,19 +900,19 @@ const x86_64 = struct {
900900 switch (old_inst.encoding.mnemonic) {
901901 .mov => {
902902 const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail;
903 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
903 relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding });
904904 encode(&.{inst}, code) catch return error.RelaxFail;
905905 },
906906 else => |x| {
907907 var err = try diags.addErrorWithNotes(2);
908 try err.addMsg("{s}: 0x{x}: 0x{x}: failed to relax relocation of type {}", .{
908 try err.addMsg("{s}: 0x{x}: 0x{x}: failed to relax relocation of type {f}", .{
909909 self.getName(macho_file),
910910 self.getAddress(macho_file),
911911 rel.offset,
912912 rel.fmtPretty(.x86_64),
913913 });
914914 err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)});
915 err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()});
915 err.addNote("while parsing {f}", .{self.getFile(macho_file).fmtPath()});
916916 return error.RelaxFailUnexpectedInstruction;
917917 },
918918 }
......@@ -924,7 +924,7 @@ const x86_64 = struct {
924924 switch (old_inst.encoding.mnemonic) {
925925 .mov => {
926926 const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail;
927 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
927 relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding });
928928 encode(&.{inst}, code) catch return error.RelaxFail;
929929 },
930930 else => return error.RelaxFail,
......@@ -938,11 +938,8 @@ const x86_64 = struct {
938938 }
939939
940940 fn encode(insts: []const Instruction, code: []u8) !void {
941 var stream = std.io.fixedBufferStream(code);
942 const writer = stream.writer();
943 for (insts) |inst| {
944 try inst.encode(writer, .{});
945 }
941 var stream: Writer = .fixed(code);
942 for (insts) |inst| try inst.encode(&stream, .{});
946943 }
947944
948945 const bits = @import("../../arch/x86_64/bits.zig");
......@@ -1003,7 +1000,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
10031000 }
10041001
10051002 switch (rel.tag) {
1006 .local => relocs_log.debug(" {}: [{x} => {d}({s},{s})] + {x}", .{
1003 .local => relocs_log.debug(" {f}: [{x} => {d}({s},{s})] + {x}", .{
10071004 rel.fmtPretty(cpu_arch),
10081005 r_address,
10091006 r_symbolnum,
......@@ -1011,7 +1008,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
10111008 macho_file.sections.items(.header)[r_symbolnum - 1].sectName(),
10121009 addend,
10131010 }),
1014 .@"extern" => relocs_log.debug(" {}: [{x} => {d}({s})] + {x}", .{
1011 .@"extern" => relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{
10151012 rel.fmtPretty(cpu_arch),
10161013 r_address,
10171014 r_symbolnum,
......@@ -1117,60 +1114,40 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
11171114 assert(i == buffer.len);
11181115}
11191116
1120pub fn format(
1121 atom: Atom,
1122 comptime unused_fmt_string: []const u8,
1123 options: std.fmt.FormatOptions,
1124 writer: anytype,
1125) !void {
1126 _ = atom;
1127 _ = unused_fmt_string;
1128 _ = options;
1129 _ = writer;
1130 @compileError("do not format Atom directly");
1131}
1132
1133pub fn fmt(atom: Atom, macho_file: *MachO) std.fmt.Formatter(format2) {
1117pub fn fmt(atom: Atom, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
11341118 return .{ .data = .{
11351119 .atom = atom,
11361120 .macho_file = macho_file,
11371121 } };
11381122}
11391123
1140const FormatContext = struct {
1124const Format = struct {
11411125 atom: Atom,
11421126 macho_file: *MachO,
1143};
11441127
1145fn format2(
1146 ctx: FormatContext,
1147 comptime unused_fmt_string: []const u8,
1148 options: std.fmt.FormatOptions,
1149 writer: anytype,
1150) !void {
1151 _ = options;
1152 _ = unused_fmt_string;
1153 const atom = ctx.atom;
1154 const macho_file = ctx.macho_file;
1155 const file = atom.getFile(macho_file);
1156 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{
1157 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),
1158 atom.out_n_sect, atom.alignment, atom.size,
1159 atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk,
1160 });
1161 if (!atom.isAlive()) try writer.writeAll(" : [*]");
1162 if (atom.getUnwindRecords(macho_file).len > 0) {
1163 try writer.writeAll(" : unwind{ ");
1164 const extra = atom.getExtra(macho_file);
1165 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {
1166 const rec = file.object.getUnwindRecord(index);
1167 try writer.print("{d}", .{index});
1168 if (!rec.alive) try writer.writeAll("([*])");
1169 if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", ");
1128 fn print(f: Format, w: *Writer) Writer.Error!void {
1129 const atom = f.atom;
1130 const macho_file = f.macho_file;
1131 const file = atom.getFile(macho_file);
1132 try w.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{
1133 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),
1134 atom.out_n_sect, atom.alignment, atom.size,
1135 atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk,
1136 });
1137 if (!atom.isAlive()) try w.writeAll(" : [*]");
1138 if (atom.getUnwindRecords(macho_file).len > 0) {
1139 try w.writeAll(" : unwind{ ");
1140 const extra = atom.getExtra(macho_file);
1141 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {
1142 const rec = file.object.getUnwindRecord(index);
1143 try w.print("{d}", .{index});
1144 if (!rec.alive) try w.writeAll("([*])");
1145 if (i < extra.unwind_index + extra.unwind_count - 1) try w.writeAll(", ");
1146 }
1147 try w.writeAll(" }");
11701148 }
1171 try writer.writeAll(" }");
11721149 }
1173}
1150};
11741151
11751152pub const Index = u32;
11761153
......@@ -1205,19 +1182,20 @@ pub const Extra = struct {
12051182
12061183pub const Alignment = @import("../../InternPool.zig").Alignment;
12071184
1208const aarch64 = @import("../aarch64.zig");
1185const std = @import("std");
12091186const assert = std.debug.assert;
12101187const macho = std.macho;
12111188const math = std.math;
12121189const mem = std.mem;
12131190const log = std.log.scoped(.link);
12141191const relocs_log = std.log.scoped(.link_relocs);
1215const std = @import("std");
1216const trace = @import("../../tracy.zig").trace;
1217
1192const Writer = std.io.Writer;
12181193const Allocator = mem.Allocator;
1219const Atom = @This();
12201194const AtomicBool = std.atomic.Value(bool);
1195
1196const aarch64 = @import("../aarch64.zig");
1197const trace = @import("../../tracy.zig").trace;
1198const Atom = @This();
12211199const File = @import("file.zig").File;
12221200const MachO = @import("../MachO.zig");
12231201const Object = @import("Object.zig");
src/link/MachO/DebugSymbols.zig+1
......@@ -460,6 +460,7 @@ const math = std.math;
460460const mem = std.mem;
461461const padToIdeal = MachO.padToIdeal;
462462const trace = @import("../../tracy.zig").trace;
463const Writer = std.io.Writer;
463464
464465const Allocator = mem.Allocator;
465466const MachO = @import("../MachO.zig");
src/link/MachO/Dylib.zig+24-43
......@@ -61,7 +61,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
6161 const file = macho_file.getFileHandle(self.file_handle);
6262 const offset = self.offset;
6363
64 log.debug("parsing dylib from binary: {}", .{@as(Path, self.path)});
64 log.debug("parsing dylib from binary: {f}", .{@as(Path, self.path)});
6565
6666 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
6767 {
......@@ -140,7 +140,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
140140
141141 if (self.platform) |platform| {
142142 if (!macho_file.platform.eqlTarget(platform)) {
143 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{
143 try macho_file.reportParseError2(self.index, "invalid platform: {f}", .{
144144 platform.fmtTarget(macho_file.getTarget().cpu.arch),
145145 });
146146 return error.InvalidTarget;
......@@ -148,7 +148,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
148148 // TODO: this can cause the CI to fail so I'm commenting this check out so that
149149 // I can work out the rest of the changes first
150150 // if (macho_file.platform.version.order(platform.version) == .lt) {
151 // try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{
151 // try macho_file.reportParseError2(self.index, "object file built for newer platform: {f}: {f} < {f}", .{
152152 // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
153153 // macho_file.platform.version,
154154 // platform.version,
......@@ -267,7 +267,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
267267
268268 const gpa = macho_file.base.comp.gpa;
269269
270 log.debug("parsing dylib from stub: {}", .{self.path});
270 log.debug("parsing dylib from stub: {f}", .{self.path});
271271
272272 const file = macho_file.getFileHandle(self.file_handle);
273273 var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| {
......@@ -691,52 +691,32 @@ pub fn setSymbolExtra(self: *Dylib, index: u32, extra: Symbol.Extra) void {
691691 }
692692}
693693
694pub fn format(
695 self: *Dylib,
696 comptime unused_fmt_string: []const u8,
697 options: std.fmt.FormatOptions,
698 writer: anytype,
699) !void {
700 _ = self;
701 _ = unused_fmt_string;
702 _ = options;
703 _ = writer;
704 @compileError("do not format dylib directly");
705}
706
707pub fn fmtSymtab(self: *Dylib, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
694pub fn fmtSymtab(self: *Dylib, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
708695 return .{ .data = .{
709696 .dylib = self,
710697 .macho_file = macho_file,
711698 } };
712699}
713700
714const FormatContext = struct {
701const Format = struct {
715702 dylib: *Dylib,
716703 macho_file: *MachO,
717};
718704
719fn formatSymtab(
720 ctx: FormatContext,
721 comptime unused_fmt_string: []const u8,
722 options: std.fmt.FormatOptions,
723 writer: anytype,
724) !void {
725 _ = unused_fmt_string;
726 _ = options;
727 const dylib = ctx.dylib;
728 const macho_file = ctx.macho_file;
729 try writer.writeAll(" globals\n");
730 for (dylib.symbols.items, 0..) |sym, i| {
731 const ref = dylib.getSymbolRef(@intCast(i), macho_file);
732 if (ref.getFile(macho_file) == null) {
733 // TODO any better way of handling this?
734 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
735 } else {
736 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
705 fn symtab(f: Format, w: *Writer) Writer.Error!void {
706 const dylib = f.dylib;
707 const macho_file = f.macho_file;
708 try w.writeAll(" globals\n");
709 for (dylib.symbols.items, 0..) |sym, i| {
710 const ref = dylib.getSymbolRef(@intCast(i), macho_file);
711 if (ref.getFile(macho_file) == null) {
712 // TODO any better way of handling this?
713 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
714 } else {
715 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
716 }
737717 }
738718 }
739}
719};
740720
741721pub const TargetMatcher = struct {
742722 allocator: Allocator,
......@@ -948,19 +928,17 @@ const Export = struct {
948928 };
949929};
950930
931const std = @import("std");
951932const assert = std.debug.assert;
952const fat = @import("fat.zig");
953933const fs = std.fs;
954934const fmt = std.fmt;
955935const log = std.log.scoped(.link);
956936const macho = std.macho;
957937const math = std.math;
958938const mem = std.mem;
959const tapi = @import("../tapi.zig");
960const trace = @import("../../tracy.zig").trace;
961const std = @import("std");
962939const Allocator = mem.Allocator;
963940const Path = std.Build.Cache.Path;
941const Writer = std.io.Writer;
964942
965943const Dylib = @This();
966944const File = @import("file.zig").File;
......@@ -969,3 +947,6 @@ const LoadCommandIterator = macho.LoadCommandIterator;
969947const MachO = @import("../MachO.zig");
970948const Symbol = @import("Symbol.zig");
971949const Tbd = tapi.Tbd;
950const fat = @import("fat.zig");
951const tapi = @import("../tapi.zig");
952const trace = @import("../../tracy.zig").trace;
src/link/MachO/InternalObject.zig+27-40
......@@ -836,62 +836,48 @@ fn needsObjcMsgsendSymbol(self: InternalObject) bool {
836836 return false;
837837}
838838
839const FormatContext = struct {
839const Format = struct {
840840 self: *InternalObject,
841841 macho_file: *MachO,
842
843 fn atoms(f: Format, w: *Writer) Writer.Error!void {
844 try w.writeAll(" atoms\n");
845 for (f.self.getAtoms()) |atom_index| {
846 const atom = f.self.getAtom(atom_index) orelse continue;
847 try w.print(" {f}\n", .{atom.fmt(f.macho_file)});
848 }
849 }
850
851 fn symtab(f: Format, w: *Writer) Writer.Error!void {
852 const macho_file = f.macho_file;
853 const self = f.self;
854 try w.writeAll(" symbols\n");
855 for (self.symbols.items, 0..) |sym, i| {
856 const ref = self.getSymbolRef(@intCast(i), macho_file);
857 if (ref.getFile(macho_file) == null) {
858 // TODO any better way of handling this?
859 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
860 } else {
861 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
862 }
863 }
864 }
842865};
843866
844pub fn fmtAtoms(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(formatAtoms) {
867pub fn fmtAtoms(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.atoms) {
845868 return .{ .data = .{
846869 .self = self,
847870 .macho_file = macho_file,
848871 } };
849872}
850873
851fn formatAtoms(
852 ctx: FormatContext,
853 comptime unused_fmt_string: []const u8,
854 options: std.fmt.FormatOptions,
855 writer: anytype,
856) !void {
857 _ = unused_fmt_string;
858 _ = options;
859 try writer.writeAll(" atoms\n");
860 for (ctx.self.getAtoms()) |atom_index| {
861 const atom = ctx.self.getAtom(atom_index) orelse continue;
862 try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)});
863 }
864}
865
866pub fn fmtSymtab(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
874pub fn fmtSymtab(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
867875 return .{ .data = .{
868876 .self = self,
869877 .macho_file = macho_file,
870878 } };
871879}
872880
873fn formatSymtab(
874 ctx: FormatContext,
875 comptime unused_fmt_string: []const u8,
876 options: std.fmt.FormatOptions,
877 writer: anytype,
878) !void {
879 _ = unused_fmt_string;
880 _ = options;
881 const macho_file = ctx.macho_file;
882 const self = ctx.self;
883 try writer.writeAll(" symbols\n");
884 for (self.symbols.items, 0..) |sym, i| {
885 const ref = self.getSymbolRef(@intCast(i), macho_file);
886 if (ref.getFile(macho_file) == null) {
887 // TODO any better way of handling this?
888 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
889 } else {
890 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
891 }
892 }
893}
894
895881const Section = struct {
896882 header: macho.section_64,
897883 relocs: std.ArrayListUnmanaged(Relocation) = .empty,
......@@ -908,6 +894,7 @@ const macho = std.macho;
908894const mem = std.mem;
909895const std = @import("std");
910896const trace = @import("../../tracy.zig").trace;
897const Writer = std.io.Writer;
911898
912899const Allocator = std.mem.Allocator;
913900const Atom = @import("Atom.zig");
src/link/MachO/Object.zig+104-174
......@@ -72,7 +72,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
7272 const tracy = trace(@src());
7373 defer tracy.end();
7474
75 log.debug("parsing {}", .{self.fmtPath()});
75 log.debug("parsing {f}", .{self.fmtPath()});
7676
7777 const gpa = macho_file.base.comp.gpa;
7878 const handle = macho_file.getFileHandle(self.file_handle);
......@@ -239,7 +239,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
239239
240240 if (self.platform) |platform| {
241241 if (!macho_file.platform.eqlTarget(platform)) {
242 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{
242 try macho_file.reportParseError2(self.index, "invalid platform: {f}", .{
243243 platform.fmtTarget(cpu_arch),
244244 });
245245 return error.InvalidTarget;
......@@ -247,7 +247,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
247247 // TODO: this causes the CI to fail so I'm commenting this check out so that
248248 // I can work out the rest of the changes first
249249 // if (macho_file.platform.version.order(platform.version) == .lt) {
250 // try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{
250 // try macho_file.reportParseError2(self.index, "object file built for newer platform: {f}: {f} < {f}", .{
251251 // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
252252 // macho_file.platform.version,
253253 // platform.version,
......@@ -308,7 +308,9 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
308308 } else nlists.len;
309309
310310 if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) {
311 const name = try std.fmt.allocPrintZ(allocator, "{s}${s}$begin", .{ sect.segName(), sect.sectName() });
311 const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}$begin", .{
312 sect.segName(), sect.sectName(),
313 }, 0);
312314 defer allocator.free(name);
313315 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;
314316 const atom_index = try self.addAtom(allocator, .{
......@@ -364,7 +366,9 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
364366 // which cannot be contained in any non-zero atom (since then this atom
365367 // would exceed section boundaries). In order to facilitate this behaviour,
366368 // we create a dummy zero-sized atom at section end (addr + size).
367 const name = try std.fmt.allocPrintZ(allocator, "{s}${s}$end", .{ sect.segName(), sect.sectName() });
369 const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}$end", .{
370 sect.segName(), sect.sectName(),
371 }, 0);
368372 defer allocator.free(name);
369373 const atom_index = try self.addAtom(allocator, .{
370374 .name = try self.addString(allocator, name),
......@@ -394,7 +398,7 @@ fn initSections(self: *Object, allocator: Allocator, nlists: anytype) !void {
394398 if (isFixedSizeLiteral(sect)) continue;
395399 if (isPtrLiteral(sect)) continue;
396400
397 const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() });
401 const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() }, 0);
398402 defer allocator.free(name);
399403
400404 const atom_index = try self.addAtom(allocator, .{
......@@ -462,7 +466,7 @@ fn initCstringLiterals(self: *Object, allocator: Allocator, file: File.Handle, m
462466 }
463467 end += 1;
464468
465 const name = try std.fmt.allocPrintZ(allocator, "l._str{d}", .{count});
469 const name = try std.fmt.allocPrintSentinel(allocator, "l._str{d}", .{count}, 0);
466470 defer allocator.free(name);
467471 const name_str = try self.addString(allocator, name);
468472
......@@ -529,7 +533,7 @@ fn initFixedSizeLiterals(self: *Object, allocator: Allocator, macho_file: *MachO
529533 pos += rec_size;
530534 count += 1;
531535 }) {
532 const name = try std.fmt.allocPrintZ(allocator, "l._literal{d}", .{count});
536 const name = try std.fmt.allocPrintSentinel(allocator, "l._literal{d}", .{count}, 0);
533537 defer allocator.free(name);
534538 const name_str = try self.addString(allocator, name);
535539
......@@ -587,7 +591,7 @@ fn initPointerLiterals(self: *Object, allocator: Allocator, macho_file: *MachO)
587591 for (0..num_ptrs) |i| {
588592 const pos: u32 = @as(u32, @intCast(i)) * rec_size;
589593
590 const name = try std.fmt.allocPrintZ(allocator, "l._ptr{d}", .{i});
594 const name = try std.fmt.allocPrintSentinel(allocator, "l._ptr{d}", .{i}, 0);
591595 defer allocator.free(name);
592596 const name_str = try self.addString(allocator, name);
593597
......@@ -1558,7 +1562,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {
15581562 const nlist = &self.symtab.items(.nlist)[nlist_idx];
15591563 const nlist_atom = &self.symtab.items(.atom)[nlist_idx];
15601564
1561 const name = try std.fmt.allocPrintZ(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)});
1565 const name = try std.fmt.allocPrintSentinel(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)}, 0);
15621566 defer gpa.free(name);
15631567
15641568 const alignment = (nlist.n_desc >> 8) & 0x0f;
......@@ -2512,172 +2516,114 @@ pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_
25122516 return data;
25132517}
25142518
2515pub fn format(
2516 self: *Object,
2517 comptime unused_fmt_string: []const u8,
2518 options: std.fmt.FormatOptions,
2519 writer: anytype,
2520) !void {
2521 _ = self;
2522 _ = unused_fmt_string;
2523 _ = options;
2524 _ = writer;
2525 @compileError("do not format objects directly");
2526}
2527
2528const FormatContext = struct {
2519const Format = struct {
25292520 object: *Object,
25302521 macho_file: *MachO,
2522
2523 fn atoms(f: Format, w: *Writer) Writer.Error!void {
2524 const object = f.object;
2525 const macho_file = f.macho_file;
2526 try w.writeAll(" atoms\n");
2527 for (object.getAtoms()) |atom_index| {
2528 const atom = object.getAtom(atom_index) orelse continue;
2529 try w.print(" {f}\n", .{atom.fmt(macho_file)});
2530 }
2531 }
2532 fn cies(f: Format, w: *Writer) Writer.Error!void {
2533 const object = f.object;
2534 try w.writeAll(" cies\n");
2535 for (object.cies.items, 0..) |cie, i| {
2536 try w.print(" cie({d}) : {f}\n", .{ i, cie.fmt(f.macho_file) });
2537 }
2538 }
2539 fn fdes(f: Format, w: *Writer) Writer.Error!void {
2540 const object = f.object;
2541 try w.writeAll(" fdes\n");
2542 for (object.fdes.items, 0..) |fde, i| {
2543 try w.print(" fde({d}) : {f}\n", .{ i, fde.fmt(f.macho_file) });
2544 }
2545 }
2546 fn unwindRecords(f: Format, w: *Writer) Writer.Error!void {
2547 const object = f.object;
2548 const macho_file = f.macho_file;
2549 try w.writeAll(" unwind records\n");
2550 for (object.unwind_records_indexes.items) |rec| {
2551 try w.print(" rec({d}) : {f}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) });
2552 }
2553 }
2554
2555 fn symtab(f: Format, w: *Writer) Writer.Error!void {
2556 const object = f.object;
2557 const macho_file = f.macho_file;
2558 try w.writeAll(" symbols\n");
2559 for (object.symbols.items, 0..) |sym, i| {
2560 const ref = object.getSymbolRef(@intCast(i), macho_file);
2561 if (ref.getFile(macho_file) == null) {
2562 // TODO any better way of handling this?
2563 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
2564 } else {
2565 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
2566 }
2567 }
2568 for (object.stab_files.items) |sf| {
2569 try w.print(" stabs({s},{s},{s})\n", .{
2570 sf.getCompDir(object.*),
2571 sf.getTuName(object.*),
2572 sf.getOsoPath(object.*),
2573 });
2574 for (sf.stabs.items) |stab| {
2575 try w.print(" {f}", .{stab.fmt(object.*)});
2576 }
2577 }
2578 }
25312579};
25322580
2533pub fn fmtAtoms(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatAtoms) {
2581pub fn fmtAtoms(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.atoms) {
25342582 return .{ .data = .{
25352583 .object = self,
25362584 .macho_file = macho_file,
25372585 } };
25382586}
25392587
2540fn formatAtoms(
2541 ctx: FormatContext,
2542 comptime unused_fmt_string: []const u8,
2543 options: std.fmt.FormatOptions,
2544 writer: anytype,
2545) !void {
2546 _ = unused_fmt_string;
2547 _ = options;
2548 const object = ctx.object;
2549 const macho_file = ctx.macho_file;
2550 try writer.writeAll(" atoms\n");
2551 for (object.getAtoms()) |atom_index| {
2552 const atom = object.getAtom(atom_index) orelse continue;
2553 try writer.print(" {}\n", .{atom.fmt(macho_file)});
2554 }
2555}
2556
2557pub fn fmtCies(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatCies) {
2588pub fn fmtCies(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.cies) {
25582589 return .{ .data = .{
25592590 .object = self,
25602591 .macho_file = macho_file,
25612592 } };
25622593}
25632594
2564fn formatCies(
2565 ctx: FormatContext,
2566 comptime unused_fmt_string: []const u8,
2567 options: std.fmt.FormatOptions,
2568 writer: anytype,
2569) !void {
2570 _ = unused_fmt_string;
2571 _ = options;
2572 const object = ctx.object;
2573 try writer.writeAll(" cies\n");
2574 for (object.cies.items, 0..) |cie, i| {
2575 try writer.print(" cie({d}) : {}\n", .{ i, cie.fmt(ctx.macho_file) });
2576 }
2577}
2578
2579pub fn fmtFdes(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatFdes) {
2595pub fn fmtFdes(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.fdes) {
25802596 return .{ .data = .{
25812597 .object = self,
25822598 .macho_file = macho_file,
25832599 } };
25842600}
25852601
2586fn formatFdes(
2587 ctx: FormatContext,
2588 comptime unused_fmt_string: []const u8,
2589 options: std.fmt.FormatOptions,
2590 writer: anytype,
2591) !void {
2592 _ = unused_fmt_string;
2593 _ = options;
2594 const object = ctx.object;
2595 try writer.writeAll(" fdes\n");
2596 for (object.fdes.items, 0..) |fde, i| {
2597 try writer.print(" fde({d}) : {}\n", .{ i, fde.fmt(ctx.macho_file) });
2598 }
2599}
2600
2601pub fn fmtUnwindRecords(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatUnwindRecords) {
2602pub fn fmtUnwindRecords(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.unwindRecords) {
26022603 return .{ .data = .{
26032604 .object = self,
26042605 .macho_file = macho_file,
26052606 } };
26062607}
26072608
2608fn formatUnwindRecords(
2609 ctx: FormatContext,
2610 comptime unused_fmt_string: []const u8,
2611 options: std.fmt.FormatOptions,
2612 writer: anytype,
2613) !void {
2614 _ = unused_fmt_string;
2615 _ = options;
2616 const object = ctx.object;
2617 const macho_file = ctx.macho_file;
2618 try writer.writeAll(" unwind records\n");
2619 for (object.unwind_records_indexes.items) |rec| {
2620 try writer.print(" rec({d}) : {}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) });
2621 }
2622}
2623
2624pub fn fmtSymtab(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
2609pub fn fmtSymtab(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
26252610 return .{ .data = .{
26262611 .object = self,
26272612 .macho_file = macho_file,
26282613 } };
26292614}
26302615
2631fn formatSymtab(
2632 ctx: FormatContext,
2633 comptime unused_fmt_string: []const u8,
2634 options: std.fmt.FormatOptions,
2635 writer: anytype,
2636) !void {
2637 _ = unused_fmt_string;
2638 _ = options;
2639 const object = ctx.object;
2640 const macho_file = ctx.macho_file;
2641 try writer.writeAll(" symbols\n");
2642 for (object.symbols.items, 0..) |sym, i| {
2643 const ref = object.getSymbolRef(@intCast(i), macho_file);
2644 if (ref.getFile(macho_file) == null) {
2645 // TODO any better way of handling this?
2646 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
2647 } else {
2648 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
2649 }
2650 }
2651 for (object.stab_files.items) |sf| {
2652 try writer.print(" stabs({s},{s},{s})\n", .{
2653 sf.getCompDir(object.*),
2654 sf.getTuName(object.*),
2655 sf.getOsoPath(object.*),
2656 });
2657 for (sf.stabs.items) |stab| {
2658 try writer.print(" {}", .{stab.fmt(object.*)});
2659 }
2660 }
2661}
2662
2663pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) {
2616pub fn fmtPath(self: Object) std.fmt.Formatter(Object, formatPath) {
26642617 return .{ .data = self };
26652618}
26662619
2667fn formatPath(
2668 object: Object,
2669 comptime unused_fmt_string: []const u8,
2670 options: std.fmt.FormatOptions,
2671 writer: anytype,
2672) !void {
2673 _ = unused_fmt_string;
2674 _ = options;
2620fn formatPath(object: Object, w: *Writer) Writer.Error!void {
26752621 if (object.in_archive) |ar| {
2676 try writer.print("{}({s})", .{
2677 @as(Path, ar.path), object.path.basename(),
2622 try w.print("{f}({s})", .{
2623 ar.path, object.path.basename(),
26782624 });
26792625 } else {
2680 try writer.print("{}", .{@as(Path, object.path)});
2626 try w.print("{f}", .{object.path});
26812627 }
26822628}
26832629
......@@ -2731,42 +2677,25 @@ const StabFile = struct {
27312677 return object.symbols.items[index];
27322678 }
27332679
2734 pub fn format(
2680 const Format = struct {
27352681 stab: Stab,
2736 comptime unused_fmt_string: []const u8,
2737 options: std.fmt.FormatOptions,
2738 writer: anytype,
2739 ) !void {
2740 _ = stab;
2741 _ = unused_fmt_string;
2742 _ = options;
2743 _ = writer;
2744 @compileError("do not format stabs directly");
2745 }
2746
2747 const StabFormatContext = struct { Stab, Object };
2748
2749 pub fn fmt(stab: Stab, object: Object) std.fmt.Formatter(format2) {
2750 return .{ .data = .{ stab, object } };
2751 }
2752
2753 fn format2(
2754 ctx: StabFormatContext,
2755 comptime unused_fmt_string: []const u8,
2756 options: std.fmt.FormatOptions,
2757 writer: anytype,
2758 ) !void {
2759 _ = unused_fmt_string;
2760 _ = options;
2761 const stab, const object = ctx;
2762 const sym = stab.getSymbol(object).?;
2763 if (stab.is_func) {
2764 try writer.print("func({d})", .{stab.index.?});
2765 } else if (sym.visibility == .global) {
2766 try writer.print("gsym({d})", .{stab.index.?});
2767 } else {
2768 try writer.print("stsym({d})", .{stab.index.?});
2682 object: Object,
2683
2684 fn default(f: Stab.Format, w: *Writer) Writer.Error!void {
2685 const stab = f.stab;
2686 const sym = stab.getSymbol(f.object).?;
2687 if (stab.is_func) {
2688 try w.print("func({d})", .{stab.index.?});
2689 } else if (sym.visibility == .global) {
2690 try w.print("gsym({d})", .{stab.index.?});
2691 } else {
2692 try w.print("stsym({d})", .{stab.index.?});
2693 }
27692694 }
2695 };
2696
2697 pub fn fmt(stab: Stab, object: Object) std.fmt.Formatter(Stab.Format, Stab.Format.default) {
2698 return .{ .data = .{ .stab = stab, .object = object } };
27702699 }
27712700 };
27722701};
......@@ -3157,17 +3086,18 @@ const aarch64 = struct {
31573086 }
31583087};
31593088
3089const std = @import("std");
31603090const assert = std.debug.assert;
3161const eh_frame = @import("eh_frame.zig");
31623091const log = std.log.scoped(.link);
31633092const macho = std.macho;
31643093const math = std.math;
31653094const mem = std.mem;
3166const trace = @import("../../tracy.zig").trace;
3167const std = @import("std");
31683095const Path = std.Build.Cache.Path;
3096const Allocator = std.mem.Allocator;
3097const Writer = std.io.Writer;
31693098
3170const Allocator = mem.Allocator;
3099const eh_frame = @import("eh_frame.zig");
3100const trace = @import("../../tracy.zig").trace;
31713101const Archive = @import("Archive.zig");
31723102const Atom = @import("Atom.zig");
31733103const Cie = eh_frame.Cie;
src/link/MachO/Relocation.zig+45-50
......@@ -70,57 +70,51 @@ pub fn lessThan(ctx: void, lhs: Relocation, rhs: Relocation) bool {
7070 return lhs.offset < rhs.offset;
7171}
7272
73const FormatCtx = struct { Relocation, std.Target.Cpu.Arch };
74
75pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatPretty) {
76 return .{ .data = .{ rel, cpu_arch } };
73pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(Format, Format.pretty) {
74 return .{ .data = .{ .relocation = rel, .arch = cpu_arch } };
7775}
7876
79fn formatPretty(
80 ctx: FormatCtx,
81 comptime unused_fmt_string: []const u8,
82 options: std.fmt.FormatOptions,
83 writer: anytype,
84) !void {
85 _ = options;
86 _ = unused_fmt_string;
87 const rel, const cpu_arch = ctx;
88 const str = switch (rel.type) {
89 .signed => "X86_64_RELOC_SIGNED",
90 .signed1 => "X86_64_RELOC_SIGNED_1",
91 .signed2 => "X86_64_RELOC_SIGNED_2",
92 .signed4 => "X86_64_RELOC_SIGNED_4",
93 .got_load => "X86_64_RELOC_GOT_LOAD",
94 .tlv => "X86_64_RELOC_TLV",
95 .page => "ARM64_RELOC_PAGE21",
96 .pageoff => "ARM64_RELOC_PAGEOFF12",
97 .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21",
98 .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
99 .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21",
100 .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
101 .branch => switch (cpu_arch) {
102 .x86_64 => "X86_64_RELOC_BRANCH",
103 .aarch64 => "ARM64_RELOC_BRANCH26",
104 else => unreachable,
105 },
106 .got => switch (cpu_arch) {
107 .x86_64 => "X86_64_RELOC_GOT",
108 .aarch64 => "ARM64_RELOC_POINTER_TO_GOT",
109 else => unreachable,
110 },
111 .subtractor => switch (cpu_arch) {
112 .x86_64 => "X86_64_RELOC_SUBTRACTOR",
113 .aarch64 => "ARM64_RELOC_SUBTRACTOR",
114 else => unreachable,
115 },
116 .unsigned => switch (cpu_arch) {
117 .x86_64 => "X86_64_RELOC_UNSIGNED",
118 .aarch64 => "ARM64_RELOC_UNSIGNED",
119 else => unreachable,
120 },
121 };
122 try writer.writeAll(str);
123}
77const Format = struct {
78 relocation: Relocation,
79 arch: std.Target.Cpu.Arch,
80
81 fn pretty(f: Format, w: *Writer) Writer.Error!void {
82 try w.writeAll(switch (f.relocation.type) {
83 .signed => "X86_64_RELOC_SIGNED",
84 .signed1 => "X86_64_RELOC_SIGNED_1",
85 .signed2 => "X86_64_RELOC_SIGNED_2",
86 .signed4 => "X86_64_RELOC_SIGNED_4",
87 .got_load => "X86_64_RELOC_GOT_LOAD",
88 .tlv => "X86_64_RELOC_TLV",
89 .page => "ARM64_RELOC_PAGE21",
90 .pageoff => "ARM64_RELOC_PAGEOFF12",
91 .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21",
92 .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
93 .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21",
94 .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
95 .branch => switch (f.arch) {
96 .x86_64 => "X86_64_RELOC_BRANCH",
97 .aarch64 => "ARM64_RELOC_BRANCH26",
98 else => unreachable,
99 },
100 .got => switch (f.arch) {
101 .x86_64 => "X86_64_RELOC_GOT",
102 .aarch64 => "ARM64_RELOC_POINTER_TO_GOT",
103 else => unreachable,
104 },
105 .subtractor => switch (f.arch) {
106 .x86_64 => "X86_64_RELOC_SUBTRACTOR",
107 .aarch64 => "ARM64_RELOC_SUBTRACTOR",
108 else => unreachable,
109 },
110 .unsigned => switch (f.arch) {
111 .x86_64 => "X86_64_RELOC_UNSIGNED",
112 .aarch64 => "ARM64_RELOC_UNSIGNED",
113 else => unreachable,
114 },
115 });
116 }
117};
124118
125119pub const Type = enum {
126120 // x86_64
......@@ -164,10 +158,11 @@ pub const Type = enum {
164158
165159const Tag = enum { local, @"extern" };
166160
161const std = @import("std");
167162const assert = std.debug.assert;
168163const macho = std.macho;
169164const math = std.math;
170const std = @import("std");
165const Writer = std.io.Writer;
171166
172167const Atom = @import("Atom.zig");
173168const MachO = @import("../MachO.zig");
src/link/MachO/Symbol.zig+40-59
......@@ -286,71 +286,51 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo
286286 }
287287}
288288
289pub fn format(
290 symbol: Symbol,
291 comptime unused_fmt_string: []const u8,
292 options: std.fmt.FormatOptions,
293 writer: anytype,
294) !void {
295 _ = symbol;
296 _ = unused_fmt_string;
297 _ = options;
298 _ = writer;
299 @compileError("do not format symbols directly");
300}
301
302const FormatContext = struct {
303 symbol: Symbol,
304 macho_file: *MachO,
305};
306
307pub fn fmt(symbol: Symbol, macho_file: *MachO) std.fmt.Formatter(format2) {
289pub fn fmt(symbol: Symbol, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
308290 return .{ .data = .{
309291 .symbol = symbol,
310292 .macho_file = macho_file,
311293 } };
312294}
313295
314fn format2(
315 ctx: FormatContext,
316 comptime unused_fmt_string: []const u8,
317 options: std.fmt.FormatOptions,
318 writer: anytype,
319) !void {
320 _ = options;
321 _ = unused_fmt_string;
322 const symbol = ctx.symbol;
323 try writer.print("%{d} : {s} : @{x}", .{
324 symbol.nlist_idx,
325 symbol.getName(ctx.macho_file),
326 symbol.getAddress(.{}, ctx.macho_file),
327 });
328 if (symbol.getFile(ctx.macho_file)) |file| {
329 if (symbol.getOutputSectionIndex(ctx.macho_file) != 0) {
330 try writer.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)});
331 }
332 if (symbol.getAtom(ctx.macho_file)) |atom| {
333 try writer.print(" : atom({d})", .{atom.atom_index});
334 }
335 var buf: [3]u8 = .{'_'} ** 3;
336 if (symbol.flags.@"export") buf[0] = 'E';
337 if (symbol.flags.import) buf[1] = 'I';
338 switch (symbol.visibility) {
339 .local => buf[2] = 'L',
340 .hidden => buf[2] = 'H',
341 .global => buf[2] = 'G',
342 }
343 try writer.print(" : {s}", .{&buf});
344 if (symbol.flags.weak) try writer.writeAll(" : weak");
345 if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab");
346 switch (file) {
347 .zig_object => |x| try writer.print(" : zig_object({d})", .{x.index}),
348 .internal => |x| try writer.print(" : internal({d})", .{x.index}),
349 .object => |x| try writer.print(" : object({d})", .{x.index}),
350 .dylib => |x| try writer.print(" : dylib({d})", .{x.index}),
351 }
352 } else try writer.writeAll(" : unresolved");
353}
296const Format = struct {
297 symbol: Symbol,
298 macho_file: *MachO,
299
300 fn default(f: Format, w: *Writer) Writer.Error!void {
301 const symbol = f.symbol;
302 try w.print("%{d} : {s} : @{x}", .{
303 symbol.nlist_idx,
304 symbol.getName(f.macho_file),
305 symbol.getAddress(.{}, f.macho_file),
306 });
307 if (symbol.getFile(f.macho_file)) |file| {
308 if (symbol.getOutputSectionIndex(f.macho_file) != 0) {
309 try w.print(" : sect({d})", .{symbol.getOutputSectionIndex(f.macho_file)});
310 }
311 if (symbol.getAtom(f.macho_file)) |atom| {
312 try w.print(" : atom({d})", .{atom.atom_index});
313 }
314 var buf: [3]u8 = .{'_'} ** 3;
315 if (symbol.flags.@"export") buf[0] = 'E';
316 if (symbol.flags.import) buf[1] = 'I';
317 switch (symbol.visibility) {
318 .local => buf[2] = 'L',
319 .hidden => buf[2] = 'H',
320 .global => buf[2] = 'G',
321 }
322 try w.print(" : {s}", .{&buf});
323 if (symbol.flags.weak) try w.writeAll(" : weak");
324 if (symbol.isSymbolStab(f.macho_file)) try w.writeAll(" : stab");
325 switch (file) {
326 .zig_object => |x| try w.print(" : zig_object({d})", .{x.index}),
327 .internal => |x| try w.print(" : internal({d})", .{x.index}),
328 .object => |x| try w.print(" : object({d})", .{x.index}),
329 .dylib => |x| try w.print(" : dylib({d})", .{x.index}),
330 }
331 } else try w.writeAll(" : unresolved");
332 }
333};
354334
355335pub const Flags = packed struct {
356336 /// Whether the symbol is imported at runtime.
......@@ -437,6 +417,7 @@ pub const Index = u32;
437417const assert = std.debug.assert;
438418const macho = std.macho;
439419const std = @import("std");
420const Writer = std.io.Writer;
440421
441422const Atom = @import("Atom.zig");
442423const File = @import("file.zig").File;
src/link/MachO/Thunk.zig+12-31
......@@ -61,47 +61,27 @@ pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {
6161 }
6262}
6363
64pub fn format(
65 thunk: Thunk,
66 comptime unused_fmt_string: []const u8,
67 options: std.fmt.FormatOptions,
68 writer: anytype,
69) !void {
70 _ = thunk;
71 _ = unused_fmt_string;
72 _ = options;
73 _ = writer;
74 @compileError("do not format Thunk directly");
75}
76
77pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(format2) {
64pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
7865 return .{ .data = .{
7966 .thunk = thunk,
8067 .macho_file = macho_file,
8168 } };
8269}
8370
84const FormatContext = struct {
71const Format = struct {
8572 thunk: Thunk,
8673 macho_file: *MachO,
87};
8874
89fn format2(
90 ctx: FormatContext,
91 comptime unused_fmt_string: []const u8,
92 options: std.fmt.FormatOptions,
93 writer: anytype,
94) !void {
95 _ = options;
96 _ = unused_fmt_string;
97 const thunk = ctx.thunk;
98 const macho_file = ctx.macho_file;
99 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
100 for (thunk.symbols.keys()) |ref| {
101 const sym = ref.getSymbol(macho_file).?;
102 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
75 fn default(f: Format, w: *Writer) Writer.Error!void {
76 const thunk = f.thunk;
77 const macho_file = f.macho_file;
78 try w.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
79 for (thunk.symbols.keys()) |ref| {
80 const sym = ref.getSymbol(macho_file).?;
81 try w.print(" {f} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
82 }
10383 }
104}
84};
10585
10686const trampoline_size = 3 * @sizeOf(u32);
10787
......@@ -115,6 +95,7 @@ const math = std.math;
11595const mem = std.mem;
11696const std = @import("std");
11797const trace = @import("../../tracy.zig").trace;
98const Writer = std.io.Writer;
11899
119100const Allocator = mem.Allocator;
120101const Atom = @import("Atom.zig");
src/link/MachO/UnwindInfo.zig+33-79
......@@ -133,7 +133,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
133133 for (info.records.items) |ref| {
134134 const rec = ref.getUnwindRecord(macho_file);
135135 const atom = rec.getAtom(macho_file);
136 log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {}", .{
136 log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {f}", .{
137137 rec.getAtomAddress(macho_file),
138138 rec.getAtomAddress(macho_file) + rec.length,
139139 atom.getName(macho_file),
......@@ -202,7 +202,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
202202 if (i >= max_common_encodings) break;
203203 if (slice[i].count < 2) continue;
204204 info.appendCommonEncoding(slice[i].enc);
205 log.debug("adding common encoding: {d} => {}", .{ i, slice[i].enc });
205 log.debug("adding common encoding: {d} => {f}", .{ i, slice[i].enc });
206206 }
207207 }
208208
......@@ -255,7 +255,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
255255 page.kind = .compressed;
256256 }
257257
258 log.debug("{}", .{page.fmt(info.*)});
258 log.debug("{f}", .{page.fmt(info.*)});
259259
260260 try info.pages.append(gpa, page);
261261 }
......@@ -455,15 +455,8 @@ pub const Encoding = extern struct {
455455 return enc.enc == other.enc;
456456 }
457457
458 pub fn format(
459 enc: Encoding,
460 comptime unused_fmt_string: []const u8,
461 options: std.fmt.FormatOptions,
462 writer: anytype,
463 ) !void {
464 _ = unused_fmt_string;
465 _ = options;
466 try writer.print("0x{x:0>8}", .{enc.enc});
458 pub fn format(enc: Encoding, w: *Writer) Writer.Error!void {
459 try w.print("0x{x:0>8}", .{enc.enc});
467460 }
468461};
469462
......@@ -517,48 +510,28 @@ pub const Record = struct {
517510 return lsda.getAddress(macho_file) + rec.lsda_offset;
518511 }
519512
520 pub fn format(
521 rec: Record,
522 comptime unused_fmt_string: []const u8,
523 options: std.fmt.FormatOptions,
524 writer: anytype,
525 ) !void {
526 _ = rec;
527 _ = unused_fmt_string;
528 _ = options;
529 _ = writer;
530 @compileError("do not format UnwindInfo.Records directly");
531 }
532
533 pub fn fmt(rec: Record, macho_file: *MachO) std.fmt.Formatter(format2) {
513 pub fn fmt(rec: Record, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
534514 return .{ .data = .{
535515 .rec = rec,
536516 .macho_file = macho_file,
537517 } };
538518 }
539519
540 const FormatContext = struct {
520 const Format = struct {
541521 rec: Record,
542522 macho_file: *MachO,
543 };
544523
545 fn format2(
546 ctx: FormatContext,
547 comptime unused_fmt_string: []const u8,
548 options: std.fmt.FormatOptions,
549 writer: anytype,
550 ) !void {
551 _ = unused_fmt_string;
552 _ = options;
553 const rec = ctx.rec;
554 const macho_file = ctx.macho_file;
555 try writer.print("{x} : len({x})", .{
556 rec.enc.enc, rec.length,
557 });
558 if (rec.enc.isDwarf(macho_file)) try writer.print(" : fde({d})", .{rec.fde});
559 try writer.print(" : {s}", .{rec.getAtom(macho_file).getName(macho_file)});
560 if (!rec.alive) try writer.writeAll(" : [*]");
561 }
524 fn default(f: Format, w: *Writer) Writer.Error!void {
525 const rec = f.rec;
526 const macho_file = f.macho_file;
527 try w.print("{x} : len({x})", .{
528 rec.enc.enc, rec.length,
529 });
530 if (rec.enc.isDwarf(macho_file)) try w.print(" : fde({d})", .{rec.fde});
531 try w.print(" : {s}", .{rec.getAtom(macho_file).getName(macho_file)});
532 if (!rec.alive) try w.writeAll(" : [*]");
533 }
534 };
562535
563536 pub const Index = u32;
564537
......@@ -613,45 +586,25 @@ const Page = struct {
613586 return null;
614587 }
615588
616 fn format(
617 page: *const Page,
618 comptime unused_format_string: []const u8,
619 options: std.fmt.FormatOptions,
620 writer: anytype,
621 ) !void {
622 _ = page;
623 _ = unused_format_string;
624 _ = options;
625 _ = writer;
626 @compileError("do not format Page directly; use page.fmt()");
627 }
628
629 const FormatPageContext = struct {
589 const Format = struct {
630590 page: Page,
631591 info: UnwindInfo,
632 };
633592
634 fn format2(
635 ctx: FormatPageContext,
636 comptime unused_format_string: []const u8,
637 options: std.fmt.FormatOptions,
638 writer: anytype,
639 ) @TypeOf(writer).Error!void {
640 _ = options;
641 _ = unused_format_string;
642 try writer.writeAll("Page:\n");
643 try writer.print(" kind: {s}\n", .{@tagName(ctx.page.kind)});
644 try writer.print(" entries: {d} - {d}\n", .{
645 ctx.page.start,
646 ctx.page.start + ctx.page.count,
647 });
648 try writer.print(" encodings (count = {d})\n", .{ctx.page.page_encodings_count});
649 for (ctx.page.page_encodings[0..ctx.page.page_encodings_count], 0..) |enc, i| {
650 try writer.print(" {d}: {}\n", .{ ctx.info.common_encodings_count + i, enc });
593 fn default(f: Format, w: *Writer) Writer.Error!void {
594 try w.writeAll("Page:\n");
595 try w.print(" kind: {s}\n", .{@tagName(f.page.kind)});
596 try w.print(" entries: {d} - {d}\n", .{
597 f.page.start,
598 f.page.start + f.page.count,
599 });
600 try w.print(" encodings (count = {d})\n", .{f.page.page_encodings_count});
601 for (f.page.page_encodings[0..f.page.page_encodings_count], 0..) |enc, i| {
602 try w.print(" {d}: {f}\n", .{ f.info.common_encodings_count + i, enc });
603 }
651604 }
652 }
605 };
653606
654 fn fmt(page: Page, info: UnwindInfo) std.fmt.Formatter(format2) {
607 fn fmt(page: Page, info: UnwindInfo) std.fmt.Formatter(Format, Format.default) {
655608 return .{ .data = .{
656609 .page = page,
657610 .info = info,
......@@ -720,6 +673,7 @@ const macho = std.macho;
720673const math = std.math;
721674const mem = std.mem;
722675const trace = @import("../../tracy.zig").trace;
676const Writer = std.io.Writer;
723677
724678const Allocator = mem.Allocator;
725679const Atom = @import("Atom.zig");
src/link/MachO/ZigObject.zig+34-47
......@@ -618,7 +618,7 @@ pub fn getNavVAddr(
618618 const zcu = pt.zcu;
619619 const ip = &zcu.intern_pool;
620620 const nav = ip.getNav(nav_index);
621 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
621 log.debug("getNavVAddr {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
622622 const sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
623623 macho_file,
624624 nav.name.toSlice(ip),
......@@ -943,7 +943,7 @@ fn updateNavCode(
943943 const ip = &zcu.intern_pool;
944944 const nav = ip.getNav(nav_index);
945945
946 log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
946 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
947947
948948 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
949949 const required_alignment = switch (pt.navAlignment(nav_index)) {
......@@ -959,7 +959,7 @@ fn updateNavCode(
959959 sym.out_n_sect = sect_index;
960960 atom.out_n_sect = sect_index;
961961
962 const sym_name = try std.fmt.allocPrintZ(gpa, "_{s}", .{nav.fqn.toSlice(ip)});
962 const sym_name = try std.fmt.allocPrintSentinel(gpa, "_{s}", .{nav.fqn.toSlice(ip)}, 0);
963963 defer gpa.free(sym_name);
964964 sym.name = try self.addString(gpa, sym_name);
965965 atom.setAlive(true);
......@@ -981,7 +981,7 @@ fn updateNavCode(
981981 if (need_realloc) {
982982 atom.grow(macho_file) catch |err|
983983 return macho_file.base.cgFail(nav_index, "failed to grow atom: {s}", .{@errorName(err)});
984 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value });
984 log.debug("growing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value });
985985 if (old_vaddr != atom.value) {
986986 sym.value = 0;
987987 nlist.n_value = 0;
......@@ -1023,7 +1023,7 @@ fn updateTlv(
10231023 const ip = &pt.zcu.intern_pool;
10241024 const nav = ip.getNav(nav_index);
10251025
1026 log.debug("updateTlv {} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });
1026 log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });
10271027
10281028 // 1. Lower TLV initializer
10291029 const init_sym_index = try self.createTlvInitializer(
......@@ -1351,7 +1351,7 @@ fn updateLazySymbol(
13511351 defer code_buffer.deinit(gpa);
13521352
13531353 const name_str = blk: {
1354 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1354 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{
13551355 @tagName(lazy_sym.kind),
13561356 Type.fromInterned(lazy_sym.ty).fmt(pt),
13571357 });
......@@ -1430,7 +1430,7 @@ pub fn deleteExport(
14301430 } orelse return;
14311431 const nlist_index = metadata.@"export"(self, name.toSlice(&zcu.intern_pool)) orelse return;
14321432
1433 log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)});
1433 log.debug("deleting export '{f}'", .{name.fmt(&zcu.intern_pool)});
14341434
14351435 const nlist = &self.symtab.items(.nlist)[nlist_index.*];
14361436 self.symtab.items(.size)[nlist_index.*] = 0;
......@@ -1678,64 +1678,50 @@ pub fn asFile(self: *ZigObject) File {
16781678 return .{ .zig_object = self };
16791679}
16801680
1681pub fn fmtSymtab(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
1681pub fn fmtSymtab(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
16821682 return .{ .data = .{
16831683 .self = self,
16841684 .macho_file = macho_file,
16851685 } };
16861686}
16871687
1688const FormatContext = struct {
1688const Format = struct {
16891689 self: *ZigObject,
16901690 macho_file: *MachO,
1691};
16921691
1693fn formatSymtab(
1694 ctx: FormatContext,
1695 comptime unused_fmt_string: []const u8,
1696 options: std.fmt.FormatOptions,
1697 writer: anytype,
1698) !void {
1699 _ = unused_fmt_string;
1700 _ = options;
1701 try writer.writeAll(" symbols\n");
1702 const self = ctx.self;
1703 const macho_file = ctx.macho_file;
1704 for (self.symbols.items, 0..) |sym, i| {
1705 const ref = self.getSymbolRef(@intCast(i), macho_file);
1706 if (ref.getFile(macho_file) == null) {
1707 // TODO any better way of handling this?
1708 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
1709 } else {
1710 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
1692 fn symtab(f: Format, w: *Writer) Writer.Error!void {
1693 try w.writeAll(" symbols\n");
1694 const self = f.self;
1695 const macho_file = f.macho_file;
1696 for (self.symbols.items, 0..) |sym, i| {
1697 const ref = self.getSymbolRef(@intCast(i), macho_file);
1698 if (ref.getFile(macho_file) == null) {
1699 // TODO any better way of handling this?
1700 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
1701 } else {
1702 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
1703 }
17111704 }
17121705 }
1713}
17141706
1715pub fn fmtAtoms(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatAtoms) {
1707 fn atoms(f: Format, w: *Writer) Writer.Error!void {
1708 const self = f.self;
1709 const macho_file = f.macho_file;
1710 try w.writeAll(" atoms\n");
1711 for (self.getAtoms()) |atom_index| {
1712 const atom = self.getAtom(atom_index) orelse continue;
1713 try w.print(" {f}\n", .{atom.fmt(macho_file)});
1714 }
1715 }
1716};
1717
1718pub fn fmtAtoms(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.atoms) {
17161719 return .{ .data = .{
17171720 .self = self,
17181721 .macho_file = macho_file,
17191722 } };
17201723}
17211724
1722fn formatAtoms(
1723 ctx: FormatContext,
1724 comptime unused_fmt_string: []const u8,
1725 options: std.fmt.FormatOptions,
1726 writer: anytype,
1727) !void {
1728 _ = unused_fmt_string;
1729 _ = options;
1730 const self = ctx.self;
1731 const macho_file = ctx.macho_file;
1732 try writer.writeAll(" atoms\n");
1733 for (self.getAtoms()) |atom_index| {
1734 const atom = self.getAtom(atom_index) orelse continue;
1735 try writer.print(" {}\n", .{atom.fmt(macho_file)});
1736 }
1737}
1738
17391725const AvMetadata = struct {
17401726 symbol_index: Symbol.Index,
17411727 /// A list of all exports aliases of this Av.
......@@ -1797,6 +1783,7 @@ const mem = std.mem;
17971783const target_util = @import("../../target.zig");
17981784const trace = @import("../../tracy.zig").trace;
17991785const std = @import("std");
1786const Writer = std.io.Writer;
18001787
18011788const Allocator = std.mem.Allocator;
18021789const Archive = @import("Archive.zig");
src/link/MachO/dead_strip.zig+4-10
......@@ -117,7 +117,7 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void {
117117fn markLive(atom: *Atom, macho_file: *MachO) void {
118118 assert(atom.visited.load(.seq_cst));
119119 atom.setAlive(true);
120 track_live_log.debug("{}marking live atom({d},{s})", .{
120 track_live_log.debug("{f}marking live atom({d},{s})", .{
121121 track_live_level,
122122 atom.atom_index,
123123 atom.getName(macho_file),
......@@ -196,15 +196,8 @@ const Level = struct {
196196 self.value += 1;
197197 }
198198
199 pub fn format(
200 self: *const @This(),
201 comptime unused_fmt_string: []const u8,
202 options: std.fmt.FormatOptions,
203 writer: anytype,
204 ) !void {
205 _ = unused_fmt_string;
206 _ = options;
207 try writer.writeByteNTimes(' ', self.value);
199 pub fn format(self: *const @This(), w: *Writer) Writer.Error!void {
200 try w.splatByteAll(' ', self.value);
208201 }
209202};
210203
......@@ -219,6 +212,7 @@ const mem = std.mem;
219212const trace = @import("../../tracy.zig").trace;
220213const track_live_log = std.log.scoped(.dead_strip_track_live);
221214const std = @import("std");
215const Writer = std.io.Writer;
222216
223217const Allocator = mem.Allocator;
224218const Atom = @import("Atom.zig");
src/link/MachO/dyld_info/Rebase.zig+3-2
......@@ -654,9 +654,10 @@ const log = std.log.scoped(.link_dyld_info);
654654const macho = std.macho;
655655const mem = std.mem;
656656const testing = std.testing;
657const trace = @import("../../../tracy.zig").trace;
658
659657const Allocator = mem.Allocator;
658const Writer = std.io.Writer;
659
660const trace = @import("../../../tracy.zig").trace;
660661const File = @import("../file.zig").File;
661662const MachO = @import("../../MachO.zig");
662663const Rebase = @This();
src/link/MachO/dyld_info/Trie.zig+2-2
......@@ -336,9 +336,9 @@ const Edge = struct {
336336fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void {
337337 assert(expected.len > 0);
338338 if (mem.eql(u8, expected, given)) return;
339 const expected_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{std.fmt.fmtSliceHexLower(expected)});
339 const expected_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{expected});
340340 defer testing.allocator.free(expected_fmt);
341 const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{std.fmt.fmtSliceHexLower(given)});
341 const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{given});
342342 defer testing.allocator.free(given_fmt);
343343 const idx = mem.indexOfDiff(u8, expected_fmt, given_fmt).?;
344344 const padding = try testing.allocator.alloc(u8, idx + 5);
src/link/MachO/dyld_info/bind.zig+2-2
......@@ -205,7 +205,7 @@ pub const Bind = struct {
205205 }
206206 }
207207
208 log.debug("{x}, {d}, {x}, {?x}, {s}", .{ offset, count, skip, addend, @tagName(state) });
208 log.debug("{x}, {d}, {x}, {x}, {s}", .{ offset, count, skip, addend, @tagName(state) });
209209 log.debug(" => {x}", .{current.offset});
210210 switch (state) {
211211 .start => {
......@@ -447,7 +447,7 @@ pub const WeakBind = struct {
447447 }
448448 }
449449
450 log.debug("{x}, {d}, {x}, {?x}, {s}", .{ offset, count, skip, addend, @tagName(state) });
450 log.debug("{x}, {d}, {x}, {x}, {s}", .{ offset, count, skip, addend, @tagName(state) });
451451 log.debug(" => {x}", .{current.offset});
452452 switch (state) {
453453 .start => {
src/link/MachO/eh_frame.zig+26-65
......@@ -81,46 +81,26 @@ pub const Cie = struct {
8181 return true;
8282 }
8383
84 pub fn format(
85 cie: Cie,
86 comptime unused_fmt_string: []const u8,
87 options: std.fmt.FormatOptions,
88 writer: anytype,
89 ) !void {
90 _ = cie;
91 _ = unused_fmt_string;
92 _ = options;
93 _ = writer;
94 @compileError("do not format CIEs directly");
95 }
96
97 pub fn fmt(cie: Cie, macho_file: *MachO) std.fmt.Formatter(format2) {
84 pub fn fmt(cie: Cie, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
9885 return .{ .data = .{
9986 .cie = cie,
10087 .macho_file = macho_file,
10188 } };
10289 }
10390
104 const FormatContext = struct {
91 const Format = struct {
10592 cie: Cie,
10693 macho_file: *MachO,
107 };
10894
109 fn format2(
110 ctx: FormatContext,
111 comptime unused_fmt_string: []const u8,
112 options: std.fmt.FormatOptions,
113 writer: anytype,
114 ) !void {
115 _ = unused_fmt_string;
116 _ = options;
117 const cie = ctx.cie;
118 try writer.print("@{x} : size({x})", .{
119 cie.offset,
120 cie.getSize(),
121 });
122 if (!cie.alive) try writer.writeAll(" : [*]");
123 }
95 fn default(f: Format, w: *Writer) Writer.Error!void {
96 const cie = f.cie;
97 try w.print("@{x} : size({x})", .{
98 cie.offset,
99 cie.getSize(),
100 });
101 if (!cie.alive) try w.writeAll(" : [*]");
102 }
103 };
124104
125105 pub const Index = u32;
126106
......@@ -231,49 +211,29 @@ pub const Fde = struct {
231211 return fde.getObject(macho_file).getAtom(fde.lsda);
232212 }
233213
234 pub fn format(
235 fde: Fde,
236 comptime unused_fmt_string: []const u8,
237 options: std.fmt.FormatOptions,
238 writer: anytype,
239 ) !void {
240 _ = fde;
241 _ = unused_fmt_string;
242 _ = options;
243 _ = writer;
244 @compileError("do not format FDEs directly");
245 }
246
247 pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(format2) {
214 pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
248215 return .{ .data = .{
249216 .fde = fde,
250217 .macho_file = macho_file,
251218 } };
252219 }
253220
254 const FormatContext = struct {
221 const Format = struct {
255222 fde: Fde,
256223 macho_file: *MachO,
257 };
258224
259 fn format2(
260 ctx: FormatContext,
261 comptime unused_fmt_string: []const u8,
262 options: std.fmt.FormatOptions,
263 writer: anytype,
264 ) !void {
265 _ = unused_fmt_string;
266 _ = options;
267 const fde = ctx.fde;
268 const macho_file = ctx.macho_file;
269 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
270 fde.offset,
271 fde.getSize(),
272 fde.cie,
273 fde.getAtom(macho_file).getName(macho_file),
274 });
275 if (!fde.alive) try writer.writeAll(" : [*]");
276 }
225 fn default(f: Format, writer: *Writer) Writer.Error!void {
226 const fde = f.fde;
227 const macho_file = f.macho_file;
228 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
229 fde.offset,
230 fde.getSize(),
231 fde.cie,
232 fde.getAtom(macho_file).getName(macho_file),
233 });
234 if (!fde.alive) try writer.writeAll(" : [*]");
235 }
236 };
277237
278238 pub const Index = u32;
279239};
......@@ -545,6 +505,7 @@ const math = std.math;
545505const mem = std.mem;
546506const std = @import("std");
547507const trace = @import("../../tracy.zig").trace;
508const Writer = std.io.Writer;
548509
549510const Allocator = std.mem.Allocator;
550511const Atom = @import("Atom.zig");
src/link/MachO/file.zig+7-13
......@@ -10,23 +10,16 @@ pub const File = union(enum) {
1010 };
1111 }
1212
13 pub fn fmtPath(file: File) std.fmt.Formatter(formatPath) {
13 pub fn fmtPath(file: File) std.fmt.Formatter(File, formatPath) {
1414 return .{ .data = file };
1515 }
1616
17 fn formatPath(
18 file: File,
19 comptime unused_fmt_string: []const u8,
20 options: std.fmt.FormatOptions,
21 writer: anytype,
22 ) !void {
23 _ = unused_fmt_string;
24 _ = options;
17 fn formatPath(file: File, w: *Writer) Writer.Error!void {
2518 switch (file) {
26 .zig_object => |zo| try writer.writeAll(zo.basename),
27 .internal => try writer.writeAll("internal"),
28 .object => |x| try writer.print("{}", .{x.fmtPath()}),
29 .dylib => |dl| try writer.print("{}", .{@as(Path, dl.path)}),
19 .zig_object => |zo| try w.writeAll(zo.basename),
20 .internal => try w.writeAll("internal"),
21 .object => |x| try w.print("{f}", .{x.fmtPath()}),
22 .dylib => |dl| try w.print("{f}", .{@as(Path, dl.path)}),
3023 }
3124 }
3225
......@@ -371,6 +364,7 @@ const log = std.log.scoped(.link);
371364const macho = std.macho;
372365const Allocator = std.mem.Allocator;
373366const Path = std.Build.Cache.Path;
367const Writer = std.io.Writer;
374368
375369const trace = @import("../../tracy.zig").trace;
376370const Archive = @import("Archive.zig");
src/link/MachO/load_commands.zig+1
......@@ -3,6 +3,7 @@ const assert = std.debug.assert;
33const log = std.log.scoped(.link);
44const macho = std.macho;
55const mem = std.mem;
6const Writer = std.io.Writer;
67
78const Allocator = mem.Allocator;
89const DebugSymbols = @import("DebugSymbols.zig");
src/link/MachO/relocatable.zig+8-7
......@@ -20,13 +20,13 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
2020 // the *only* input file over.
2121 const path = positionals.items[0].path().?;
2222 const in_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err|
23 return diags.fail("failed to open {}: {s}", .{ path, @errorName(err) });
23 return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) });
2424 const stat = in_file.stat() catch |err|
25 return diags.fail("failed to stat {}: {s}", .{ path, @errorName(err) });
25 return diags.fail("failed to stat {f}: {s}", .{ path, @errorName(err) });
2626 const amt = in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size) catch |err|
27 return diags.fail("failed to copy range of file {}: {s}", .{ path, @errorName(err) });
27 return diags.fail("failed to copy range of file {f}: {s}", .{ path, @errorName(err) });
2828 if (amt != stat.size)
29 return diags.fail("unexpected short write in copy range of file {}", .{path});
29 return diags.fail("unexpected short write in copy range of file {f}", .{path});
3030 return;
3131 }
3232
......@@ -62,7 +62,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
6262 allocateSegment(macho_file);
6363
6464 if (build_options.enable_logging) {
65 state_log.debug("{}", .{macho_file.dumpState()});
65 state_log.debug("{f}", .{macho_file.dumpState()});
6666 }
6767
6868 try writeSections(macho_file);
......@@ -126,7 +126,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
126126 allocateSegment(macho_file);
127127
128128 if (build_options.enable_logging) {
129 state_log.debug("{}", .{macho_file.dumpState()});
129 state_log.debug("{f}", .{macho_file.dumpState()});
130130 }
131131
132132 try writeSections(macho_file);
......@@ -202,7 +202,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
202202 };
203203
204204 if (build_options.enable_logging) {
205 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(macho_file)});
205 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
206206 }
207207
208208 var buffer = std.ArrayList(u8).init(gpa);
......@@ -784,6 +784,7 @@ const macho = std.macho;
784784const math = std.math;
785785const mem = std.mem;
786786const state_log = std.log.scoped(.link_state);
787const Writer = std.io.Writer;
787788
788789const Archive = @import("Archive.zig");
789790const Atom = @import("Atom.zig");
src/link/MachO/synthetic.zig+70-97
......@@ -37,34 +37,27 @@ pub const GotSection = struct {
3737 }
3838 }
3939
40 const FormatCtx = struct {
40 const Format = struct {
4141 got: GotSection,
4242 macho_file: *MachO,
43
44 pub fn print(f: Format, w: *Writer) Writer.Error!void {
45 for (f.got.symbols.items, 0..) |ref, i| {
46 const symbol = ref.getSymbol(f.macho_file).?;
47 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
48 i,
49 symbol.getGotAddress(f.macho_file),
50 ref,
51 symbol.getAddress(.{}, f.macho_file),
52 symbol.getName(f.macho_file),
53 });
54 }
55 }
4356 };
4457
45 pub fn fmt(got: GotSection, macho_file: *MachO) std.fmt.Formatter(format2) {
58 pub fn fmt(got: GotSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
4659 return .{ .data = .{ .got = got, .macho_file = macho_file } };
4760 }
48
49 pub fn format2(
50 ctx: FormatCtx,
51 comptime unused_fmt_string: []const u8,
52 options: std.fmt.FormatOptions,
53 writer: anytype,
54 ) !void {
55 _ = options;
56 _ = unused_fmt_string;
57 for (ctx.got.symbols.items, 0..) |ref, i| {
58 const symbol = ref.getSymbol(ctx.macho_file).?;
59 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
60 i,
61 symbol.getGotAddress(ctx.macho_file),
62 ref,
63 symbol.getAddress(.{}, ctx.macho_file),
64 symbol.getName(ctx.macho_file),
65 });
66 }
67 }
6861};
6962
7063pub const StubsSection = struct {
......@@ -128,34 +121,27 @@ pub const StubsSection = struct {
128121 }
129122 }
130123
131 const FormatCtx = struct {
132 stubs: StubsSection,
133 macho_file: *MachO,
134 };
135
136 pub fn fmt(stubs: StubsSection, macho_file: *MachO) std.fmt.Formatter(format2) {
124 pub fn fmt(stubs: StubsSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
137125 return .{ .data = .{ .stubs = stubs, .macho_file = macho_file } };
138126 }
139127
140 pub fn format2(
141 ctx: FormatCtx,
142 comptime unused_fmt_string: []const u8,
143 options: std.fmt.FormatOptions,
144 writer: anytype,
145 ) !void {
146 _ = options;
147 _ = unused_fmt_string;
148 for (ctx.stubs.symbols.items, 0..) |ref, i| {
149 const symbol = ref.getSymbol(ctx.macho_file).?;
150 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
151 i,
152 symbol.getStubsAddress(ctx.macho_file),
153 ref,
154 symbol.getAddress(.{}, ctx.macho_file),
155 symbol.getName(ctx.macho_file),
156 });
128 const Format = struct {
129 stubs: StubsSection,
130 macho_file: *MachO,
131
132 pub fn print(f: Format, w: *Writer) Writer.Error!void {
133 for (f.stubs.symbols.items, 0..) |ref, i| {
134 const symbol = ref.getSymbol(f.macho_file).?;
135 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
136 i,
137 symbol.getStubsAddress(f.macho_file),
138 ref,
139 symbol.getAddress(.{}, f.macho_file),
140 symbol.getName(f.macho_file),
141 });
142 }
157143 }
158 }
144 };
159145};
160146
161147pub const StubsHelperSection = struct {
......@@ -357,34 +343,27 @@ pub const TlvPtrSection = struct {
357343 }
358344 }
359345
360 const FormatCtx = struct {
361 tlv: TlvPtrSection,
362 macho_file: *MachO,
363 };
364
365 pub fn fmt(tlv: TlvPtrSection, macho_file: *MachO) std.fmt.Formatter(format2) {
346 pub fn fmt(tlv: TlvPtrSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
366347 return .{ .data = .{ .tlv = tlv, .macho_file = macho_file } };
367348 }
368349
369 pub fn format2(
370 ctx: FormatCtx,
371 comptime unused_fmt_string: []const u8,
372 options: std.fmt.FormatOptions,
373 writer: anytype,
374 ) !void {
375 _ = options;
376 _ = unused_fmt_string;
377 for (ctx.tlv.symbols.items, 0..) |ref, i| {
378 const symbol = ref.getSymbol(ctx.macho_file).?;
379 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
380 i,
381 symbol.getTlvPtrAddress(ctx.macho_file),
382 ref,
383 symbol.getAddress(.{}, ctx.macho_file),
384 symbol.getName(ctx.macho_file),
385 });
350 const Format = struct {
351 tlv: TlvPtrSection,
352 macho_file: *MachO,
353
354 pub fn print(f: Format, w: *Writer) Writer.Error!void {
355 for (f.tlv.symbols.items, 0..) |ref, i| {
356 const symbol = ref.getSymbol(f.macho_file).?;
357 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
358 i,
359 symbol.getTlvPtrAddress(f.macho_file),
360 ref,
361 symbol.getAddress(.{}, f.macho_file),
362 symbol.getName(f.macho_file),
363 });
364 }
386365 }
387 }
366 };
388367};
389368
390369pub const ObjcStubsSection = struct {
......@@ -482,34 +461,27 @@ pub const ObjcStubsSection = struct {
482461 }
483462 }
484463
485 const FormatCtx = struct {
486 objc: ObjcStubsSection,
487 macho_file: *MachO,
488 };
489
490 pub fn fmt(objc: ObjcStubsSection, macho_file: *MachO) std.fmt.Formatter(format2) {
464 pub fn fmt(objc: ObjcStubsSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
491465 return .{ .data = .{ .objc = objc, .macho_file = macho_file } };
492466 }
493467
494 pub fn format2(
495 ctx: FormatCtx,
496 comptime unused_fmt_string: []const u8,
497 options: std.fmt.FormatOptions,
498 writer: anytype,
499 ) !void {
500 _ = options;
501 _ = unused_fmt_string;
502 for (ctx.objc.symbols.items, 0..) |ref, i| {
503 const symbol = ref.getSymbol(ctx.macho_file).?;
504 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
505 i,
506 symbol.getObjcStubsAddress(ctx.macho_file),
507 ref,
508 symbol.getAddress(.{}, ctx.macho_file),
509 symbol.getName(ctx.macho_file),
510 });
468 const Format = struct {
469 objc: ObjcStubsSection,
470 macho_file: *MachO,
471
472 pub fn print(f: Format, w: *Writer) Writer.Error!void {
473 for (f.objc.symbols.items, 0..) |ref, i| {
474 const symbol = ref.getSymbol(f.macho_file).?;
475 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
476 i,
477 symbol.getObjcStubsAddress(f.macho_file),
478 ref,
479 symbol.getAddress(.{}, f.macho_file),
480 symbol.getName(f.macho_file),
481 });
482 }
511483 }
512 }
484 };
513485
514486 pub const Index = u32;
515487};
......@@ -625,13 +597,14 @@ pub const DataInCode = struct {
625597 };
626598};
627599
600const std = @import("std");
628601const aarch64 = @import("../aarch64.zig");
629602const assert = std.debug.assert;
630603const macho = std.macho;
631604const math = std.math;
632const std = @import("std");
633const trace = @import("../../tracy.zig").trace;
634
635605const Allocator = std.mem.Allocator;
606const Writer = std.io.Writer;
607
608const trace = @import("../../tracy.zig").trace;
636609const MachO = @import("../MachO.zig");
637610const Symbol = @import("Symbol.zig");
src/link/Plan9.zig+6-6
......@@ -445,7 +445,7 @@ pub fn updateNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
445445 .func => return,
446446 .variable => |variable| Value.fromInterned(variable.init),
447447 .@"extern" => {
448 log.debug("found extern decl: {}", .{nav.name.fmt(ip)});
448 log.debug("found extern decl: {f}", .{nav.name.fmt(ip)});
449449 return;
450450 },
451451 else => nav_val,
......@@ -675,7 +675,7 @@ pub fn flush(
675675 const off = self.getAddr(text_i, .t);
676676 text_i += out.code.len;
677677 atom.offset = off;
678 log.debug("write text nav 0x{x} ({}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ nav_index, nav.name.fmt(&pt.zcu.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off });
678 log.debug("write text nav 0x{x} ({f}), lines {d} to {d}.;__GOT+0x{x} vaddr: 0x{x}", .{ nav_index, nav.name.fmt(&pt.zcu.intern_pool), out.start_line + 1, out.end_line, atom.got_index.? * 8, off });
679679 if (!self.sixtyfour_bit) {
680680 mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @intCast(off), target.cpu.arch.endian());
681681 } else {
......@@ -974,11 +974,11 @@ pub fn seeNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
974974 self.etext_edata_end_atom_indices[2] = atom_idx;
975975 }
976976 try self.updateFinish(pt, nav_index);
977 log.debug("seeNav(extern) for {} (got_addr=0x{x})", .{
977 log.debug("seeNav(extern) for {f} (got_addr=0x{x})", .{
978978 nav.name.fmt(ip),
979979 self.getAtom(atom_idx).getOffsetTableAddress(self),
980980 });
981 } else log.debug("seeNav for {}", .{nav.name.fmt(ip)});
981 } else log.debug("seeNav for {f}", .{nav.name.fmt(ip)});
982982 return atom_idx;
983983}
984984
......@@ -1043,7 +1043,7 @@ fn updateLazySymbolAtom(
10431043 defer code_buffer.deinit(gpa);
10441044
10451045 // create the symbol for the name
1046 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1046 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{
10471047 @tagName(sym.kind),
10481048 Type.fromInterned(sym.ty).fmt(pt),
10491049 });
......@@ -1314,7 +1314,7 @@ pub fn getNavVAddr(
13141314) !u64 {
13151315 const ip = &pt.zcu.intern_pool;
13161316 const nav = ip.getNav(nav_index);
1317 log.debug("getDeclVAddr for {}", .{nav.name.fmt(ip)});
1317 log.debug("getDeclVAddr for {f}", .{nav.name.fmt(ip)});
13181318 if (nav.getExtern(ip) != null) {
13191319 if (nav.name.eqlSlice("etext", ip)) {
13201320 try self.addReloc(reloc_info.parent.atom_index, .{
src/link/SpirV.zig+8-8
......@@ -117,7 +117,7 @@ pub fn updateNav(self: *SpirV, pt: Zcu.PerThread, nav: InternPool.Nav.Index) lin
117117 }
118118
119119 const ip = &pt.zcu.intern_pool;
120 log.debug("lowering nav {}({d})", .{ ip.getNav(nav).fqn.fmt(ip), nav });
120 log.debug("lowering nav {f}({d})", .{ ip.getNav(nav).fqn.fmt(ip), nav });
121121
122122 try self.object.updateNav(pt, nav);
123123}
......@@ -203,10 +203,10 @@ pub fn flush(
203203 // We need to export the list of error names somewhere so that we can pretty-print them in the
204204 // executor. This is not really an important thing though, so we can just dump it in any old
205205 // nonsemantic instruction. For now, just put it in OpSourceExtension with a special name.
206 var error_info = std.ArrayList(u8).init(self.object.gpa);
206 var error_info: std.io.Writer.Allocating = .init(self.object.gpa);
207207 defer error_info.deinit();
208208
209 try error_info.appendSlice("zig_errors:");
209 error_info.writer.writeAll("zig_errors:") catch return error.OutOfMemory;
210210 const ip = &self.base.comp.zcu.?.intern_pool;
211211 for (ip.global_error_set.getNamesFromMainThread()) |name| {
212212 // Errors can contain pretty much any character - to encode them in a string we must escape
......@@ -214,9 +214,9 @@ pub fn flush(
214214 // name if it contains no strange characters is nice for debugging. URI encoding fits the bill.
215215 // We're using : as separator, which is a reserved character.
216216
217 try error_info.append(':');
218 try std.Uri.Component.percentEncode(
219 error_info.writer(),
217 error_info.writer.writeByte(':') catch return error.OutOfMemory;
218 std.Uri.Component.percentEncode(
219 &error_info.writer,
220220 name.toSlice(ip),
221221 struct {
222222 fn isValidChar(c: u8) bool {
......@@ -226,10 +226,10 @@ pub fn flush(
226226 };
227227 }
228228 }.isValidChar,
229 );
229 ) catch return error.OutOfMemory;
230230 }
231231 try spv.sections.debug_strings.emit(gpa, .OpSourceExtension, .{
232 .extension = error_info.items,
232 .extension = error_info.getWritten(),
233233 });
234234
235235 const module = try spv.finalize(arena);
src/link/SpirV/deduplicate.zig+1-1
......@@ -110,7 +110,7 @@ const ModuleInfo = struct {
110110 .TypeDeclaration, .ConstantCreation => {
111111 const entry = try entities.getOrPut(result_id);
112112 if (entry.found_existing) {
113 log.err("type or constant {} has duplicate definition", .{result_id});
113 log.err("type or constant {f} has duplicate definition", .{result_id});
114114 return error.DuplicateId;
115115 }
116116 entry.value_ptr.* = entity;
src/link/SpirV/lower_invocation_globals.zig+9-9
......@@ -92,7 +92,7 @@ const ModuleInfo = struct {
9292 const entry_point: ResultId = @enumFromInt(inst.operands[1]);
9393 const entry = try entry_points.getOrPut(entry_point);
9494 if (entry.found_existing) {
95 log.err("Entry point type {} has duplicate definition", .{entry_point});
95 log.err("Entry point type {f} has duplicate definition", .{entry_point});
9696 return error.DuplicateId;
9797 }
9898 },
......@@ -103,7 +103,7 @@ const ModuleInfo = struct {
103103
104104 const entry = try fn_types.getOrPut(fn_type);
105105 if (entry.found_existing) {
106 log.err("Function type {} has duplicate definition", .{fn_type});
106 log.err("Function type {f} has duplicate definition", .{fn_type});
107107 return error.DuplicateId;
108108 }
109109
......@@ -135,7 +135,7 @@ const ModuleInfo = struct {
135135 },
136136 .OpFunction => {
137137 if (maybe_current_function) |current_function| {
138 log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function});
138 log.err("OpFunction {f} does not have an OpFunctionEnd", .{current_function});
139139 return error.InvalidPhysicalFormat;
140140 }
141141
......@@ -154,7 +154,7 @@ const ModuleInfo = struct {
154154 };
155155 const entry = try functions.getOrPut(current_function);
156156 if (entry.found_existing) {
157 log.err("Function {} has duplicate definition", .{current_function});
157 log.err("Function {f} has duplicate definition", .{current_function});
158158 return error.DuplicateId;
159159 }
160160
......@@ -162,7 +162,7 @@ const ModuleInfo = struct {
162162 try callee_store.appendSlice(calls.keys());
163163
164164 const fn_type = fn_types.get(fn_ty_id) orelse {
165 log.err("Function {} has invalid OpFunction type", .{current_function});
165 log.err("Function {f} has invalid OpFunction type", .{current_function});
166166 return error.InvalidId;
167167 };
168168
......@@ -187,7 +187,7 @@ const ModuleInfo = struct {
187187 }
188188
189189 if (maybe_current_function) |current_function| {
190 log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function});
190 log.err("OpFunction {f} does not have an OpFunctionEnd", .{current_function});
191191 return error.InvalidPhysicalFormat;
192192 }
193193
......@@ -222,7 +222,7 @@ const ModuleInfo = struct {
222222 seen: *std.DynamicBitSetUnmanaged,
223223 ) !void {
224224 const index = self.functions.getIndex(id) orelse {
225 log.err("function calls invalid function {}", .{id});
225 log.err("function calls invalid function {f}", .{id});
226226 return error.InvalidId;
227227 };
228228
......@@ -261,7 +261,7 @@ const ModuleInfo = struct {
261261 seen: *std.DynamicBitSetUnmanaged,
262262 ) !void {
263263 const index = self.invocation_globals.getIndex(id) orelse {
264 log.err("invalid invocation global {}", .{id});
264 log.err("invalid invocation global {f}", .{id});
265265 return error.InvalidId;
266266 };
267267
......@@ -276,7 +276,7 @@ const ModuleInfo = struct {
276276 }
277277
278278 const initializer = self.functions.get(info.initializer) orelse {
279 log.err("invocation global {} has invalid initializer {}", .{ id, info.initializer });
279 log.err("invocation global {f} has invalid initializer {f}", .{ id, info.initializer });
280280 return error.InvalidId;
281281 };
282282
src/link/SpirV/prune_unused.zig+4-4
......@@ -128,7 +128,7 @@ const ModuleInfo = struct {
128128 switch (inst.opcode) {
129129 .OpFunction => {
130130 if (maybe_current_function) |current_function| {
131 log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function});
131 log.err("OpFunction {f} does not have an OpFunctionEnd", .{current_function});
132132 return error.InvalidPhysicalFormat;
133133 }
134134
......@@ -145,7 +145,7 @@ const ModuleInfo = struct {
145145 };
146146 const entry = try functions.getOrPut(current_function);
147147 if (entry.found_existing) {
148 log.err("Function {} has duplicate definition", .{current_function});
148 log.err("Function {f} has duplicate definition", .{current_function});
149149 return error.DuplicateId;
150150 }
151151
......@@ -163,7 +163,7 @@ const ModuleInfo = struct {
163163 }
164164
165165 if (maybe_current_function) |current_function| {
166 log.err("OpFunction {} does not have an OpFunctionEnd", .{current_function});
166 log.err("OpFunction {f} does not have an OpFunctionEnd", .{current_function});
167167 return error.InvalidPhysicalFormat;
168168 }
169169
......@@ -184,7 +184,7 @@ const AliveMarker = struct {
184184
185185 fn markAlive(self: *AliveMarker, result_id: ResultId) BinaryModule.ParseError!void {
186186 const index = self.info.result_id_to_code_offset.getIndex(result_id) orelse {
187 log.err("undefined result-id {}", .{result_id});
187 log.err("undefined result-id {f}", .{result_id});
188188 return error.InvalidId;
189189 };
190190
src/link/Wasm.zig+10-19
......@@ -547,7 +547,7 @@ pub const SourceLocation = enum(u32) {
547547 switch (sl.unpack(wasm)) {
548548 .none => unreachable,
549549 .zig_object_nofile => diags.addError("zig compilation unit: " ++ f, args),
550 .object_index => |i| diags.addError("{}: " ++ f, .{i.ptr(wasm).path} ++ args),
550 .object_index => |i| diags.addError("{f}: " ++ f, .{i.ptr(wasm).path} ++ args),
551551 .source_location_index => @panic("TODO"),
552552 }
553553 }
......@@ -579,9 +579,9 @@ pub const SourceLocation = enum(u32) {
579579 .object_index => |i| {
580580 const obj = i.ptr(wasm);
581581 return if (obj.archive_member_name.slice(wasm)) |obj_name|
582 try bundle.printString("{} ({s}): {s}", .{ obj.path, std.fs.path.basename(obj_name), msg })
582 try bundle.printString("{f} ({s}): {s}", .{ obj.path, std.fs.path.basename(obj_name), msg })
583583 else
584 try bundle.printString("{}: {s}", .{ obj.path, msg });
584 try bundle.printString("{f}: {s}", .{ obj.path, msg });
585585 },
586586 .source_location_index => @panic("TODO"),
587587 };
......@@ -2126,14 +2126,7 @@ pub const FunctionType = extern struct {
21262126 wasm: *const Wasm,
21272127 ft: FunctionType,
21282128
2129 pub fn format(
2130 self: Formatter,
2131 comptime format_string: []const u8,
2132 options: std.fmt.FormatOptions,
2133 writer: anytype,
2134 ) !void {
2135 if (format_string.len != 0) std.fmt.invalidFmtError(format_string, self);
2136 _ = options;
2129 pub fn format(self: Formatter, writer: *std.io.Writer) std.io.Writer.Error!void {
21372130 const params = self.ft.params.slice(self.wasm);
21382131 const returns = self.ft.returns.slice(self.wasm);
21392132
......@@ -2912,9 +2905,7 @@ pub const Feature = packed struct(u8) {
29122905 @"=",
29132906 };
29142907
2915 pub fn format(feature: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
2916 _ = opt;
2917 _ = fmt;
2908 pub fn format(feature: Feature, writer: *std.io.Writer) std.io.Writer.Error!void {
29182909 try writer.print("{s} {s}", .{ @tagName(feature.prefix), @tagName(feature.tag) });
29192910 }
29202911
......@@ -3036,7 +3027,7 @@ fn openParseObjectReportingFailure(wasm: *Wasm, path: Path) void {
30363027}
30373028
30383029fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {
3039 log.debug("parseObject {}", .{obj.path});
3030 log.debug("parseObject {f}", .{obj.path});
30403031 const gpa = wasm.base.comp.gpa;
30413032 const gc_sections = wasm.base.gc_sections;
30423033
......@@ -3060,7 +3051,7 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {
30603051}
30613052
30623053fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void {
3063 log.debug("parseArchive {}", .{obj.path});
3054 log.debug("parseArchive {f}", .{obj.path});
30643055 const gpa = wasm.base.comp.gpa;
30653056 const gc_sections = wasm.base.gc_sections;
30663057
......@@ -3196,7 +3187,7 @@ pub fn updateFunc(
31963187 const is_obj = zcu.comp.config.output_mode == .Obj;
31973188 const target = &zcu.comp.root_mod.resolved_target.result;
31983189 const owner_nav = zcu.funcInfo(func_index).owner_nav;
3199 log.debug("updateFunc {}", .{ip.getNav(owner_nav).fqn.fmt(ip)});
3190 log.debug("updateFunc {f}", .{ip.getNav(owner_nav).fqn.fmt(ip)});
32003191
32013192 // For Wasm, we do not lower the MIR to code just yet. That lowering happens during `flush`,
32023193 // after garbage collection, which can affect function and global indexes, which affects the
......@@ -3307,7 +3298,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
33073298 .variable => |variable| .{ variable.init, variable.owner_nav },
33083299 else => .{ nav.status.fully_resolved.val, nav_index },
33093300 };
3310 //log.debug("updateNav {} {d}", .{ nav.fqn.fmt(ip), chased_nav_index });
3301 //log.debug("updateNav {f} {d}", .{ nav.fqn.fmt(ip), chased_nav_index });
33113302 assert(!wasm.imports.contains(chased_nav_index));
33123303
33133304 if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
......@@ -4347,7 +4338,7 @@ fn resolveFunctionSynthetic(
43474338 });
43484339 if (import.type != correct_func_type) {
43494340 const diags = &wasm.base.comp.link_diags;
4350 return import.source_location.fail(diags, "synthetic function {s} {} imported with incorrect signature {}", .{
4341 return import.source_location.fail(diags, "synthetic function {s} {f} imported with incorrect signature {f}", .{
43514342 @tagName(res), correct_func_type.fmt(wasm), import.type.fmt(wasm),
43524343 });
43534344 }
src/link/Wasm/Flush.zig+4-10
......@@ -534,7 +534,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
534534 wasm.memories.limits.max = @intCast(max_memory / page_size);
535535 wasm.memories.limits.flags.has_max = true;
536536 if (shared_memory) wasm.memories.limits.flags.is_shared = true;
537 log.debug("maximum memory pages: {?d}", .{wasm.memories.limits.max});
537 log.debug("maximum memory pages: {d}", .{wasm.memories.limits.max});
538538 }
539539 f.memory_layout_finished = true;
540540
......@@ -1035,20 +1035,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
10351035 var id: [16]u8 = undefined;
10361036 std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{});
10371037 var uuid: [36]u8 = undefined;
1038 _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{
1039 std.fmt.fmtSliceHexLower(id[0..4]),
1040 std.fmt.fmtSliceHexLower(id[4..6]),
1041 std.fmt.fmtSliceHexLower(id[6..8]),
1042 std.fmt.fmtSliceHexLower(id[8..10]),
1043 std.fmt.fmtSliceHexLower(id[10..]),
1038 _ = try std.fmt.bufPrint(&uuid, "{x}-{x}-{x}-{x}-{x}", .{
1039 id[0..4], id[4..6], id[6..8], id[8..10], id[10..],
10441040 });
10451041 try emitBuildIdSection(gpa, binary_bytes, &uuid);
10461042 },
10471043 .hexstring => |hs| {
10481044 var buffer: [32 * 2]u8 = undefined;
1049 const str = std.fmt.bufPrint(&buffer, "{s}", .{
1050 std.fmt.fmtSliceHexLower(hs.toSlice()),
1051 }) catch unreachable;
1045 const str = std.fmt.bufPrint(&buffer, "{x}", .{hs.toSlice()}) catch unreachable;
10521046 try emitBuildIdSection(gpa, binary_bytes, str);
10531047 },
10541048 else => |mode| {
src/link/Wasm/Object.zig+7-7
......@@ -856,7 +856,7 @@ pub fn parse(
856856 start_function = @enumFromInt(functions_start + index);
857857 },
858858 .element => {
859 log.warn("unimplemented: element section in {} {?s}", .{ path, archive_member_name });
859 log.warn("unimplemented: element section in {f} {?s}", .{ path, archive_member_name });
860860 pos = section_end;
861861 },
862862 .code => {
......@@ -984,10 +984,10 @@ pub fn parse(
984984 if (gop.value_ptr.type != fn_ty_index) {
985985 var err = try diags.addErrorWithNotes(2);
986986 try err.addMsg("symbol '{s}' mismatching function signatures", .{name.slice(wasm)});
987 gop.value_ptr.source_location.addNote(&err, "imported as {} here", .{
987 gop.value_ptr.source_location.addNote(&err, "imported as {f} here", .{
988988 gop.value_ptr.type.fmt(wasm),
989989 });
990 source_location.addNote(&err, "imported as {} here", .{fn_ty_index.fmt(wasm)});
990 source_location.addNote(&err, "imported as {f} here", .{fn_ty_index.fmt(wasm)});
991991 continue;
992992 }
993993 if (gop.value_ptr.module_name != ptr.module_name.toOptional()) {
......@@ -1155,11 +1155,11 @@ pub fn parse(
11551155 if (gop.value_ptr.type != ptr.type_index) {
11561156 var err = try diags.addErrorWithNotes(2);
11571157 try err.addMsg("function signature mismatch: {s}", .{name.slice(wasm)});
1158 gop.value_ptr.source_location.addNote(&err, "exported as {} here", .{
1158 gop.value_ptr.source_location.addNote(&err, "exported as {f} here", .{
11591159 ptr.type_index.fmt(wasm),
11601160 });
11611161 const word = if (gop.value_ptr.resolution == .unresolved) "imported" else "exported";
1162 source_location.addNote(&err, "{s} as {} here", .{ word, gop.value_ptr.type.fmt(wasm) });
1162 source_location.addNote(&err, "{s} as {f} here", .{ word, gop.value_ptr.type.fmt(wasm) });
11631163 continue;
11641164 }
11651165 if (gop.value_ptr.resolution == .unresolved or gop.value_ptr.flags.binding == .weak) {
......@@ -1176,8 +1176,8 @@ pub fn parse(
11761176 }
11771177 var err = try diags.addErrorWithNotes(2);
11781178 try err.addMsg("symbol collision: {s}", .{name.slice(wasm)});
1179 gop.value_ptr.source_location.addNote(&err, "exported as {} here", .{ptr.type_index.fmt(wasm)});
1180 source_location.addNote(&err, "exported as {} here", .{gop.value_ptr.type.fmt(wasm)});
1179 gop.value_ptr.source_location.addNote(&err, "exported as {f} here", .{ptr.type_index.fmt(wasm)});
1180 source_location.addNote(&err, "exported as {f} here", .{gop.value_ptr.type.fmt(wasm)});
11811181 continue;
11821182 } else {
11831183 gop.value_ptr.* = .{
src/link/table_section.zig+1-8
......@@ -39,14 +39,7 @@ pub fn TableSection(comptime Entry: type) type {
3939 return self.entries.items.len;
4040 }
4141
42 pub fn format(
43 self: Self,
44 comptime unused_format_string: []const u8,
45 options: std.fmt.FormatOptions,
46 writer: anytype,
47 ) !void {
48 _ = options;
49 comptime assert(unused_format_string.len == 0);
42 pub fn format(self: Self, writer: *std.io.Writer) std.io.Writer.Error!void {
5043 try writer.writeAll("TableSection:\n");
5144 for (self.entries.items, 0..) |entry, i| {
5245 try writer.print(" {d} => {}\n", .{ i, entry });
src/link/tapi/parse.zig+10-43
......@@ -57,14 +57,9 @@ pub const Node = struct {
5757 }
5858 }
5959
60 pub fn format(
61 self: *const Node,
62 comptime fmt: []const u8,
63 options: std.fmt.FormatOptions,
64 writer: anytype,
65 ) !void {
60 pub fn format(self: *const Node, writer: *std.io.Writer) std.io.Writer.Error!void {
6661 switch (self.tag) {
67 inline else => |tag| return @as(*tag.Type(), @fieldParentPtr("base", self)).format(fmt, options, writer),
62 inline else => |tag| return @as(*tag.Type(), @fieldParentPtr("base", self)).format(writer),
6863 }
6964 }
7065
......@@ -86,24 +81,17 @@ pub const Node = struct {
8681 }
8782 }
8883
89 pub fn format(
90 self: *const Doc,
91 comptime fmt: []const u8,
92 options: std.fmt.FormatOptions,
93 writer: anytype,
94 ) !void {
95 _ = options;
96 _ = fmt;
84 pub fn format(self: *const Doc, writer: *std.io.Writer) std.io.Writer.Error!void {
9785 if (self.directive) |id| {
98 try std.fmt.format(writer, "{{ ", .{});
86 try writer.print("{{ ", .{});
9987 const directive = self.base.tree.getRaw(id, id);
100 try std.fmt.format(writer, ".directive = {s}, ", .{directive});
88 try writer.print(".directive = {s}, ", .{directive});
10189 }
10290 if (self.value) |node| {
103 try std.fmt.format(writer, "{}", .{node});
91 try writer.print("{}", .{node});
10492 }
10593 if (self.directive != null) {
106 try std.fmt.format(writer, " }}", .{});
94 try writer.print(" }}", .{});
10795 }
10896 }
10997 };
......@@ -133,14 +121,7 @@ pub const Node = struct {
133121 self.values.deinit(allocator);
134122 }
135123
136 pub fn format(
137 self: *const Map,
138 comptime fmt: []const u8,
139 options: std.fmt.FormatOptions,
140 writer: anytype,
141 ) !void {
142 _ = options;
143 _ = fmt;
124 pub fn format(self: *const Map, writer: *std.io.Writer) std.io.Writer.Error!void {
144125 try std.fmt.format(writer, "{{ ", .{});
145126 for (self.values.items) |entry| {
146127 const key = self.base.tree.getRaw(entry.key, entry.key);
......@@ -172,14 +153,7 @@ pub const Node = struct {
172153 self.values.deinit(allocator);
173154 }
174155
175 pub fn format(
176 self: *const List,
177 comptime fmt: []const u8,
178 options: std.fmt.FormatOptions,
179 writer: anytype,
180 ) !void {
181 _ = options;
182 _ = fmt;
156 pub fn format(self: *const List, writer: *std.io.Writer) std.io.Writer.Error!void {
183157 try std.fmt.format(writer, "[ ", .{});
184158 for (self.values.items) |node| {
185159 try std.fmt.format(writer, "{}, ", .{node});
......@@ -203,14 +177,7 @@ pub const Node = struct {
203177 self.string_value.deinit(allocator);
204178 }
205179
206 pub fn format(
207 self: *const Value,
208 comptime fmt: []const u8,
209 options: std.fmt.FormatOptions,
210 writer: anytype,
211 ) !void {
212 _ = options;
213 _ = fmt;
180 pub fn format(self: *const Value, writer: *std.io.Writer) std.io.Writer.Error!void {
214181 const raw = self.base.tree.getRaw(self.base.start, self.base.end);
215182 return std.fmt.format(writer, "{s}", .{raw});
216183 }
src/main.zig+108-99
......@@ -65,6 +65,9 @@ pub fn wasi_cwd() std.os.wasi.fd_t {
6565
6666const fatal = std.process.fatal;
6767
68/// This can be global since stdout is a singleton.
69var stdio_buffer: [4096]u8 = undefined;
70
6871/// Shaming all the locations that inappropriately use an O(N) search algorithm.
6972/// Please delete this and fix the compilation errors!
7073pub const @"bad O(N)" = void;
......@@ -340,11 +343,11 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
340343 } else if (mem.eql(u8, cmd, "targets")) {
341344 dev.check(.targets_command);
342345 const host = std.zig.resolveTargetQueryOrFatal(.{});
343 const stdout = io.getStdOut().writer();
346 const stdout = fs.File.stdout().deprecatedWriter();
344347 return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, &host);
345348 } else if (mem.eql(u8, cmd, "version")) {
346349 dev.check(.version_command);
347 try std.io.getStdOut().writeAll(build_options.version ++ "\n");
350 try fs.File.stdout().writeAll(build_options.version ++ "\n");
348351 // Check libc++ linkage to make sure Zig was built correctly, but only
349352 // for "env" and "version" to avoid affecting the startup time for
350353 // build-critical commands (check takes about ~10 μs)
......@@ -352,7 +355,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
352355 } else if (mem.eql(u8, cmd, "env")) {
353356 dev.check(.env_command);
354357 verifyLibcxxCorrectlyLinked();
355 return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer());
358 return @import("print_env.zig").cmdEnv(arena, cmd_args);
356359 } else if (mem.eql(u8, cmd, "reduce")) {
357360 return jitCmd(gpa, arena, cmd_args, .{
358361 .cmd_name = "reduce",
......@@ -360,10 +363,10 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
360363 });
361364 } else if (mem.eql(u8, cmd, "zen")) {
362365 dev.check(.zen_command);
363 return io.getStdOut().writeAll(info_zen);
366 return fs.File.stdout().writeAll(info_zen);
364367 } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
365368 dev.check(.help_command);
366 return io.getStdOut().writeAll(usage);
369 return fs.File.stdout().writeAll(usage);
367370 } else if (mem.eql(u8, cmd, "ast-check")) {
368371 return cmdAstCheck(arena, cmd_args);
369372 } else if (mem.eql(u8, cmd, "detect-cpu")) {
......@@ -1038,7 +1041,7 @@ fn buildOutputType(
10381041 };
10391042 } else if (mem.startsWith(u8, arg, "-")) {
10401043 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
1041 try io.getStdOut().writeAll(usage_build_generic);
1044 try fs.File.stdout().writeAll(usage_build_generic);
10421045 return cleanExit();
10431046 } else if (mem.eql(u8, arg, "--")) {
10441047 if (arg_mode == .run) {
......@@ -1806,6 +1809,7 @@ fn buildOutputType(
18061809 } else manifest_file = arg;
18071810 },
18081811 .assembly, .assembly_with_cpp, .c, .cpp, .h, .hpp, .hm, .hmm, .ll, .bc, .m, .mm => {
1812 dev.check(.c_compiler);
18091813 try create_module.c_source_files.append(arena, .{
18101814 // Populated after module creation.
18111815 .owner = undefined,
......@@ -1816,6 +1820,7 @@ fn buildOutputType(
18161820 });
18171821 },
18181822 .rc => {
1823 dev.check(.win32_resource);
18191824 try create_module.rc_source_files.append(arena, .{
18201825 // Populated after module creation.
18211826 .owner = undefined,
......@@ -2766,9 +2771,9 @@ fn buildOutputType(
27662771 } else if (mem.eql(u8, arg, "-V")) {
27672772 warn("ignoring request for supported emulations: unimplemented", .{});
27682773 } else if (mem.eql(u8, arg, "-v")) {
2769 try std.io.getStdOut().writeAll("zig ld " ++ build_options.version ++ "\n");
2774 try fs.File.stdout().writeAll("zig ld " ++ build_options.version ++ "\n");
27702775 } else if (mem.eql(u8, arg, "--version")) {
2771 try std.io.getStdOut().writeAll("zig ld " ++ build_options.version ++ "\n");
2776 try fs.File.stdout().writeAll("zig ld " ++ build_options.version ++ "\n");
27722777 process.exit(0);
27732778 } else {
27742779 fatal("unsupported linker arg: {s}", .{arg});
......@@ -3301,6 +3306,7 @@ fn buildOutputType(
33013306 defer thread_pool.deinit();
33023307
33033308 for (create_module.c_source_files.items) |*src| {
3309 dev.check(.c_compiler);
33043310 if (!mem.eql(u8, src.src_path, "-")) continue;
33053311
33063312 const ext = src.ext orelse
......@@ -3325,17 +3331,20 @@ fn buildOutputType(
33253331 // for the hashing algorithm here and in the cache are the same.
33263332 // We are providing our own cache key, because this file has nothing
33273333 // to do with the cache manifest.
3328 var hasher = Cache.Hasher.init("0123456789abcdef");
3329 var w = io.multiWriter(.{ f.writer(), hasher.writer() });
3330 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
3331 try fifo.pump(io.getStdIn().reader(), w.writer());
3334 var file_writer = f.writer(&.{});
3335 var buffer: [1000]u8 = undefined;
3336 var hasher = file_writer.interface.hashed(Cache.Hasher.init("0123456789abcdef"), &buffer);
3337 var stdin_reader = fs.File.stdin().readerStreaming(&.{});
3338 _ = hasher.writer.sendFileAll(&stdin_reader, .unlimited) catch |err| switch (err) {
3339 error.WriteFailed => fatal("failed to write {s}: {t}", .{ dump_path, file_writer.err.? }),
3340 else => fatal("failed to pipe stdin to {s}: {t}", .{ dump_path, err }),
3341 };
3342 try hasher.writer.flush();
33323343
3333 var bin_digest: Cache.BinDigest = undefined;
3334 hasher.final(&bin_digest);
3344 const bin_digest: Cache.BinDigest = hasher.hasher.finalResult();
33353345
3336 const sub_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{s}-stdin{s}", .{
3337 std.fmt.fmtSliceHexLower(&bin_digest),
3338 ext.canonicalName(target),
3346 const sub_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-stdin{s}", .{
3347 &bin_digest, ext.canonicalName(target),
33393348 });
33403349 try dirs.local_cache.handle.rename(dump_path, sub_path);
33413350
......@@ -3506,7 +3515,7 @@ fn buildOutputType(
35063515 if (t.arch == target.cpu.arch and t.os == target.os.tag) {
35073516 // If there's a `glibc_min`, there's also an `os_ver`.
35083517 if (t.glibc_min) |glibc_min| {
3509 std.log.info("zig can provide libc for related target {s}-{s}.{}-{s}.{d}.{d}", .{
3518 std.log.info("zig can provide libc for related target {s}-{s}.{f}-{s}.{d}.{d}", .{
35103519 @tagName(t.arch),
35113520 @tagName(t.os),
35123521 t.os_ver.?,
......@@ -3515,7 +3524,7 @@ fn buildOutputType(
35153524 glibc_min.minor,
35163525 });
35173526 } else if (t.os_ver) |os_ver| {
3518 std.log.info("zig can provide libc for related target {s}-{s}.{}-{s}", .{
3527 std.log.info("zig can provide libc for related target {s}-{s}.{f}-{s}", .{
35193528 @tagName(t.arch),
35203529 @tagName(t.os),
35213530 os_ver,
......@@ -3546,15 +3555,15 @@ fn buildOutputType(
35463555 if (show_builtin) {
35473556 const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config);
35483557 const source = try builtin_opts.generate(arena);
3549 return std.io.getStdOut().writeAll(source);
3558 return fs.File.stdout().writeAll(source);
35503559 }
35513560 switch (listen) {
35523561 .none => {},
35533562 .stdio => {
35543563 try serve(
35553564 comp,
3556 std.io.getStdIn(),
3557 std.io.getStdOut(),
3565 .stdin(),
3566 .stdout(),
35583567 test_exec_args.items,
35593568 self_exe_path,
35603569 arg_mode,
......@@ -4606,7 +4615,7 @@ fn cmdTranslateC(
46064615 fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });
46074616 };
46084617 defer zig_file.close();
4609 try io.getStdOut().writeFileAll(zig_file, .{});
4618 try fs.File.stdout().writeFileAll(zig_file, .{});
46104619 return cleanExit();
46114620 }
46124621}
......@@ -4636,7 +4645,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
46364645 if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip")) {
46374646 strip = true;
46384647 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
4639 try io.getStdOut().writeAll(usage_init);
4648 try fs.File.stdout().writeAll(usage_init);
46404649 return cleanExit();
46414650 } else {
46424651 fatal("unrecognized parameter: '{s}'", .{arg});
......@@ -5287,7 +5296,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52875296 const s = fs.path.sep_str;
52885297 const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce;
52895298 const stdout = dirs.local_cache.handle.readFileAlloc(arena, tmp_sub_path, 50 * 1024 * 1024) catch |err| {
5290 fatal("unable to read results of configure phase from '{}{s}': {s}", .{
5299 fatal("unable to read results of configure phase from '{f}{s}': {s}", .{
52915300 dirs.local_cache, tmp_sub_path, @errorName(err),
52925301 });
52935302 };
......@@ -5481,8 +5490,8 @@ fn jitCmd(
54815490 defer comp.destroy();
54825491
54835492 if (options.server) {
5484 var server = std.zig.Server{
5485 .out = std.io.getStdOut(),
5493 var server: std.zig.Server = .{
5494 .out = fs.File.stdout(),
54865495 .in = undefined, // won't be receiving messages
54875496 .receive_fifo = undefined, // won't be receiving messages
54885497 };
......@@ -6015,7 +6024,7 @@ fn cmdAstCheck(
60156024 const arg = args[i];
60166025 if (mem.startsWith(u8, arg, "-")) {
60176026 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
6018 try io.getStdOut().writeAll(usage_ast_check);
6027 try fs.File.stdout().writeAll(usage_ast_check);
60196028 return cleanExit();
60206029 } else if (mem.eql(u8, arg, "-t")) {
60216030 want_output_text = true;
......@@ -6046,7 +6055,7 @@ fn cmdAstCheck(
60466055 break :file fs.cwd().openFile(p, .{}) catch |err| {
60476056 fatal("unable to open file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
60486057 };
6049 } else io.getStdIn();
6058 } else fs.File.stdin();
60506059 defer if (zig_source_path != null) f.close();
60516060 break :s std.zig.readSourceFileToEndAlloc(arena, f, null) catch |err| {
60526061 fatal("unable to load file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
......@@ -6065,6 +6074,8 @@ fn cmdAstCheck(
60656074
60666075 const tree = try Ast.parse(arena, source, mode);
60676076
6077 var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
6078 const stdout_bw = &stdout_writer.interface;
60686079 switch (mode) {
60696080 .zig => {
60706081 const zir = try AstGen.generate(arena, tree);
......@@ -6107,31 +6118,30 @@ fn cmdAstCheck(
61076118 const extra_bytes = zir.extra.len * @sizeOf(u32);
61086119 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
61096120 zir.string_bytes.len * @sizeOf(u8);
6110 const stdout = io.getStdOut();
6111 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
61126121 // zig fmt: off
6113 try stdout.writer().print(
6114 \\# Source bytes: {}
6115 \\# Tokens: {} ({})
6116 \\# AST Nodes: {} ({})
6117 \\# Total ZIR bytes: {}
6118 \\# Instructions: {d} ({})
6122 try stdout_bw.print(
6123 \\# Source bytes: {Bi}
6124 \\# Tokens: {} ({Bi})
6125 \\# AST Nodes: {} ({Bi})
6126 \\# Total ZIR bytes: {Bi}
6127 \\# Instructions: {d} ({Bi})
61196128 \\# String Table Bytes: {}
6120 \\# Extra Data Items: {d} ({})
6129 \\# Extra Data Items: {d} ({Bi})
61216130 \\
61226131 , .{
6123 fmtIntSizeBin(source.len),
6124 tree.tokens.len, fmtIntSizeBin(token_bytes),
6125 tree.nodes.len, fmtIntSizeBin(tree_bytes),
6126 fmtIntSizeBin(total_bytes),
6127 zir.instructions.len, fmtIntSizeBin(instruction_bytes),
6128 fmtIntSizeBin(zir.string_bytes.len),
6129 zir.extra.len, fmtIntSizeBin(extra_bytes),
6132 source.len,
6133 tree.tokens.len, token_bytes,
6134 tree.nodes.len, tree_bytes,
6135 total_bytes,
6136 zir.instructions.len, instruction_bytes,
6137 zir.string_bytes.len,
6138 zir.extra.len, extra_bytes,
61306139 });
61316140 // zig fmt: on
61326141 }
61336142
6134 try @import("print_zir.zig").renderAsTextToFile(arena, tree, zir, io.getStdOut());
6143 try @import("print_zir.zig").renderAsText(arena, tree, zir, stdout_bw);
6144 try stdout_bw.flush();
61356145
61366146 if (zir.hasCompileErrors()) {
61376147 process.exit(1);
......@@ -6158,7 +6168,8 @@ fn cmdAstCheck(
61586168 fatal("-t option only available in builds of zig with debug extensions", .{});
61596169 }
61606170
6161 try @import("print_zoir.zig").renderToFile(zoir, arena, io.getStdOut());
6171 try @import("print_zoir.zig").renderToWriter(zoir, arena, stdout_bw);
6172 try stdout_bw.flush();
61626173 return cleanExit();
61636174 },
61646175 }
......@@ -6186,8 +6197,7 @@ fn cmdDetectCpu(args: []const []const u8) !void {
61866197 const arg = args[i];
61876198 if (mem.startsWith(u8, arg, "-")) {
61886199 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
6189 const stdout = io.getStdOut().writer();
6190 try stdout.writeAll(detect_cpu_usage);
6200 try fs.File.stdout().writeAll(detect_cpu_usage);
61916201 return cleanExit();
61926202 } else if (mem.eql(u8, arg, "--llvm")) {
61936203 use_llvm = true;
......@@ -6279,11 +6289,11 @@ fn detectNativeCpuWithLLVM(
62796289}
62806290
62816291fn printCpu(cpu: std.Target.Cpu) !void {
6282 var bw = io.bufferedWriter(io.getStdOut().writer());
6283 const stdout = bw.writer();
6292 var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
6293 const stdout_bw = &stdout_writer.interface;
62846294
62856295 if (cpu.model.llvm_name) |llvm_name| {
6286 try stdout.print("{s}\n", .{llvm_name});
6296 try stdout_bw.print("{s}\n", .{llvm_name});
62876297 }
62886298
62896299 const all_features = cpu.arch.allFeaturesList();
......@@ -6292,10 +6302,10 @@ fn printCpu(cpu: std.Target.Cpu) !void {
62926302 const index: std.Target.Cpu.Feature.Set.Index = @intCast(index_usize);
62936303 const is_enabled = cpu.features.isEnabled(index);
62946304 const plus_or_minus = "-+"[@intFromBool(is_enabled)];
6295 try stdout.print("{c}{s}\n", .{ plus_or_minus, llvm_name });
6305 try stdout_bw.print("{c}{s}\n", .{ plus_or_minus, llvm_name });
62966306 }
62976307
6298 try bw.flush();
6308 try stdout_bw.flush();
62996309}
63006310
63016311fn cmdDumpLlvmInts(
......@@ -6328,16 +6338,14 @@ fn cmdDumpLlvmInts(
63286338 const dl = tm.createTargetDataLayout();
63296339 const context = llvm.Context.create();
63306340
6331 var bw = io.bufferedWriter(io.getStdOut().writer());
6332 const stdout = bw.writer();
6333
6341 var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
6342 const stdout_bw = &stdout_writer.interface;
63346343 for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| {
63356344 const int_type = context.intType(bits);
63366345 const alignment = dl.abiAlignmentOfType(int_type);
6337 try stdout.print("LLVMABIAlignmentOfType(i{d}) == {d}\n", .{ bits, alignment });
6346 try stdout_bw.print("LLVMABIAlignmentOfType(i{d}) == {d}\n", .{ bits, alignment });
63386347 }
6339
6340 try bw.flush();
6348 try stdout_bw.flush();
63416349
63426350 return cleanExit();
63436351}
......@@ -6359,6 +6367,8 @@ fn cmdDumpZir(
63596367 defer f.close();
63606368
63616369 const zir = try Zcu.loadZirCache(arena, f);
6370 var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
6371 const stdout_bw = &stdout_writer.interface;
63626372
63636373 {
63646374 const instruction_bytes = zir.instructions.len *
......@@ -6368,25 +6378,24 @@ fn cmdDumpZir(
63686378 const extra_bytes = zir.extra.len * @sizeOf(u32);
63696379 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
63706380 zir.string_bytes.len * @sizeOf(u8);
6371 const stdout = io.getStdOut();
6372 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
63736381 // zig fmt: off
6374 try stdout.writer().print(
6375 \\# Total ZIR bytes: {}
6376 \\# Instructions: {d} ({})
6377 \\# String Table Bytes: {}
6378 \\# Extra Data Items: {d} ({})
6382 try stdout_bw.print(
6383 \\# Total ZIR bytes: {Bi}
6384 \\# Instructions: {d} ({Bi})
6385 \\# String Table Bytes: {Bi}
6386 \\# Extra Data Items: {d} ({Bi})
63796387 \\
63806388 , .{
6381 fmtIntSizeBin(total_bytes),
6382 zir.instructions.len, fmtIntSizeBin(instruction_bytes),
6383 fmtIntSizeBin(zir.string_bytes.len),
6384 zir.extra.len, fmtIntSizeBin(extra_bytes),
6389 total_bytes,
6390 zir.instructions.len, instruction_bytes,
6391 zir.string_bytes.len,
6392 zir.extra.len, extra_bytes,
63856393 });
63866394 // zig fmt: on
63876395 }
63886396
6389 return @import("print_zir.zig").renderAsTextToFile(arena, null, zir, io.getStdOut());
6397 try @import("print_zir.zig").renderAsText(arena, null, zir, stdout_bw);
6398 try stdout_bw.flush();
63906399}
63916400
63926401/// This is only enabled for debug builds.
......@@ -6444,19 +6453,19 @@ fn cmdChangelist(
64446453 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;
64456454 try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map);
64466455
6447 var bw = io.bufferedWriter(io.getStdOut().writer());
6448 const stdout = bw.writer();
6456 var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
6457 const stdout_bw = &stdout_writer.interface;
64496458 {
6450 try stdout.print("Instruction mappings:\n", .{});
6459 try stdout_bw.print("Instruction mappings:\n", .{});
64516460 var it = inst_map.iterator();
64526461 while (it.next()) |entry| {
6453 try stdout.print(" %{d} => %{d}\n", .{
6462 try stdout_bw.print(" %{d} => %{d}\n", .{
64546463 @intFromEnum(entry.key_ptr.*),
64556464 @intFromEnum(entry.value_ptr.*),
64566465 });
64576466 }
64586467 }
6459 try bw.flush();
6468 try stdout_bw.flush();
64606469}
64616470
64626471fn eatIntPrefix(arg: []const u8, base: u8) []const u8 {
......@@ -6718,13 +6727,10 @@ fn accessFrameworkPath(
67186727
67196728 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
67206729 test_path.clearRetainingCapacity();
6721 try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
6722 framework_dir_path,
6723 framework_name,
6724 framework_name,
6725 ext,
6730 try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
6731 framework_dir_path, framework_name, framework_name, ext,
67266732 });
6727 try checked_paths.writer().print("\n {s}", .{test_path.items});
6733 try checked_paths.print("\n {s}", .{test_path.items});
67286734 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
67296735 error.FileNotFound => continue,
67306736 else => |e| fatal("unable to search for {s} framework '{s}': {s}", .{
......@@ -6794,8 +6800,7 @@ fn cmdFetch(
67946800 const arg = args[i];
67956801 if (mem.startsWith(u8, arg, "-")) {
67966802 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
6797 const stdout = io.getStdOut().writer();
6798 try stdout.writeAll(usage_fetch);
6803 try fs.File.stdout().writeAll(usage_fetch);
67996804 return cleanExit();
68006805 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
68016806 if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
......@@ -6908,7 +6913,9 @@ fn cmdFetch(
69086913
69096914 const name = switch (save) {
69106915 .no => {
6911 try io.getStdOut().writer().print("{s}\n", .{package_hash_slice});
6916 var stdout = fs.File.stdout().writerStreaming(&stdio_buffer);
6917 try stdout.interface.print("{s}\n", .{package_hash_slice});
6918 try stdout.interface.flush();
69126919 return cleanExit();
69136920 },
69146921 .yes, .exact => |name| name: {
......@@ -6944,7 +6951,7 @@ fn cmdFetch(
69446951 var saved_path_or_url = path_or_url;
69456952
69466953 if (fetch.latest_commit) |latest_commit| resolved: {
6947 const latest_commit_hex = try std.fmt.allocPrint(arena, "{}", .{latest_commit});
6954 const latest_commit_hex = try std.fmt.allocPrint(arena, "{f}", .{latest_commit});
69486955
69496956 var uri = try std.Uri.parse(path_or_url);
69506957
......@@ -6957,7 +6964,9 @@ fn cmdFetch(
69576964 std.log.info("resolved ref '{s}' to commit {s}", .{ target_ref, latest_commit_hex });
69586965
69596966 // include the original refspec in a query parameter, could be used to check for updates
6960 uri.query = .{ .percent_encoded = try std.fmt.allocPrint(arena, "ref={%}", .{fragment}) };
6967 uri.query = .{ .percent_encoded = try std.fmt.allocPrint(arena, "ref={f}", .{
6968 std.fmt.alt(fragment, .formatEscaped),
6969 }) };
69616970 } else {
69626971 std.log.info("resolved to commit {s}", .{latest_commit_hex});
69636972 }
......@@ -6966,23 +6975,23 @@ fn cmdFetch(
69666975 uri.fragment = .{ .raw = latest_commit_hex };
69676976
69686977 switch (save) {
6969 .yes => saved_path_or_url = try std.fmt.allocPrint(arena, "{}", .{uri}),
6978 .yes => saved_path_or_url = try std.fmt.allocPrint(arena, "{f}", .{uri}),
69706979 .no, .exact => {}, // keep the original URL
69716980 }
69726981 }
69736982
69746983 const new_node_init = try std.fmt.allocPrint(arena,
69756984 \\.{{
6976 \\ .url = "{}",
6977 \\ .hash = "{}",
6985 \\ .url = "{f}",
6986 \\ .hash = "{f}",
69786987 \\ }}
69796988 , .{
6980 std.zig.fmtEscapes(saved_path_or_url),
6981 std.zig.fmtEscapes(package_hash_slice),
6989 std.zig.fmtString(saved_path_or_url),
6990 std.zig.fmtString(package_hash_slice),
69826991 });
69836992
6984 const new_node_text = try std.fmt.allocPrint(arena, ".{p_} = {s},\n", .{
6985 std.zig.fmtId(name), new_node_init,
6993 const new_node_text = try std.fmt.allocPrint(arena, ".{f} = {s},\n", .{
6994 std.zig.fmtIdPU(name), new_node_init,
69866995 });
69876996
69886997 const dependencies_init = try std.fmt.allocPrint(arena, ".{{\n {s} }}", .{
......@@ -7008,13 +7017,13 @@ fn cmdFetch(
70087017
70097018 const location_replace = try std.fmt.allocPrint(
70107019 arena,
7011 "\"{}\"",
7012 .{std.zig.fmtEscapes(saved_path_or_url)},
7020 "\"{f}\"",
7021 .{std.zig.fmtString(saved_path_or_url)},
70137022 );
70147023 const hash_replace = try std.fmt.allocPrint(
70157024 arena,
7016 "\"{}\"",
7017 .{std.zig.fmtEscapes(package_hash_slice)},
7025 "\"{f}\"",
7026 .{std.zig.fmtString(package_hash_slice)},
70187027 );
70197028
70207029 warn("overwriting existing dependency named '{s}'", .{name});
src/print_env.zig+2-2
......@@ -4,7 +4,7 @@ const introspect = @import("introspect.zig");
44const Allocator = std.mem.Allocator;
55const fatal = std.process.fatal;
66
7pub fn cmdEnv(arena: Allocator, args: []const []const u8, stdout: std.fs.File.Writer) !void {
7pub fn cmdEnv(arena: Allocator, args: []const []const u8) !void {
88 _ = args;
99 const cwd_path = try introspect.getResolvedCwd(arena);
1010 const self_exe_path = try std.fs.selfExePathAlloc(arena);
......@@ -21,7 +21,7 @@ pub fn cmdEnv(arena: Allocator, args: []const []const u8, stdout: std.fs.File.Wr
2121 const host = try std.zig.system.resolveTargetQuery(.{});
2222 const triple = try host.zigTriple(arena);
2323
24 var bw = std.io.bufferedWriter(stdout);
24 var bw = std.io.bufferedWriter(std.fs.File.stdout().deprecatedWriter());
2525 const w = bw.writer();
2626
2727 var jws = std.json.writeStream(w, .{ .whitespace = .indent_1 });
src/print_targets.zig+1-1
......@@ -64,7 +64,7 @@ pub fn cmdTargets(
6464 {
6565 var glibc_obj = try root_obj.beginTupleField("glibc", .{});
6666 for (glibc_abi.all_versions) |ver| {
67 const tmp = try std.fmt.allocPrint(allocator, "{}", .{ver});
67 const tmp = try std.fmt.allocPrint(allocator, "{f}", .{ver});
6868 defer allocator.free(tmp);
6969 try glibc_obj.field(tmp, .{});
7070 }
src/print_value.zig+34-47
......@@ -20,15 +20,8 @@ pub const FormatContext = struct {
2020 depth: u8,
2121};
2222
23pub fn formatSema(
24 ctx: FormatContext,
25 comptime fmt: []const u8,
26 options: std.fmt.FormatOptions,
27 writer: anytype,
28) !void {
29 _ = options;
23pub fn formatSema(ctx: FormatContext, writer: *std.io.Writer) std.io.Writer.Error!void {
3024 const sema = ctx.opt_sema.?;
31 comptime std.debug.assert(fmt.len == 0);
3225 return print(ctx.val, writer, ctx.depth, ctx.pt, sema) catch |err| switch (err) {
3326 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
3427 error.ComptimeBreak, error.ComptimeReturn => unreachable,
......@@ -37,15 +30,8 @@ pub fn formatSema(
3730 };
3831}
3932
40pub fn format(
41 ctx: FormatContext,
42 comptime fmt: []const u8,
43 options: std.fmt.FormatOptions,
44 writer: anytype,
45) !void {
46 _ = options;
33pub fn format(ctx: FormatContext, writer: *std.io.Writer) std.io.Writer.Error!void {
4734 std.debug.assert(ctx.opt_sema == null);
48 comptime std.debug.assert(fmt.len == 0);
4935 return print(ctx.val, writer, ctx.depth, ctx.pt, null) catch |err| switch (err) {
5036 error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
5137 error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable,
......@@ -55,11 +41,11 @@ pub fn format(
5541
5642pub fn print(
5743 val: Value,
58 writer: anytype,
44 writer: *std.io.Writer,
5945 level: u8,
6046 pt: Zcu.PerThread,
6147 opt_sema: ?*Sema,
62) (@TypeOf(writer).Error || Zcu.CompileError)!void {
48) (std.io.Writer.Error || Zcu.CompileError)!void {
6349 const zcu = pt.zcu;
6450 const ip = &zcu.intern_pool;
6551 switch (ip.indexToKey(val.toIntern())) {
......@@ -87,35 +73,36 @@ pub fn print(
8773 else => try writer.writeAll(@tagName(simple_value)),
8874 },
8975 .variable => try writer.writeAll("(variable)"),
90 .@"extern" => |e| try writer.print("(extern '{}')", .{e.name.fmt(ip)}),
91 .func => |func| try writer.print("(function '{}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}),
76 .@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}),
77 .func => |func| try writer.print("(function '{f}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}),
9278 .int => |int| switch (int.storage) {
93 inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),
79 inline .u64, .i64 => |x| try writer.print("{d}", .{x}),
80 .big_int => |x| try writer.print("{d}", .{x}),
9481 .lazy_align => |ty| if (opt_sema != null) {
9582 const a = try Type.fromInterned(ty).abiAlignmentSema(pt);
96 try writer.print("{}", .{a.toByteUnits() orelse 0});
97 } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(pt)}),
83 try writer.print("{d}", .{a.toByteUnits() orelse 0});
84 } else try writer.print("@alignOf({f})", .{Type.fromInterned(ty).fmt(pt)}),
9885 .lazy_size => |ty| if (opt_sema != null) {
9986 const s = try Type.fromInterned(ty).abiSizeSema(pt);
100 try writer.print("{}", .{s});
101 } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(pt)}),
87 try writer.print("{d}", .{s});
88 } else try writer.print("@sizeOf({f})", .{Type.fromInterned(ty).fmt(pt)}),
10289 },
103 .err => |err| try writer.print("error.{}", .{
90 .err => |err| try writer.print("error.{f}", .{
10491 err.name.fmt(ip),
10592 }),
10693 .error_union => |error_union| switch (error_union.val) {
107 .err_name => |err_name| try writer.print("error.{}", .{
94 .err_name => |err_name| try writer.print("error.{f}", .{
10895 err_name.fmt(ip),
10996 }),
11097 .payload => |payload| try print(Value.fromInterned(payload), writer, level, pt, opt_sema),
11198 },
112 .enum_literal => |enum_literal| try writer.print(".{}", .{
99 .enum_literal => |enum_literal| try writer.print(".{f}", .{
113100 enum_literal.fmt(ip),
114101 }),
115102 .enum_tag => |enum_tag| {
116103 const enum_type = ip.loadEnumType(val.typeOf(zcu).toIntern());
117104 if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {
118 return writer.print(".{i}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});
105 return writer.print(".{f}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});
119106 }
120107 if (level == 0) {
121108 return writer.writeAll("@enumFromInt(...)");
......@@ -178,7 +165,7 @@ pub fn print(
178165 }
179166 if (un.tag == .none) {
180167 const backing_ty = try val.typeOf(zcu).unionBackingType(pt);
181 try writer.print("@bitCast(@as({}, ", .{backing_ty.fmt(pt)});
168 try writer.print("@bitCast(@as({f}, ", .{backing_ty.fmt(pt)});
182169 try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema);
183170 try writer.writeAll("))");
184171 } else {
......@@ -197,11 +184,11 @@ fn printAggregate(
197184 val: Value,
198185 aggregate: InternPool.Key.Aggregate,
199186 is_ref: bool,
200 writer: anytype,
187 writer: *std.io.Writer,
201188 level: u8,
202189 pt: Zcu.PerThread,
203190 opt_sema: ?*Sema,
204) (@TypeOf(writer).Error || Zcu.CompileError)!void {
191) (std.io.Writer.Error || Zcu.CompileError)!void {
205192 if (level == 0) {
206193 if (is_ref) try writer.writeByte('&');
207194 return writer.writeAll(".{ ... }");
......@@ -220,7 +207,7 @@ fn printAggregate(
220207 for (0..max_len) |i| {
221208 if (i != 0) try writer.writeAll(", ");
222209 const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?;
223 try writer.print(".{i} = ", .{field_name.fmt(ip)});
210 try writer.print(".{f} = ", .{field_name.fmt(ip)});
224211 try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);
225212 }
226213 try writer.writeAll(" }");
......@@ -232,7 +219,7 @@ fn printAggregate(
232219 const len = ty.arrayLenIncludingSentinel(zcu);
233220 if (len == 0) break :string;
234221 const slice = bytes.toSlice(if (bytes.at(len - 1, ip) == 0) len - 1 else len, ip);
235 try writer.print("\"{}\"", .{std.zig.fmtEscapes(slice)});
222 try writer.print("\"{f}\"", .{std.zig.fmtString(slice)});
236223 if (!is_ref) try writer.writeAll(".*");
237224 return;
238225 },
......@@ -249,7 +236,7 @@ fn printAggregate(
249236 const elem_val = Value.fromInterned(aggregate.storage.values()[0]);
250237 if (elem_val.isUndef(zcu)) break :one_byte_str;
251238 const byte = elem_val.toUnsignedInt(zcu);
252 try writer.print("\"{}\"", .{std.zig.fmtEscapes(&.{@intCast(byte)})});
239 try writer.print("\"{f}\"", .{std.zig.fmtString(&.{@intCast(byte)})});
253240 if (!is_ref) try writer.writeAll(".*");
254241 return;
255242 },
......@@ -283,11 +270,11 @@ fn printPtr(
283270 ptr_val: Value,
284271 /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen.
285272 want_kind: ?PrintPtrKind,
286 writer: anytype,
273 writer: *std.io.Writer,
287274 level: u8,
288275 pt: Zcu.PerThread,
289276 opt_sema: ?*Sema,
290) (@TypeOf(writer).Error || Zcu.CompileError)!void {
277) (std.io.Writer.Error || Zcu.CompileError)!void {
291278 const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
292279 .undef => return writer.writeAll("undefined"),
293280 .ptr => |ptr| ptr,
......@@ -329,7 +316,7 @@ const PrintPtrKind = enum { lvalue, rvalue };
329316/// Returns the root derivation, which may be ignored.
330317pub fn printPtrDerivation(
331318 derivation: Value.PointerDeriveStep,
332 writer: anytype,
319 writer: *std.io.Writer,
333320 pt: Zcu.PerThread,
334321 /// Whether to print `derivation` as an lvalue or rvalue. If `null`, the more concise option is chosen.
335322 /// If this is `.rvalue`, the result may look like `&foo`, so it's not necessarily valid to treat it as
......@@ -405,14 +392,14 @@ pub fn printPtrDerivation(
405392 const agg_ty = (try field.parent.ptrType(pt)).childType(zcu);
406393 switch (agg_ty.zigTypeTag(zcu)) {
407394 .@"struct" => if (agg_ty.structFieldName(field.field_idx, zcu).unwrap()) |field_name| {
408 try writer.print(".{i}", .{field_name.fmt(ip)});
395 try writer.print(".{f}", .{field_name.fmt(ip)});
409396 } else {
410397 try writer.print("[{d}]", .{field.field_idx});
411398 },
412399 .@"union" => {
413400 const tag_ty = agg_ty.unionTagTypeHypothetical(zcu);
414401 const field_name = tag_ty.enumFieldName(field.field_idx, zcu);
415 try writer.print(".{i}", .{field_name.fmt(ip)});
402 try writer.print(".{f}", .{field_name.fmt(ip)});
416403 },
417404 .pointer => switch (field.field_idx) {
418405 Value.slice_ptr_index => try writer.writeAll(".ptr"),
......@@ -430,12 +417,12 @@ pub fn printPtrDerivation(
430417 },
431418
432419 .offset_and_cast => |oac| if (oac.byte_offset == 0) root: {
433 try writer.print("@as({}, @ptrCast(", .{oac.new_ptr_ty.fmt(pt)});
420 try writer.print("@as({f}, @ptrCast(", .{oac.new_ptr_ty.fmt(pt)});
434421 const root = try printPtrDerivation(oac.parent.*, writer, pt, .rvalue, root_strat, ptr_depth - 1);
435422 try writer.writeAll("))");
436423 break :root root;
437424 } else root: {
438 try writer.print("@as({}, @ptrFromInt(@intFromPtr(", .{oac.new_ptr_ty.fmt(pt)});
425 try writer.print("@as({f}, @ptrFromInt(@intFromPtr(", .{oac.new_ptr_ty.fmt(pt)});
439426 const root = try printPtrDerivation(oac.parent.*, writer, pt, .rvalue, root_strat, ptr_depth - 1);
440427 try writer.print(") + {d}))", .{oac.byte_offset});
441428 break :root root;
......@@ -447,22 +434,22 @@ pub fn printPtrDerivation(
447434 if (root_or_null == null) switch (root_strat) {
448435 .str => |x| try writer.writeAll(x),
449436 .print_val => |x| switch (derivation) {
450 .int => |int| try writer.print("@as({}, @ptrFromInt(0x{x}))", .{ int.ptr_ty.fmt(pt), int.addr }),
451 .nav_ptr => |nav| try writer.print("{}", .{ip.getNav(nav).fqn.fmt(ip)}),
437 .int => |int| try writer.print("@as({f}, @ptrFromInt(0x{x}))", .{ int.ptr_ty.fmt(pt), int.addr }),
438 .nav_ptr => |nav| try writer.print("{f}", .{ip.getNav(nav).fqn.fmt(ip)}),
452439 .uav_ptr => |uav| {
453440 const ty = Value.fromInterned(uav.val).typeOf(zcu);
454 try writer.print("@as({}, ", .{ty.fmt(pt)});
441 try writer.print("@as({f}, ", .{ty.fmt(pt)});
455442 try print(Value.fromInterned(uav.val), writer, x.level - 1, pt, x.opt_sema);
456443 try writer.writeByte(')');
457444 },
458445 .comptime_alloc_ptr => |info| {
459 try writer.print("@as({}, ", .{info.val.typeOf(zcu).fmt(pt)});
446 try writer.print("@as({f}, ", .{info.val.typeOf(zcu).fmt(pt)});
460447 try print(info.val, writer, x.level - 1, pt, x.opt_sema);
461448 try writer.writeByte(')');
462449 },
463450 .comptime_field_ptr => |val| {
464451 const ty = val.typeOf(zcu);
465 try writer.print("@as({}, ", .{ty.fmt(pt)});
452 try writer.print("@as({f}, ", .{ty.fmt(pt)});
466453 try print(val, writer, x.level - 1, pt, x.opt_sema);
467454 try writer.writeByte(')');
468455 },
src/print_zir.zig+185-195
......@@ -9,13 +9,8 @@ const Zir = std.zig.Zir;
99const Zcu = @import("Zcu.zig");
1010const LazySrcLoc = Zcu.LazySrcLoc;
1111
12/// Write human-readable, debug formatted ZIR code to a file.
13pub fn renderAsTextToFile(
14 gpa: Allocator,
15 tree: ?Ast,
16 zir: Zir,
17 fs_file: std.fs.File,
18) !void {
12/// Write human-readable, debug formatted ZIR code.
13pub fn renderAsText(gpa: Allocator, tree: ?Ast, zir: Zir, bw: *std.io.Writer) !void {
1914 var arena = std.heap.ArenaAllocator.init(gpa);
2015 defer arena.deinit();
2116
......@@ -30,16 +25,13 @@ pub fn renderAsTextToFile(
3025 .recurse_blocks = true,
3126 };
3227
33 var raw_stream = std.io.bufferedWriter(fs_file.writer());
34 const stream = raw_stream.writer();
35
3628 const main_struct_inst: Zir.Inst.Index = .main_struct_inst;
37 try stream.print("%{d} ", .{@intFromEnum(main_struct_inst)});
38 try writer.writeInstToStream(stream, main_struct_inst);
39 try stream.writeAll("\n");
29 try bw.print("%{d} ", .{@intFromEnum(main_struct_inst)});
30 try writer.writeInstToStream(bw, main_struct_inst);
31 try bw.writeAll("\n");
4032 const imports_index = zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
4133 if (imports_index != 0) {
42 try stream.writeAll("Imports:\n");
34 try bw.writeAll("Imports:\n");
4335
4436 const extra = zir.extraData(Zir.Inst.Imports, imports_index);
4537 var extra_index = extra.end;
......@@ -49,15 +41,13 @@ pub fn renderAsTextToFile(
4941 extra_index = item.end;
5042
5143 const import_path = zir.nullTerminatedString(item.data.name);
52 try stream.print(" @import(\"{}\") ", .{
53 std.zig.fmtEscapes(import_path),
44 try bw.print(" @import(\"{f}\") ", .{
45 std.zig.fmtString(import_path),
5446 });
55 try writer.writeSrcTokAbs(stream, item.data.token);
56 try stream.writeAll("\n");
47 try writer.writeSrcTokAbs(bw, item.data.token);
48 try bw.writeAll("\n");
5749 }
5850 }
59
60 try raw_stream.flush();
6151}
6252
6353pub fn renderInstructionContext(
......@@ -67,7 +57,7 @@ pub fn renderInstructionContext(
6757 scope_file: *Zcu.File,
6858 parent_decl_node: Ast.Node.Index,
6959 indent: u32,
70 stream: anytype,
60 bw: *std.io.Writer,
7161) !void {
7262 var arena = std.heap.ArenaAllocator.init(gpa);
7363 defer arena.deinit();
......@@ -83,13 +73,13 @@ pub fn renderInstructionContext(
8373 .recurse_blocks = true,
8474 };
8575
86 try writer.writeBody(stream, block[0..block_index]);
87 try stream.writeByteNTimes(' ', writer.indent - 2);
88 try stream.print("> %{d} ", .{@intFromEnum(block[block_index])});
89 try writer.writeInstToStream(stream, block[block_index]);
90 try stream.writeByte('\n');
76 try writer.writeBody(bw, block[0..block_index]);
77 try bw.splatByteAll(' ', writer.indent - 2);
78 try bw.print("> %{d} ", .{@intFromEnum(block[block_index])});
79 try writer.writeInstToStream(bw, block[block_index]);
80 try bw.writeByte('\n');
9181 if (block_index + 1 < block.len) {
92 try writer.writeBody(stream, block[block_index + 1 ..]);
82 try writer.writeBody(bw, block[block_index + 1 ..]);
9383 }
9484}
9585
......@@ -99,7 +89,7 @@ pub fn renderSingleInstruction(
9989 scope_file: *Zcu.File,
10090 parent_decl_node: Ast.Node.Index,
10191 indent: u32,
102 stream: anytype,
92 bw: *std.io.Writer,
10393) !void {
10494 var arena = std.heap.ArenaAllocator.init(gpa);
10595 defer arena.deinit();
......@@ -115,8 +105,8 @@ pub fn renderSingleInstruction(
115105 .recurse_blocks = false,
116106 };
117107
118 try stream.print("%{d} ", .{@intFromEnum(inst)});
119 try writer.writeInstToStream(stream, inst);
108 try bw.print("%{d} ", .{@intFromEnum(inst)});
109 try writer.writeInstToStream(bw, inst);
120110}
121111
122112const Writer = struct {
......@@ -186,11 +176,13 @@ const Writer = struct {
186176 }
187177 } = .{},
188178
179 const Error = std.io.Writer.Error || Allocator.Error;
180
189181 fn writeInstToStream(
190182 self: *Writer,
191 stream: anytype,
183 stream: *std.io.Writer,
192184 inst: Zir.Inst.Index,
193 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
185 ) Error!void {
194186 const tags = self.code.instructions.items(.tag);
195187 const tag = tags[@intFromEnum(inst)];
196188 try stream.print("= {s}(", .{@tagName(tags[@intFromEnum(inst)])});
......@@ -516,7 +508,7 @@ const Writer = struct {
516508 }
517509 }
518510
519 fn writeExtended(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
511 fn writeExtended(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
520512 const extended = self.code.instructions.items(.data)[@intFromEnum(inst)].extended;
521513 try stream.print("{s}(", .{@tagName(extended.opcode)});
522514 switch (extended.opcode) {
......@@ -623,13 +615,13 @@ const Writer = struct {
623615 }
624616 }
625617
626 fn writeExtNode(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
618 fn writeExtNode(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
627619 try stream.writeAll(")) ");
628620 const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
629621 try self.writeSrcNode(stream, src_node);
630622 }
631623
632 fn writeArrayInitElemType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
624 fn writeArrayInitElemType(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
633625 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].bin;
634626 try self.writeInstRef(stream, inst_data.lhs);
635627 try stream.print(", {d})", .{@intFromEnum(inst_data.rhs)});
......@@ -637,9 +629,9 @@ const Writer = struct {
637629
638630 fn writeUnNode(
639631 self: *Writer,
640 stream: anytype,
632 stream: *std.io.Writer,
641633 inst: Zir.Inst.Index,
642 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
634 ) Error!void {
643635 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
644636 try self.writeInstRef(stream, inst_data.operand);
645637 try stream.writeAll(") ");
......@@ -648,9 +640,9 @@ const Writer = struct {
648640
649641 fn writeUnTok(
650642 self: *Writer,
651 stream: anytype,
643 stream: *std.io.Writer,
652644 inst: Zir.Inst.Index,
653 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
645 ) Error!void {
654646 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].un_tok;
655647 try self.writeInstRef(stream, inst_data.operand);
656648 try stream.writeAll(") ");
......@@ -659,9 +651,9 @@ const Writer = struct {
659651
660652 fn writeValidateDestructure(
661653 self: *Writer,
662 stream: anytype,
654 stream: *std.io.Writer,
663655 inst: Zir.Inst.Index,
664 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
656 ) Error!void {
665657 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
666658 const extra = self.code.extraData(Zir.Inst.ValidateDestructure, inst_data.payload_index).data;
667659 try self.writeInstRef(stream, extra.operand);
......@@ -673,9 +665,9 @@ const Writer = struct {
673665
674666 fn writeValidateArrayInitTy(
675667 self: *Writer,
676 stream: anytype,
668 stream: *std.io.Writer,
677669 inst: Zir.Inst.Index,
678 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
670 ) Error!void {
679671 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
680672 const extra = self.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
681673 try self.writeInstRef(stream, extra.ty);
......@@ -685,9 +677,9 @@ const Writer = struct {
685677
686678 fn writeArrayTypeSentinel(
687679 self: *Writer,
688 stream: anytype,
680 stream: *std.io.Writer,
689681 inst: Zir.Inst.Index,
690 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
682 ) Error!void {
691683 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
692684 const extra = self.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data;
693685 try self.writeInstRef(stream, extra.len);
......@@ -701,9 +693,9 @@ const Writer = struct {
701693
702694 fn writePtrType(
703695 self: *Writer,
704 stream: anytype,
696 stream: *std.io.Writer,
705697 inst: Zir.Inst.Index,
706 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
698 ) Error!void {
707699 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].ptr_type;
708700 const str_allowzero = if (inst_data.flags.is_allowzero) "allowzero, " else "";
709701 const str_const = if (!inst_data.flags.is_mutable) "const, " else "";
......@@ -744,12 +736,12 @@ const Writer = struct {
744736 try self.writeSrcNode(stream, extra.data.src_node);
745737 }
746738
747 fn writeInt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
739 fn writeInt(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
748740 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].int;
749741 try stream.print("{d})", .{inst_data});
750742 }
751743
752 fn writeIntBig(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
744 fn writeIntBig(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
753745 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;
754746 const byte_count = inst_data.len * @sizeOf(std.math.big.Limb);
755747 const limb_bytes = self.code.string_bytes[@intFromEnum(inst_data.start)..][0..byte_count];
......@@ -768,12 +760,12 @@ const Writer = struct {
768760 try stream.print("{s})", .{as_string});
769761 }
770762
771 fn writeFloat(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
763 fn writeFloat(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
772764 const number = self.code.instructions.items(.data)[@intFromEnum(inst)].float;
773765 try stream.print("{d})", .{number});
774766 }
775767
776 fn writeFloat128(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
768 fn writeFloat128(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
777769 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
778770 const extra = self.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data;
779771 const number = extra.get();
......@@ -784,15 +776,15 @@ const Writer = struct {
784776
785777 fn writeStr(
786778 self: *Writer,
787 stream: anytype,
779 stream: *std.io.Writer,
788780 inst: Zir.Inst.Index,
789 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
781 ) Error!void {
790782 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str;
791783 const str = inst_data.get(self.code);
792 try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
784 try stream.print("\"{f}\")", .{std.zig.fmtString(str)});
793785 }
794786
795 fn writeSliceStart(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
787 fn writeSliceStart(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
796788 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
797789 const extra = self.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data;
798790 try self.writeInstRef(stream, extra.lhs);
......@@ -802,7 +794,7 @@ const Writer = struct {
802794 try self.writeSrcNode(stream, inst_data.src_node);
803795 }
804796
805 fn writeSliceEnd(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
797 fn writeSliceEnd(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
806798 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
807799 const extra = self.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data;
808800 try self.writeInstRef(stream, extra.lhs);
......@@ -814,7 +806,7 @@ const Writer = struct {
814806 try self.writeSrcNode(stream, inst_data.src_node);
815807 }
816808
817 fn writeSliceSentinel(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
809 fn writeSliceSentinel(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
818810 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
819811 const extra = self.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data;
820812 try self.writeInstRef(stream, extra.lhs);
......@@ -828,7 +820,7 @@ const Writer = struct {
828820 try self.writeSrcNode(stream, inst_data.src_node);
829821 }
830822
831 fn writeSliceLength(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
823 fn writeSliceLength(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
832824 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
833825 const extra = self.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data;
834826 try self.writeInstRef(stream, extra.lhs);
......@@ -844,7 +836,7 @@ const Writer = struct {
844836 try self.writeSrcNode(stream, inst_data.src_node);
845837 }
846838
847 fn writeUnionInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
839 fn writeUnionInit(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
848840 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
849841 const extra = self.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
850842 try self.writeInstRef(stream, extra.union_type);
......@@ -856,7 +848,7 @@ const Writer = struct {
856848 try self.writeSrcNode(stream, inst_data.src_node);
857849 }
858850
859 fn writeShuffle(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
851 fn writeShuffle(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
860852 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
861853 const extra = self.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data;
862854 try self.writeInstRef(stream, extra.elem_type);
......@@ -870,7 +862,7 @@ const Writer = struct {
870862 try self.writeSrcNode(stream, inst_data.src_node);
871863 }
872864
873 fn writeSelect(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
865 fn writeSelect(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
874866 const extra = self.code.extraData(Zir.Inst.Select, extended.operand).data;
875867 try self.writeInstRef(stream, extra.elem_type);
876868 try stream.writeAll(", ");
......@@ -883,7 +875,7 @@ const Writer = struct {
883875 try self.writeSrcNode(stream, extra.node);
884876 }
885877
886 fn writeMulAdd(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
878 fn writeMulAdd(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
887879 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
888880 const extra = self.code.extraData(Zir.Inst.MulAdd, inst_data.payload_index).data;
889881 try self.writeInstRef(stream, extra.mulend1);
......@@ -895,7 +887,7 @@ const Writer = struct {
895887 try self.writeSrcNode(stream, inst_data.src_node);
896888 }
897889
898 fn writeBuiltinCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
890 fn writeBuiltinCall(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
899891 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
900892 const extra = self.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
901893
......@@ -911,7 +903,7 @@ const Writer = struct {
911903 try self.writeSrcNode(stream, inst_data.src_node);
912904 }
913905
914 fn writeFieldParentPtr(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
906 fn writeFieldParentPtr(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
915907 const extra = self.code.extraData(Zir.Inst.FieldParentPtr, extended.operand).data;
916908 const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
917909 const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
......@@ -928,12 +920,12 @@ const Writer = struct {
928920 try self.writeSrcNode(stream, extra.src_node);
929921 }
930922
931 fn writeParam(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
923 fn writeParam(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
932924 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
933925 const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index);
934926 const body = self.code.bodySlice(extra.end, extra.data.type.body_len);
935 try stream.print("\"{}\", ", .{
936 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)),
927 try stream.print("\"{f}\", ", .{
928 std.zig.fmtString(self.code.nullTerminatedString(extra.data.name)),
937929 });
938930
939931 if (extra.data.type.is_generic) try stream.writeAll("[generic] ");
......@@ -943,7 +935,7 @@ const Writer = struct {
943935 try self.writeSrcTok(stream, inst_data.src_tok);
944936 }
945937
946 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
938 fn writePlNodeBin(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
947939 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
948940 const extra = self.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
949941 try self.writeInstRef(stream, extra.lhs);
......@@ -953,7 +945,7 @@ const Writer = struct {
953945 try self.writeSrcNode(stream, inst_data.src_node);
954946 }
955947
956 fn writePlNodeMultiOp(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
948 fn writePlNodeMultiOp(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
957949 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
958950 const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
959951 const args = self.code.refSlice(extra.end, extra.data.operands_len);
......@@ -966,7 +958,7 @@ const Writer = struct {
966958 try self.writeSrcNode(stream, inst_data.src_node);
967959 }
968960
969 fn writeArrayMul(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
961 fn writeArrayMul(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
970962 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
971963 const extra = self.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data;
972964 try self.writeInstRef(stream, extra.res_ty);
......@@ -978,13 +970,13 @@ const Writer = struct {
978970 try self.writeSrcNode(stream, inst_data.src_node);
979971 }
980972
981 fn writeElemValImm(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
973 fn writeElemValImm(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
982974 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].elem_val_imm;
983975 try self.writeInstRef(stream, inst_data.operand);
984976 try stream.print(", {d})", .{inst_data.idx});
985977 }
986978
987 fn writeArrayInitElemPtr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
979 fn writeArrayInitElemPtr(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
988980 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
989981 const extra = self.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
990982
......@@ -993,7 +985,7 @@ const Writer = struct {
993985 try self.writeSrcNode(stream, inst_data.src_node);
994986 }
995987
996 fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
988 fn writePlNodeExport(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
997989 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
998990 const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
999991
......@@ -1004,7 +996,7 @@ const Writer = struct {
1004996 try self.writeSrcNode(stream, inst_data.src_node);
1005997 }
1006998
1007 fn writeValidateArrayInitRefTy(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
999 fn writeValidateArrayInitRefTy(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
10081000 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
10091001 const extra = self.code.extraData(Zir.Inst.ArrayInitRefTy, inst_data.payload_index).data;
10101002
......@@ -1014,7 +1006,7 @@ const Writer = struct {
10141006 try self.writeSrcNode(stream, inst_data.src_node);
10151007 }
10161008
1017 fn writeStructInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1009 fn writeStructInit(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
10181010 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
10191011 const extra = self.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
10201012 var field_i: u32 = 0;
......@@ -1038,7 +1030,7 @@ const Writer = struct {
10381030 try self.writeSrcNode(stream, inst_data.src_node);
10391031 }
10401032
1041 fn writeCmpxchg(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1033 fn writeCmpxchg(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
10421034 const extra = self.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data;
10431035
10441036 try self.writeInstRef(stream, extra.ptr);
......@@ -1054,7 +1046,7 @@ const Writer = struct {
10541046 try self.writeSrcNode(stream, extra.node);
10551047 }
10561048
1057 fn writePtrCastFull(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1049 fn writePtrCastFull(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
10581050 const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
10591051 const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
10601052 const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
......@@ -1070,7 +1062,7 @@ const Writer = struct {
10701062 try self.writeSrcNode(stream, extra.node);
10711063 }
10721064
1073 fn writePtrCastNoDest(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1065 fn writePtrCastNoDest(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
10741066 const FlagsInt = @typeInfo(Zir.Inst.FullPtrCastFlags).@"struct".backing_integer.?;
10751067 const flags: Zir.Inst.FullPtrCastFlags = @bitCast(@as(FlagsInt, @truncate(extended.small)));
10761068 const extra = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
......@@ -1081,7 +1073,7 @@ const Writer = struct {
10811073 try self.writeSrcNode(stream, extra.node);
10821074 }
10831075
1084 fn writeAtomicLoad(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1076 fn writeAtomicLoad(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
10851077 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
10861078 const extra = self.code.extraData(Zir.Inst.AtomicLoad, inst_data.payload_index).data;
10871079
......@@ -1094,7 +1086,7 @@ const Writer = struct {
10941086 try self.writeSrcNode(stream, inst_data.src_node);
10951087 }
10961088
1097 fn writeAtomicStore(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1089 fn writeAtomicStore(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
10981090 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
10991091 const extra = self.code.extraData(Zir.Inst.AtomicStore, inst_data.payload_index).data;
11001092
......@@ -1107,7 +1099,7 @@ const Writer = struct {
11071099 try self.writeSrcNode(stream, inst_data.src_node);
11081100 }
11091101
1110 fn writeAtomicRmw(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1102 fn writeAtomicRmw(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
11111103 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
11121104 const extra = self.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;
11131105
......@@ -1122,7 +1114,7 @@ const Writer = struct {
11221114 try self.writeSrcNode(stream, inst_data.src_node);
11231115 }
11241116
1125 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1117 fn writeStructInitAnon(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
11261118 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
11271119 const extra = self.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
11281120 var field_i: u32 = 0;
......@@ -1143,7 +1135,7 @@ const Writer = struct {
11431135 try self.writeSrcNode(stream, inst_data.src_node);
11441136 }
11451137
1146 fn writeStructInitFieldType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1138 fn writeStructInitFieldType(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
11471139 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
11481140 const extra = self.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
11491141 try self.writeInstRef(stream, extra.container_type);
......@@ -1152,7 +1144,7 @@ const Writer = struct {
11521144 try self.writeSrcNode(stream, inst_data.src_node);
11531145 }
11541146
1155 fn writeFieldTypeRef(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1147 fn writeFieldTypeRef(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
11561148 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
11571149 const extra = self.code.extraData(Zir.Inst.FieldTypeRef, inst_data.payload_index).data;
11581150 try self.writeInstRef(stream, extra.container_type);
......@@ -1162,7 +1154,7 @@ const Writer = struct {
11621154 try self.writeSrcNode(stream, inst_data.src_node);
11631155 }
11641156
1165 fn writeNodeMultiOp(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1157 fn writeNodeMultiOp(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
11661158 const extra = self.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
11671159 const operands = self.code.refSlice(extra.end, extended.small);
11681160
......@@ -1176,9 +1168,9 @@ const Writer = struct {
11761168
11771169 fn writeInstNode(
11781170 self: *Writer,
1179 stream: anytype,
1171 stream: *std.io.Writer,
11801172 inst: Zir.Inst.Index,
1181 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1173 ) Error!void {
11821174 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].inst_node;
11831175 try self.writeInstIndex(stream, inst_data.inst);
11841176 try stream.writeAll(") ");
......@@ -1187,7 +1179,7 @@ const Writer = struct {
11871179
11881180 fn writeAsm(
11891181 self: *Writer,
1190 stream: anytype,
1182 stream: *std.io.Writer,
11911183 extended: Zir.Inst.Extended.InstData,
11921184 tmpl_is_expr: bool,
11931185 ) !void {
......@@ -1203,7 +1195,7 @@ const Writer = struct {
12031195 try stream.writeAll(", ");
12041196 } else {
12051197 const asm_source = self.code.nullTerminatedString(extra.data.asm_source);
1206 try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)});
1198 try stream.print("\"{f}\", ", .{std.zig.fmtString(asm_source)});
12071199 }
12081200 try stream.writeAll(", ");
12091201
......@@ -1220,8 +1212,8 @@ const Writer = struct {
12201212
12211213 const name = self.code.nullTerminatedString(output.data.name);
12221214 const constraint = self.code.nullTerminatedString(output.data.constraint);
1223 try stream.print("output({p}, \"{}\", ", .{
1224 std.zig.fmtId(name), std.zig.fmtEscapes(constraint),
1215 try stream.print("output({f}, \"{f}\", ", .{
1216 std.zig.fmtIdP(name), std.zig.fmtString(constraint),
12251217 });
12261218 try self.writeFlag(stream, "->", is_type);
12271219 try self.writeInstRef(stream, output.data.operand);
......@@ -1239,8 +1231,8 @@ const Writer = struct {
12391231
12401232 const name = self.code.nullTerminatedString(input.data.name);
12411233 const constraint = self.code.nullTerminatedString(input.data.constraint);
1242 try stream.print("input({p}, \"{}\", ", .{
1243 std.zig.fmtId(name), std.zig.fmtEscapes(constraint),
1234 try stream.print("input({f}, \"{f}\", ", .{
1235 std.zig.fmtIdP(name), std.zig.fmtString(constraint),
12441236 });
12451237 try self.writeInstRef(stream, input.data.operand);
12461238 try stream.writeAll(")");
......@@ -1255,7 +1247,7 @@ const Writer = struct {
12551247 const str_index = self.code.extra[extra_i];
12561248 extra_i += 1;
12571249 const clobber = self.code.nullTerminatedString(@enumFromInt(str_index));
1258 try stream.print("{p}", .{std.zig.fmtId(clobber)});
1250 try stream.print("{f}", .{std.zig.fmtIdP(clobber)});
12591251 if (i + 1 < clobbers_len) {
12601252 try stream.writeAll(", ");
12611253 }
......@@ -1265,7 +1257,7 @@ const Writer = struct {
12651257 try self.writeSrcNode(stream, extra.data.src_node);
12661258 }
12671259
1268 fn writeOverflowArithmetic(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1260 fn writeOverflowArithmetic(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
12691261 const extra = self.code.extraData(Zir.Inst.BinNode, extended.operand).data;
12701262
12711263 try self.writeInstRef(stream, extra.lhs);
......@@ -1277,7 +1269,7 @@ const Writer = struct {
12771269
12781270 fn writeCall(
12791271 self: *Writer,
1280 stream: anytype,
1272 stream: *std.io.Writer,
12811273 inst: Zir.Inst.Index,
12821274 comptime kind: enum { direct, field },
12831275 ) !void {
......@@ -1299,7 +1291,7 @@ const Writer = struct {
12991291 .field => {
13001292 const field_name = self.code.nullTerminatedString(extra.data.field_name_start);
13011293 try self.writeInstRef(stream, extra.data.obj_ptr);
1302 try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)});
1294 try stream.print(", \"{f}\"", .{std.zig.fmtString(field_name)});
13031295 },
13041296 }
13051297 try stream.writeAll(", [");
......@@ -1311,7 +1303,7 @@ const Writer = struct {
13111303 var i: usize = 0;
13121304 var arg_start: u32 = args_len;
13131305 while (i < args_len) : (i += 1) {
1314 try stream.writeByteNTimes(' ', self.indent);
1306 try stream.splatByteAll(' ', self.indent);
13151307 const arg_end = self.code.extra[extra.end + i];
13161308 defer arg_start = arg_end;
13171309 const arg_body = body[arg_start..arg_end];
......@@ -1321,14 +1313,14 @@ const Writer = struct {
13211313 }
13221314 self.indent -= 2;
13231315 if (args_len != 0) {
1324 try stream.writeByteNTimes(' ', self.indent);
1316 try stream.splatByteAll(' ', self.indent);
13251317 }
13261318
13271319 try stream.writeAll("]) ");
13281320 try self.writeSrcNode(stream, inst_data.src_node);
13291321 }
13301322
1331 fn writeBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1323 fn writeBlock(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
13321324 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
13331325 const extra = self.code.extraData(Zir.Inst.Block, inst_data.payload_index);
13341326 const body = self.code.bodySlice(extra.end, extra.data.body_len);
......@@ -1337,7 +1329,7 @@ const Writer = struct {
13371329 try self.writeSrcNode(stream, inst_data.src_node);
13381330 }
13391331
1340 fn writeBlockComptime(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1332 fn writeBlockComptime(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
13411333 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
13421334 const extra = self.code.extraData(Zir.Inst.BlockComptime, inst_data.payload_index);
13431335 const body = self.code.bodySlice(extra.end, extra.data.body_len);
......@@ -1347,7 +1339,7 @@ const Writer = struct {
13471339 try self.writeSrcNode(stream, inst_data.src_node);
13481340 }
13491341
1350 fn writeCondBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1342 fn writeCondBr(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
13511343 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
13521344 const extra = self.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
13531345 const then_body = self.code.bodySlice(extra.end, extra.data.then_body_len);
......@@ -1361,7 +1353,7 @@ const Writer = struct {
13611353 try self.writeSrcNode(stream, inst_data.src_node);
13621354 }
13631355
1364 fn writeTry(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1356 fn writeTry(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
13651357 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
13661358 const extra = self.code.extraData(Zir.Inst.Try, inst_data.payload_index);
13671359 const body = self.code.bodySlice(extra.end, extra.data.body_len);
......@@ -1372,7 +1364,7 @@ const Writer = struct {
13721364 try self.writeSrcNode(stream, inst_data.src_node);
13731365 }
13741366
1375 fn writeStructDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1367 fn writeStructDecl(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
13761368 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
13771369
13781370 const extra = self.code.extraData(Zir.Inst.StructDecl, extended.operand);
......@@ -1388,7 +1380,7 @@ const Writer = struct {
13881380 extra.data.fields_hash_3,
13891381 });
13901382
1391 try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)});
1383 try stream.print("hash({x}) ", .{&fields_hash});
13921384
13931385 var extra_index: usize = extra.end;
13941386
......@@ -1446,7 +1438,7 @@ const Writer = struct {
14461438 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
14471439 self.indent -= 2;
14481440 extra_index += decls_len;
1449 try stream.writeByteNTimes(' ', self.indent);
1441 try stream.splatByteAll(' ', self.indent);
14501442 try stream.writeAll("}, ");
14511443 }
14521444
......@@ -1515,11 +1507,11 @@ const Writer = struct {
15151507 self.indent += 2;
15161508
15171509 for (fields, 0..) |field, i| {
1518 try stream.writeByteNTimes(' ', self.indent);
1510 try stream.splatByteAll(' ', self.indent);
15191511 try self.writeFlag(stream, "comptime ", field.is_comptime);
15201512 if (field.name != .empty) {
15211513 const field_name = self.code.nullTerminatedString(field.name);
1522 try stream.print("{p}: ", .{std.zig.fmtId(field_name)});
1514 try stream.print("{f}: ", .{std.zig.fmtIdP(field_name)});
15231515 } else {
15241516 try stream.print("@\"{d}\": ", .{i});
15251517 }
......@@ -1558,13 +1550,13 @@ const Writer = struct {
15581550 }
15591551
15601552 self.indent -= 2;
1561 try stream.writeByteNTimes(' ', self.indent);
1553 try stream.splatByteAll(' ', self.indent);
15621554 try stream.writeAll("}) ");
15631555 }
15641556 try self.writeSrcNode(stream, .zero);
15651557 }
15661558
1567 fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1559 fn writeUnionDecl(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
15681560 const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
15691561
15701562 const extra = self.code.extraData(Zir.Inst.UnionDecl, extended.operand);
......@@ -1580,7 +1572,7 @@ const Writer = struct {
15801572 extra.data.fields_hash_3,
15811573 });
15821574
1583 try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)});
1575 try stream.print("hash({x}) ", .{&fields_hash});
15841576
15851577 var extra_index: usize = extra.end;
15861578
......@@ -1630,7 +1622,7 @@ const Writer = struct {
16301622 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
16311623 self.indent -= 2;
16321624 extra_index += decls_len;
1633 try stream.writeByteNTimes(' ', self.indent);
1625 try stream.splatByteAll(' ', self.indent);
16341626 try stream.writeAll("}");
16351627 }
16361628
......@@ -1681,8 +1673,8 @@ const Writer = struct {
16811673 const field_name = self.code.nullTerminatedString(field_name_index);
16821674 extra_index += 1;
16831675
1684 try stream.writeByteNTimes(' ', self.indent);
1685 try stream.print("{p}", .{std.zig.fmtId(field_name)});
1676 try stream.splatByteAll(' ', self.indent);
1677 try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
16861678
16871679 if (has_type) {
16881680 const field_type = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
......@@ -1710,12 +1702,12 @@ const Writer = struct {
17101702 }
17111703
17121704 self.indent -= 2;
1713 try stream.writeByteNTimes(' ', self.indent);
1705 try stream.splatByteAll(' ', self.indent);
17141706 try stream.writeAll("}) ");
17151707 try self.writeSrcNode(stream, .zero);
17161708 }
17171709
1718 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1710 fn writeEnumDecl(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
17191711 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
17201712
17211713 const extra = self.code.extraData(Zir.Inst.EnumDecl, extended.operand);
......@@ -1731,7 +1723,7 @@ const Writer = struct {
17311723 extra.data.fields_hash_3,
17321724 });
17331725
1734 try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)});
1726 try stream.print("hash({x}) ", .{&fields_hash});
17351727
17361728 var extra_index: usize = extra.end;
17371729
......@@ -1779,7 +1771,7 @@ const Writer = struct {
17791771 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
17801772 self.indent -= 2;
17811773 extra_index += decls_len;
1782 try stream.writeByteNTimes(' ', self.indent);
1774 try stream.splatByteAll(' ', self.indent);
17831775 try stream.writeAll("}, ");
17841776 }
17851777
......@@ -1815,8 +1807,8 @@ const Writer = struct {
18151807 const field_name = self.code.nullTerminatedString(@enumFromInt(self.code.extra[extra_index]));
18161808 extra_index += 1;
18171809
1818 try stream.writeByteNTimes(' ', self.indent);
1819 try stream.print("{p}", .{std.zig.fmtId(field_name)});
1810 try stream.splatByteAll(' ', self.indent);
1811 try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
18201812
18211813 if (has_tag_value) {
18221814 const tag_value_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
......@@ -1828,7 +1820,7 @@ const Writer = struct {
18281820 try stream.writeAll(",\n");
18291821 }
18301822 self.indent -= 2;
1831 try stream.writeByteNTimes(' ', self.indent);
1823 try stream.splatByteAll(' ', self.indent);
18321824 try stream.writeAll("}) ");
18331825 }
18341826 try self.writeSrcNode(stream, .zero);
......@@ -1836,7 +1828,7 @@ const Writer = struct {
18361828
18371829 fn writeOpaqueDecl(
18381830 self: *Writer,
1839 stream: anytype,
1831 stream: *std.io.Writer,
18401832 extended: Zir.Inst.Extended.InstData,
18411833 ) !void {
18421834 const small = @as(Zir.Inst.OpaqueDecl.Small, @bitCast(extended.small));
......@@ -1872,13 +1864,13 @@ const Writer = struct {
18721864 self.indent += 2;
18731865 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
18741866 self.indent -= 2;
1875 try stream.writeByteNTimes(' ', self.indent);
1867 try stream.splatByteAll(' ', self.indent);
18761868 try stream.writeAll("}) ");
18771869 }
18781870 try self.writeSrcNode(stream, .zero);
18791871 }
18801872
1881 fn writeTupleDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1873 fn writeTupleDecl(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
18821874 const fields_len = extended.small;
18831875 assert(fields_len != 0);
18841876 const extra = self.code.extraData(Zir.Inst.TupleDecl, extended.operand);
......@@ -1906,7 +1898,7 @@ const Writer = struct {
19061898
19071899 fn writeErrorSetDecl(
19081900 self: *Writer,
1909 stream: anytype,
1901 stream: *std.io.Writer,
19101902 inst: Zir.Inst.Index,
19111903 ) !void {
19121904 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
......@@ -1920,18 +1912,18 @@ const Writer = struct {
19201912 while (extra_index < extra_index_end) : (extra_index += 1) {
19211913 const name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
19221914 const name = self.code.nullTerminatedString(name_index);
1923 try stream.writeByteNTimes(' ', self.indent);
1924 try stream.print("{p},\n", .{std.zig.fmtId(name)});
1915 try stream.splatByteAll(' ', self.indent);
1916 try stream.print("{f},\n", .{std.zig.fmtIdP(name)});
19251917 }
19261918
19271919 self.indent -= 2;
1928 try stream.writeByteNTimes(' ', self.indent);
1920 try stream.splatByteAll(' ', self.indent);
19291921 try stream.writeAll("}) ");
19301922
19311923 try self.writeSrcNode(stream, inst_data.src_node);
19321924 }
19331925
1934 fn writeSwitchBlockErrUnion(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1926 fn writeSwitchBlockErrUnion(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
19351927 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
19361928 const extra = self.code.extraData(Zir.Inst.SwitchBlockErrUnion, inst_data.payload_index);
19371929
......@@ -1967,7 +1959,7 @@ const Writer = struct {
19671959 extra_index += body.len;
19681960
19691961 try stream.writeAll(",\n");
1970 try stream.writeByteNTimes(' ', self.indent);
1962 try stream.splatByteAll(' ', self.indent);
19711963 try stream.writeAll("non_err => ");
19721964 try self.writeBracedBody(stream, body);
19731965 }
......@@ -1985,7 +1977,7 @@ const Writer = struct {
19851977 extra_index += body.len;
19861978
19871979 try stream.writeAll(",\n");
1988 try stream.writeByteNTimes(' ', self.indent);
1980 try stream.splatByteAll(' ', self.indent);
19891981 try stream.print("{s}{s}else => ", .{ capture_text, inline_text });
19901982 try self.writeBracedBody(stream, body);
19911983 }
......@@ -2002,7 +1994,7 @@ const Writer = struct {
20021994 extra_index += info.body_len;
20031995
20041996 try stream.writeAll(",\n");
2005 try stream.writeByteNTimes(' ', self.indent);
1997 try stream.splatByteAll(' ', self.indent);
20061998 switch (info.capture) {
20071999 .none => {},
20082000 .by_val => try stream.writeAll("by_val "),
......@@ -2027,7 +2019,7 @@ const Writer = struct {
20272019 extra_index += items_len;
20282020
20292021 try stream.writeAll(",\n");
2030 try stream.writeByteNTimes(' ', self.indent);
2022 try stream.splatByteAll(' ', self.indent);
20312023 switch (info.capture) {
20322024 .none => {},
20332025 .by_val => try stream.writeAll("by_val "),
......@@ -2068,7 +2060,7 @@ const Writer = struct {
20682060 try self.writeSrcNode(stream, inst_data.src_node);
20692061 }
20702062
2071 fn writeSwitchBlock(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2063 fn writeSwitchBlock(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
20722064 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
20732065 const extra = self.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
20742066
......@@ -2115,7 +2107,7 @@ const Writer = struct {
21152107 extra_index += body.len;
21162108
21172109 try stream.writeAll(",\n");
2118 try stream.writeByteNTimes(' ', self.indent);
2110 try stream.splatByteAll(' ', self.indent);
21192111 try stream.print("{s}{s}{s} => ", .{ capture_text, inline_text, prong_name });
21202112 try self.writeBracedBody(stream, body);
21212113 }
......@@ -2132,7 +2124,7 @@ const Writer = struct {
21322124 extra_index += info.body_len;
21332125
21342126 try stream.writeAll(",\n");
2135 try stream.writeByteNTimes(' ', self.indent);
2127 try stream.splatByteAll(' ', self.indent);
21362128 switch (info.capture) {
21372129 .none => {},
21382130 .by_val => try stream.writeAll("by_val "),
......@@ -2157,7 +2149,7 @@ const Writer = struct {
21572149 extra_index += items_len;
21582150
21592151 try stream.writeAll(",\n");
2160 try stream.writeByteNTimes(' ', self.indent);
2152 try stream.splatByteAll(' ', self.indent);
21612153 switch (info.capture) {
21622154 .none => {},
21632155 .by_val => try stream.writeAll("by_val "),
......@@ -2198,16 +2190,16 @@ const Writer = struct {
21982190 try self.writeSrcNode(stream, inst_data.src_node);
21992191 }
22002192
2201 fn writePlNodeField(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2193 fn writePlNodeField(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
22022194 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
22032195 const extra = self.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
22042196 const name = self.code.nullTerminatedString(extra.field_name_start);
22052197 try self.writeInstRef(stream, extra.lhs);
2206 try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)});
2198 try stream.print(", \"{f}\") ", .{std.zig.fmtString(name)});
22072199 try self.writeSrcNode(stream, inst_data.src_node);
22082200 }
22092201
2210 fn writePlNodeFieldNamed(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2202 fn writePlNodeFieldNamed(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
22112203 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
22122204 const extra = self.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
22132205 try self.writeInstRef(stream, extra.lhs);
......@@ -2217,7 +2209,7 @@ const Writer = struct {
22172209 try self.writeSrcNode(stream, inst_data.src_node);
22182210 }
22192211
2220 fn writeAs(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2212 fn writeAs(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
22212213 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
22222214 const extra = self.code.extraData(Zir.Inst.As, inst_data.payload_index).data;
22232215 try self.writeInstRef(stream, extra.dest_type);
......@@ -2229,9 +2221,9 @@ const Writer = struct {
22292221
22302222 fn writeNode(
22312223 self: *Writer,
2232 stream: anytype,
2224 stream: *std.io.Writer,
22332225 inst: Zir.Inst.Index,
2234 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2226 ) Error!void {
22352227 const src_node = self.code.instructions.items(.data)[@intFromEnum(inst)].node;
22362228 try stream.writeAll(") ");
22372229 try self.writeSrcNode(stream, src_node);
......@@ -2239,25 +2231,25 @@ const Writer = struct {
22392231
22402232 fn writeStrTok(
22412233 self: *Writer,
2242 stream: anytype,
2234 stream: *std.io.Writer,
22432235 inst: Zir.Inst.Index,
2244 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2236 ) Error!void {
22452237 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
22462238 const str = inst_data.get(self.code);
2247 try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)});
2239 try stream.print("\"{f}\") ", .{std.zig.fmtString(str)});
22482240 try self.writeSrcTok(stream, inst_data.src_tok);
22492241 }
22502242
2251 fn writeStrOp(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2243 fn writeStrOp(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
22522244 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_op;
22532245 const str = inst_data.getStr(self.code);
22542246 try self.writeInstRef(stream, inst_data.operand);
2255 try stream.print(", \"{}\")", .{std.zig.fmtEscapes(str)});
2247 try stream.print(", \"{f}\")", .{std.zig.fmtString(str)});
22562248 }
22572249
22582250 fn writeFunc(
22592251 self: *Writer,
2260 stream: anytype,
2252 stream: *std.io.Writer,
22612253 inst: Zir.Inst.Index,
22622254 inferred_error_set: bool,
22632255 ) !void {
......@@ -2308,7 +2300,7 @@ const Writer = struct {
23082300 );
23092301 }
23102302
2311 fn writeFuncFancy(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2303 fn writeFuncFancy(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
23122304 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
23132305 const extra = self.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
23142306
......@@ -2367,7 +2359,7 @@ const Writer = struct {
23672359 );
23682360 }
23692361
2370 fn writeAllocExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
2362 fn writeAllocExtended(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
23712363 const extra = self.code.extraData(Zir.Inst.AllocExtended, extended.operand);
23722364 const small = @as(Zir.Inst.AllocExtended.Small, @bitCast(extended.small));
23732365
......@@ -2390,7 +2382,7 @@ const Writer = struct {
23902382 try self.writeSrcNode(stream, extra.data.src_node);
23912383 }
23922384
2393 fn writeTypeofPeer(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
2385 fn writeTypeofPeer(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
23942386 const extra = self.code.extraData(Zir.Inst.TypeOfPeer, extended.operand);
23952387 const body = self.code.bodySlice(extra.data.body_index, extra.data.body_len);
23962388 try self.writeBracedBody(stream, body);
......@@ -2403,7 +2395,7 @@ const Writer = struct {
24032395 try stream.writeAll("])");
24042396 }
24052397
2406 fn writeBoolBr(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2398 fn writeBoolBr(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
24072399 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
24082400 const extra = self.code.extraData(Zir.Inst.BoolBr, inst_data.payload_index);
24092401 const body = self.code.bodySlice(extra.end, extra.data.body_len);
......@@ -2414,7 +2406,7 @@ const Writer = struct {
24142406 try self.writeSrcNode(stream, inst_data.src_node);
24152407 }
24162408
2417 fn writeIntType(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2409 fn writeIntType(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
24182410 const int_type = self.code.instructions.items(.data)[@intFromEnum(inst)].int_type;
24192411 const prefix: u8 = switch (int_type.signedness) {
24202412 .signed => 'i',
......@@ -2424,7 +2416,7 @@ const Writer = struct {
24242416 try self.writeSrcNode(stream, int_type.src_node);
24252417 }
24262418
2427 fn writeSaveErrRetIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2419 fn writeSaveErrRetIndex(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
24282420 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].save_err_ret_index;
24292421
24302422 try self.writeInstRef(stream, inst_data.operand);
......@@ -2432,7 +2424,7 @@ const Writer = struct {
24322424 try stream.writeAll(")");
24332425 }
24342426
2435 fn writeRestoreErrRetIndex(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
2427 fn writeRestoreErrRetIndex(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
24362428 const extra = self.code.extraData(Zir.Inst.RestoreErrRetIndex, extended.operand).data;
24372429
24382430 try self.writeInstRef(stream, extra.block);
......@@ -2442,7 +2434,7 @@ const Writer = struct {
24422434 try self.writeSrcNode(stream, extra.src_node);
24432435 }
24442436
2445 fn writeBreak(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2437 fn writeBreak(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
24462438 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"break";
24472439 const extra = self.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
24482440
......@@ -2452,7 +2444,7 @@ const Writer = struct {
24522444 try stream.writeAll(")");
24532445 }
24542446
2455 fn writeArrayInit(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2447 fn writeArrayInit(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
24562448 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
24572449
24582450 const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
......@@ -2468,7 +2460,7 @@ const Writer = struct {
24682460 try self.writeSrcNode(stream, inst_data.src_node);
24692461 }
24702462
2471 fn writeArrayInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2463 fn writeArrayInitAnon(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
24722464 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
24732465
24742466 const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
......@@ -2483,7 +2475,7 @@ const Writer = struct {
24832475 try self.writeSrcNode(stream, inst_data.src_node);
24842476 }
24852477
2486 fn writeArrayInitSent(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2478 fn writeArrayInitSent(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
24872479 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
24882480
24892481 const extra = self.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
......@@ -2503,7 +2495,7 @@ const Writer = struct {
25032495 try self.writeSrcNode(stream, inst_data.src_node);
25042496 }
25052497
2506 fn writeUnreachable(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2498 fn writeUnreachable(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
25072499 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"unreachable";
25082500 try stream.writeAll(") ");
25092501 try self.writeSrcNode(stream, inst_data.src_node);
......@@ -2511,7 +2503,7 @@ const Writer = struct {
25112503
25122504 fn writeFuncCommon(
25132505 self: *Writer,
2514 stream: anytype,
2506 stream: *std.io.Writer,
25152507 inferred_error_set: bool,
25162508 var_args: bool,
25172509 is_noinline: bool,
......@@ -2548,19 +2540,19 @@ const Writer = struct {
25482540 try self.writeSrcNode(stream, src_node);
25492541 }
25502542
2551 fn writeDbgStmt(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2543 fn writeDbgStmt(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
25522544 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
25532545 try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });
25542546 }
25552547
2556 fn writeDefer(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2548 fn writeDefer(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
25572549 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].@"defer";
25582550 const body = self.code.bodySlice(inst_data.index, inst_data.len);
25592551 try self.writeBracedBody(stream, body);
25602552 try stream.writeByte(')');
25612553 }
25622554
2563 fn writeDeferErrCode(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2555 fn writeDeferErrCode(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
25642556 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].defer_err_code;
25652557 const extra = self.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
25662558
......@@ -2573,7 +2565,7 @@ const Writer = struct {
25732565 try stream.writeByte(')');
25742566 }
25752567
2576 fn writeDeclaration(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2568 fn writeDeclaration(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
25772569 const decl = self.code.getDeclaration(inst);
25782570
25792571 const prev_parent_decl_node = self.parent_decl_node;
......@@ -2594,10 +2586,8 @@ const Writer = struct {
25942586 },
25952587 }
25962588 const src_hash = self.code.getAssociatedSrcHash(inst).?;
2597 try stream.print(" line({d}) column({d}) hash({})", .{
2598 decl.src_line,
2599 decl.src_column,
2600 std.fmt.fmtSliceHexLower(&src_hash),
2589 try stream.print(" line({d}) column({d}) hash({x})", .{
2590 decl.src_line, decl.src_column, &src_hash,
26012591 });
26022592
26032593 {
......@@ -2631,26 +2621,26 @@ const Writer = struct {
26312621 try self.writeSrcNode(stream, .zero);
26322622 }
26332623
2634 fn writeClosureGet(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
2624 fn writeClosureGet(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
26352625 try stream.print("{d})) ", .{extended.small});
26362626 const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
26372627 try self.writeSrcNode(stream, src_node);
26382628 }
26392629
2640 fn writeBuiltinValue(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
2630 fn writeBuiltinValue(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
26412631 const val: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);
26422632 try stream.print("{s})) ", .{@tagName(val)});
26432633 const src_node: Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand)));
26442634 try self.writeSrcNode(stream, src_node);
26452635 }
26462636
2647 fn writeInplaceArithResultTy(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
2637 fn writeInplaceArithResultTy(self: *Writer, stream: *std.io.Writer, extended: Zir.Inst.Extended.InstData) !void {
26482638 const op: Zir.Inst.InplaceOp = @enumFromInt(extended.small);
26492639 try self.writeInstRef(stream, @enumFromInt(extended.operand));
26502640 try stream.print(", {s}))", .{@tagName(op)});
26512641 }
26522642
2653 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
2643 fn writeInstRef(self: *Writer, stream: *std.io.Writer, ref: Zir.Inst.Ref) !void {
26542644 if (ref == .none) {
26552645 return stream.writeAll(".none");
26562646 } else if (ref.toIndex()) |i| {
......@@ -2661,12 +2651,12 @@ const Writer = struct {
26612651 }
26622652 }
26632653
2664 fn writeInstIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2654 fn writeInstIndex(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
26652655 _ = self;
26662656 return stream.print("%{d}", .{@intFromEnum(inst)});
26672657 }
26682658
2669 fn writeCaptures(self: *Writer, stream: anytype, extra_index: usize, captures_len: u32) !usize {
2659 fn writeCaptures(self: *Writer, stream: *std.io.Writer, extra_index: usize, captures_len: u32) !usize {
26702660 if (captures_len == 0) {
26712661 try stream.writeAll("{}");
26722662 return extra_index;
......@@ -2686,7 +2676,7 @@ const Writer = struct {
26862676 return extra_index + 2 * captures_len;
26872677 }
26882678
2689 fn writeCapture(self: *Writer, stream: anytype, capture: Zir.Inst.Capture) !void {
2679 fn writeCapture(self: *Writer, stream: *std.io.Writer, capture: Zir.Inst.Capture) !void {
26902680 switch (capture.unwrap()) {
26912681 .nested => |i| return stream.print("[{d}]", .{i}),
26922682 .instruction => |inst| return self.writeInstIndex(stream, inst),
......@@ -2694,18 +2684,18 @@ const Writer = struct {
26942684 try stream.writeAll("load ");
26952685 try self.writeInstIndex(stream, ptr_inst);
26962686 },
2697 .decl_val => |str| try stream.print("decl_val \"{}\"", .{
2698 std.zig.fmtEscapes(self.code.nullTerminatedString(str)),
2687 .decl_val => |str| try stream.print("decl_val \"{f}\"", .{
2688 std.zig.fmtString(self.code.nullTerminatedString(str)),
26992689 }),
2700 .decl_ref => |str| try stream.print("decl_ref \"{}\"", .{
2701 std.zig.fmtEscapes(self.code.nullTerminatedString(str)),
2690 .decl_ref => |str| try stream.print("decl_ref \"{f}\"", .{
2691 std.zig.fmtString(self.code.nullTerminatedString(str)),
27022692 }),
27032693 }
27042694 }
27052695
27062696 fn writeOptionalInstRef(
27072697 self: *Writer,
2708 stream: anytype,
2698 stream: *std.io.Writer,
27092699 prefix: []const u8,
27102700 inst: Zir.Inst.Ref,
27112701 ) !void {
......@@ -2716,7 +2706,7 @@ const Writer = struct {
27162706
27172707 fn writeOptionalInstRefOrBody(
27182708 self: *Writer,
2719 stream: anytype,
2709 stream: *std.io.Writer,
27202710 prefix: []const u8,
27212711 ref: Zir.Inst.Ref,
27222712 body: []const Zir.Inst.Index,
......@@ -2734,7 +2724,7 @@ const Writer = struct {
27342724
27352725 fn writeFlag(
27362726 self: *Writer,
2737 stream: anytype,
2727 stream: *std.io.Writer,
27382728 name: []const u8,
27392729 flag: bool,
27402730 ) !void {
......@@ -2743,7 +2733,7 @@ const Writer = struct {
27432733 try stream.writeAll(name);
27442734 }
27452735
2746 fn writeSrcNode(self: *Writer, stream: anytype, src_node: Ast.Node.Offset) !void {
2736 fn writeSrcNode(self: *Writer, stream: *std.io.Writer, src_node: Ast.Node.Offset) !void {
27472737 const tree = self.tree orelse return;
27482738 const abs_node = src_node.toAbsolute(self.parent_decl_node);
27492739 const src_span = tree.nodeToSpan(abs_node);
......@@ -2755,7 +2745,7 @@ const Writer = struct {
27552745 });
27562746 }
27572747
2758 fn writeSrcTok(self: *Writer, stream: anytype, src_tok: Ast.TokenOffset) !void {
2748 fn writeSrcTok(self: *Writer, stream: *std.io.Writer, src_tok: Ast.TokenOffset) !void {
27592749 const tree = self.tree orelse return;
27602750 const abs_tok = src_tok.toAbsolute(tree.firstToken(self.parent_decl_node));
27612751 const span_start = tree.tokenStart(abs_tok);
......@@ -2768,7 +2758,7 @@ const Writer = struct {
27682758 });
27692759 }
27702760
2771 fn writeSrcTokAbs(self: *Writer, stream: anytype, src_tok: Ast.TokenIndex) !void {
2761 fn writeSrcTokAbs(self: *Writer, stream: *std.io.Writer, src_tok: Ast.TokenIndex) !void {
27722762 const tree = self.tree orelse return;
27732763 const span_start = tree.tokenStart(src_tok);
27742764 const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(src_tok).len));
......@@ -2780,15 +2770,15 @@ const Writer = struct {
27802770 });
27812771 }
27822772
2783 fn writeBracedDecl(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void {
2773 fn writeBracedDecl(self: *Writer, stream: *std.io.Writer, body: []const Zir.Inst.Index) !void {
27842774 try self.writeBracedBodyConditional(stream, body, self.recurse_decls);
27852775 }
27862776
2787 fn writeBracedBody(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void {
2777 fn writeBracedBody(self: *Writer, stream: *std.io.Writer, body: []const Zir.Inst.Index) !void {
27882778 try self.writeBracedBodyConditional(stream, body, self.recurse_blocks);
27892779 }
27902780
2791 fn writeBracedBodyConditional(self: *Writer, stream: anytype, body: []const Zir.Inst.Index, enabled: bool) !void {
2781 fn writeBracedBodyConditional(self: *Writer, stream: *std.io.Writer, body: []const Zir.Inst.Index, enabled: bool) !void {
27922782 if (body.len == 0) {
27932783 try stream.writeAll("{}");
27942784 } else if (enabled) {
......@@ -2796,7 +2786,7 @@ const Writer = struct {
27962786 self.indent += 2;
27972787 try self.writeBody(stream, body);
27982788 self.indent -= 2;
2799 try stream.writeByteNTimes(' ', self.indent);
2789 try stream.splatByteAll(' ', self.indent);
28002790 try stream.writeAll("}");
28012791 } else if (body.len == 1) {
28022792 try stream.writeByte('{');
......@@ -2817,21 +2807,21 @@ const Writer = struct {
28172807 }
28182808 }
28192809
2820 fn writeBody(self: *Writer, stream: anytype, body: []const Zir.Inst.Index) !void {
2810 fn writeBody(self: *Writer, stream: *std.io.Writer, body: []const Zir.Inst.Index) !void {
28212811 for (body) |inst| {
2822 try stream.writeByteNTimes(' ', self.indent);
2812 try stream.splatByteAll(' ', self.indent);
28232813 try stream.print("%{d} ", .{@intFromEnum(inst)});
28242814 try self.writeInstToStream(stream, inst);
28252815 try stream.writeByte('\n');
28262816 }
28272817 }
28282818
2829 fn writeImport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2819 fn writeImport(self: *Writer, stream: *std.io.Writer, inst: Zir.Inst.Index) !void {
28302820 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
28312821 const extra = self.code.extraData(Zir.Inst.Import, inst_data.payload_index).data;
28322822 try self.writeInstRef(stream, extra.res_ty);
28332823 const import_path = self.code.nullTerminatedString(extra.path);
2834 try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(import_path)});
2824 try stream.print(", \"{f}\") ", .{std.zig.fmtString(import_path)});
28352825 try self.writeSrcTok(stream, inst_data.src_tok);
28362826 }
28372827};
src/print_zoir.zig+22-28
......@@ -1,13 +1,8 @@
1pub fn renderToFile(zoir: Zoir, arena: Allocator, f: std.fs.File) (std.fs.File.WriteError || Allocator.Error)!void {
2 var bw = std.io.bufferedWriter(f.writer());
3 try renderToWriter(zoir, arena, bw.writer());
4 try bw.flush();
5}
1pub const Error = error{ WriteFailed, OutOfMemory };
62
7pub fn renderToWriter(zoir: Zoir, arena: Allocator, w: anytype) (@TypeOf(w).Error || Allocator.Error)!void {
3pub fn renderToWriter(zoir: Zoir, arena: Allocator, w: *Writer) Error!void {
84 assert(!zoir.hasCompileErrors());
95
10 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
116 const bytes_per_node = comptime n: {
127 var n: usize = 0;
138 for (@typeInfo(Zoir.Node.Repr).@"struct".fields) |f| {
......@@ -23,42 +18,42 @@ pub fn renderToWriter(zoir: Zoir, arena: Allocator, w: anytype) (@TypeOf(w).Erro
2318
2419 // zig fmt: off
2520 try w.print(
26 \\# Nodes: {} ({})
27 \\# Extra Data Items: {} ({})
28 \\# BigInt Limbs: {} ({})
29 \\# String Table Bytes: {}
30 \\# Total ZON Bytes: {}
21 \\# Nodes: {} ({Bi})
22 \\# Extra Data Items: {} ({Bi})
23 \\# BigInt Limbs: {} ({Bi})
24 \\# String Table Bytes: {Bi}
25 \\# Total ZON Bytes: {Bi}
3126 \\
3227 , .{
33 zoir.nodes.len, fmtIntSizeBin(node_bytes),
34 zoir.extra.len, fmtIntSizeBin(extra_bytes),
35 zoir.limbs.len, fmtIntSizeBin(limb_bytes),
36 fmtIntSizeBin(string_bytes),
37 fmtIntSizeBin(node_bytes + extra_bytes + limb_bytes + string_bytes),
28 zoir.nodes.len, node_bytes,
29 zoir.extra.len, extra_bytes,
30 zoir.limbs.len, limb_bytes,
31 string_bytes,
32 node_bytes + extra_bytes + limb_bytes + string_bytes,
3833 });
3934 // zig fmt: on
4035 var pz: PrintZon = .{
41 .w = w.any(),
36 .w = w,
4237 .arena = arena,
4338 .zoir = zoir,
4439 .indent = 0,
4540 };
4641
47 return @errorCast(pz.renderRoot());
42 return pz.renderRoot();
4843}
4944
5045const PrintZon = struct {
51 w: std.io.AnyWriter,
46 w: *Writer,
5247 arena: Allocator,
5348 zoir: Zoir,
5449 indent: u32,
5550
56 fn renderRoot(pz: *PrintZon) anyerror!void {
51 fn renderRoot(pz: *PrintZon) Error!void {
5752 try pz.renderNode(.root);
5853 try pz.w.writeByte('\n');
5954 }
6055
61 fn renderNode(pz: *PrintZon, node: Zoir.Node.Index) anyerror!void {
56 fn renderNode(pz: *PrintZon, node: Zoir.Node.Index) Error!void {
6257 const zoir = pz.zoir;
6358 try pz.w.print("%{d} = ", .{@intFromEnum(node)});
6459 switch (node.get(zoir)) {
......@@ -77,8 +72,8 @@ const PrintZon = struct {
7772 },
7873 .float_literal => |x| try pz.w.print("float({d})", .{x}),
7974 .char_literal => |x| try pz.w.print("char({d})", .{x}),
80 .enum_literal => |x| try pz.w.print("enum_literal({p})", .{std.zig.fmtId(x.get(zoir))}),
81 .string_literal => |x| try pz.w.print("str(\"{}\")", .{std.zig.fmtEscapes(x)}),
75 .enum_literal => |x| try pz.w.print("enum_literal({f})", .{std.zig.fmtIdP(x.get(zoir))}),
76 .string_literal => |x| try pz.w.print("str(\"{f}\")", .{std.zig.fmtString(x)}),
8277 .empty_literal => try pz.w.writeAll("empty_literal(.{})"),
8378 .array_literal => |vals| {
8479 try pz.w.writeAll("array_literal({");
......@@ -97,7 +92,7 @@ const PrintZon = struct {
9792 pz.indent += 1;
9893 for (s.names, 0..s.vals.len) |name, idx| {
9994 try pz.newline();
100 try pz.w.print("[{p}] ", .{std.zig.fmtId(name.get(zoir))});
95 try pz.w.print("[{f}] ", .{std.zig.fmtIdP(name.get(zoir))});
10196 try pz.renderNode(s.vals.at(@intCast(idx)));
10297 try pz.w.writeByte(',');
10398 }
......@@ -110,9 +105,7 @@ const PrintZon = struct {
110105
111106 fn newline(pz: *PrintZon) !void {
112107 try pz.w.writeByte('\n');
113 for (0..pz.indent) |_| {
114 try pz.w.writeByteNTimes(' ', 2);
115 }
108 try pz.w.splatByteAll(' ', 2 * pz.indent);
116109 }
117110};
118111
......@@ -120,3 +113,4 @@ const std = @import("std");
120113const assert = std.debug.assert;
121114const Allocator = std.mem.Allocator;
122115const Zoir = std.zig.Zoir;
116const Writer = std.io.Writer;
src/register_manager.zig+3-3
......@@ -238,7 +238,7 @@ pub fn RegisterManager(
238238 if (i < count) return null;
239239
240240 for (regs, insts) |reg, inst| {
241 log.debug("tryAllocReg {} for inst {?}", .{ reg, inst });
241 log.debug("tryAllocReg {} for inst {?f}", .{ reg, inst });
242242 self.markRegAllocated(reg);
243243
244244 if (inst) |tracked_inst| {
......@@ -317,7 +317,7 @@ pub fn RegisterManager(
317317 tracked_index: TrackedIndex,
318318 inst: ?Air.Inst.Index,
319319 ) AllocationError!void {
320 log.debug("getReg {} for inst {?}", .{ regAtTrackedIndex(tracked_index), inst });
320 log.debug("getReg {} for inst {?f}", .{ regAtTrackedIndex(tracked_index), inst });
321321 if (!self.isRegIndexFree(tracked_index)) {
322322 // Move the instruction that was previously there to a
323323 // stack allocation.
......@@ -349,7 +349,7 @@ pub fn RegisterManager(
349349 tracked_index: TrackedIndex,
350350 inst: ?Air.Inst.Index,
351351 ) void {
352 log.debug("getRegAssumeFree {} for inst {?}", .{ regAtTrackedIndex(tracked_index), inst });
352 log.debug("getRegAssumeFree {} for inst {?f}", .{ regAtTrackedIndex(tracked_index), inst });
353353 self.markRegIndexAllocated(tracked_index);
354354
355355 assert(self.isRegIndexFree(tracked_index));
src/translate_c.zig+11-11
......@@ -357,7 +357,7 @@ fn transFileScopeAsm(c: *Context, scope: *Scope, file_scope_asm: *const clang.Fi
357357 var len: usize = undefined;
358358 const bytes_ptr = asm_string.getString_bytes_begin_size(&len);
359359
360 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
360 const str = try std.fmt.allocPrint(c.arena, "\"{f}\"", .{std.zig.fmtString(bytes_ptr[0..len])});
361361 const str_node = try Tag.string_literal.create(c.arena, str);
362362
363363 const asm_node = try Tag.asm_simple.create(c.arena, str_node);
......@@ -2276,7 +2276,7 @@ fn transNarrowStringLiteral(
22762276 var len: usize = undefined;
22772277 const bytes_ptr = stmt.getString_bytes_begin_size(&len);
22782278
2279 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
2279 const str = try std.fmt.allocPrint(c.arena, "\"{f}\"", .{std.zig.fmtString(bytes_ptr[0..len])});
22802280 const node = try Tag.string_literal.create(c.arena, str);
22812281 return maybeSuppressResult(c, result_used, node);
22822282}
......@@ -3338,7 +3338,7 @@ fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.Predefined
33383338
33393339fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node {
33403340 return Tag.char_literal.create(c.arena, if (narrow)
3341 try std.fmt.allocPrint(c.arena, "'{'}'", .{std.zig.fmtEscapes(&.{@as(u8, @intCast(val))})})
3341 try std.fmt.allocPrint(c.arena, "'{f}'", .{std.zig.fmtChar(&.{@as(u8, @intCast(val))})})
33423342 else
33433343 try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val}));
33443344}
......@@ -5832,7 +5832,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58325832 num += c - 'A' + 10;
58335833 },
58345834 else => {
5835 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
5835 i += std.fmt.printInt(bytes[i..], num, 16, .lower, .{ .fill = '0', .width = 2 });
58365836 num = 0;
58375837 if (c == '\\')
58385838 state = .escape
......@@ -5858,7 +5858,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58585858 };
58595859 num += c - '0';
58605860 } else {
5861 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
5861 i += std.fmt.printInt(bytes[i..], num, 16, .lower, .{ .fill = '0', .width = 2 });
58625862 num = 0;
58635863 count = 0;
58645864 if (c == '\\')
......@@ -5872,21 +5872,21 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58725872 }
58735873 }
58745874 if (state == .hex or state == .octal)
5875 i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
5875 i += std.fmt.printInt(bytes[i..], num, 16, .lower, .{ .fill = '0', .width = 2 });
58765876 return bytes[0..i];
58775877}
58785878
5879/// non-ASCII characters (c > 127) are also treated as non-printable by fmtSliceEscapeLower.
5879/// non-ASCII characters (c > 127) are also treated as non-printable by ascii.hexEscape.
58805880/// If a C string literal or char literal in a macro is not valid UTF-8, we need to escape
58815881/// non-ASCII characters so that the Zig source we output will itself be UTF-8.
58825882fn escapeUnprintables(ctx: *Context, m: *MacroCtx) ![]const u8 {
58835883 const zigified = try zigifyEscapeSequences(ctx, m);
58845884 if (std.unicode.utf8ValidateSlice(zigified)) return zigified;
58855885
5886 const formatter = std.fmt.fmtSliceEscapeLower(zigified);
5887 const encoded_size = @as(usize, @intCast(std.fmt.count("{s}", .{formatter})));
5886 const formatter = std.ascii.hexEscape(zigified, .lower);
5887 const encoded_size: usize = @intCast(std.fmt.count("{f}", .{formatter}));
58885888 const output = try ctx.arena.alloc(u8, encoded_size);
5889 return std.fmt.bufPrint(output, "{s}", .{formatter}) catch |err| switch (err) {
5889 return std.fmt.bufPrint(output, "{f}", .{formatter}) catch |err| switch (err) {
58905890 error.NoSpaceLeft => unreachable,
58915891 else => |e| return e,
58925892 };
......@@ -5905,7 +5905,7 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
59055905 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
59065906 return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m));
59075907 } else {
5908 const str = try std.fmt.allocPrint(c.arena, "0x{s}", .{std.fmt.fmtSliceHexLower(slice[1 .. slice.len - 1])});
5908 const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]});
59095909 return Tag.integer_literal.create(c.arena, str);
59105910 }
59115911 },
stage1/wasi.c+18-6
......@@ -520,12 +520,15 @@ uint32_t wasi_snapshot_preview1_fd_read(uint32_t fd, uint32_t iovs, uint32_t iov
520520 default: panic("unimplemented: fd_read special file");
521521 }
522522
523 if (fds[fd].stream == NULL) {
524 store32_align2(res_size_ptr, 0);
525 return wasi_errno_success;
526 }
527
523528 size_t size = 0;
524529 for (uint32_t i = 0; i < iovs_len; i += 1) {
525530 uint32_t len = load32_align2(&iovs_ptr[i].len);
526 size_t read_size = 0;
527 if (fds[fd].stream != NULL)
528 read_size = fread(&m[load32_align2(&iovs_ptr[i].ptr)], 1, len, fds[fd].stream);
531 size_t read_size = fread(&m[load32_align2(&iovs_ptr[i].ptr)], 1, len, fds[fd].stream);
529532 size += read_size;
530533 if (read_size < len) break;
531534 }
......@@ -633,8 +636,10 @@ uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t i
633636 }
634637
635638 fpos_t pos;
636 if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
637 if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
639 if (fds[fd].stream != NULL) {
640 if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
641 if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
642 }
638643
639644 size_t size = 0;
640645 for (uint32_t i = 0; i < iovs_len; i += 1) {
......@@ -648,7 +653,9 @@ uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t i
648653 if (written_size < len) break;
649654 }
650655
651 if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
656 if (fds[fd].stream != NULL) {
657 if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
658 }
652659
653660 if (size > 0) {
654661 time_t now = time(NULL);
......@@ -964,6 +971,11 @@ uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t io
964971 default: panic("unimplemented: fd_pread special file");
965972 }
966973
974 if (fds[fd].stream == NULL) {
975 store32_align2(res_size_ptr, 0);
976 return wasi_errno_success;
977 }
978
967979 fpos_t pos;
968980 if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
969981 if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
test/behavior/error.zig-18
......@@ -1032,24 +1032,6 @@ test "function called at runtime is properly analyzed for inferred error set" {
10321032 };
10331033}
10341034
1035test "generic type constructed from inferred error set of unresolved function" {
1036 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1037 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1038 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1039
1040 const S = struct {
1041 fn write(_: void, bytes: []const u8) !usize {
1042 _ = bytes;
1043 return 0;
1044 }
1045 const T = std.io.Writer(void, @typeInfo(@typeInfo(@TypeOf(write)).@"fn".return_type.?).error_union.error_set, write);
1046 fn writer() T {
1047 return .{ .context = {} };
1048 }
1049 };
1050 _ = std.io.multiWriter(.{S.writer()});
1051}
1052
10531035test "errorCast to adhoc inferred error set" {
10541036 const S = struct {
10551037 inline fn baz() !i32 {
test/behavior/union_with_members.zig+2-2
......@@ -10,8 +10,8 @@ const ET = union(enum) {
1010
1111 pub fn print(a: *const ET, buf: []u8) anyerror!usize {
1212 return switch (a.*) {
13 ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}),
14 ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}),
13 ET.SINT => |x| fmt.printInt(buf, x, 10, .lower, fmt.FormatOptions{}),
14 ET.UINT => |x| fmt.printInt(buf, x, 10, .lower, fmt.FormatOptions{}),
1515 };
1616 }
1717};
test/cases/safety/slice sentinel mismatch - floats.zig +1-1
......@@ -2,7 +2,7 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 1.2e0, found 4e0")) {
5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 1.2, found 4")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
test/compare_output.zig+3-286
......@@ -17,15 +17,6 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
1717 \\}
1818 , "Hello, world!" ++ if (@import("builtin").os.tag == .windows) "\r\n" else "\n");
1919
20 cases.add("hello world without libc",
21 \\const io = @import("std").io;
22 \\
23 \\pub fn main() void {
24 \\ const stdout = io.getStdOut().writer();
25 \\ stdout.print("Hello, world!\n{d:4} {x:3} {c}\n", .{@as(u32, 12), @as(u16, 0x12), @as(u8, 'a')}) catch unreachable;
26 \\}
27 , "Hello, world!\n 12 12 a\n");
28
2920 cases.addC("number literals",
3021 \\const std = @import("std");
3122 \\const builtin = @import("builtin");
......@@ -158,24 +149,6 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
158149 \\
159150 );
160151
161 cases.add("order-independent declarations",
162 \\const io = @import("std").io;
163 \\const z = io.stdin_fileno;
164 \\const x : @TypeOf(y) = 1234;
165 \\const y : u16 = 5678;
166 \\pub fn main() void {
167 \\ var x_local : i32 = print_ok(x);
168 \\ _ = &x_local;
169 \\}
170 \\fn print_ok(val: @TypeOf(x)) @TypeOf(foo) {
171 \\ _ = val;
172 \\ const stdout = io.getStdOut().writer();
173 \\ stdout.print("OK\n", .{}) catch unreachable;
174 \\ return 0;
175 \\}
176 \\const foo : i32 = 0;
177 , "OK\n");
178
179152 cases.addC("expose function pointer to C land",
180153 \\const c = @cImport(@cInclude("stdlib.h"));
181154 \\
......@@ -236,267 +209,11 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
236209 \\}
237210 , "3.25\n3\n3.00\n-0.40\n");
238211
239 cases.add("same named methods in incomplete struct",
240 \\const io = @import("std").io;
241 \\
242 \\const Foo = struct {
243 \\ field1: Bar,
244 \\
245 \\ fn method(a: *const Foo) bool {
246 \\ _ = a;
247 \\ return true;
248 \\ }
249 \\};
250 \\
251 \\const Bar = struct {
252 \\ field2: i32,
253 \\
254 \\ fn method(b: *const Bar) bool {
255 \\ _ = b;
256 \\ return true;
257 \\ }
258 \\};
259 \\
260 \\pub fn main() void {
261 \\ const bar = Bar {.field2 = 13,};
262 \\ const foo = Foo {.field1 = bar,};
263 \\ const stdout = io.getStdOut().writer();
264 \\ if (!foo.method()) {
265 \\ stdout.print("BAD\n", .{}) catch unreachable;
266 \\ }
267 \\ if (!bar.method()) {
268 \\ stdout.print("BAD\n", .{}) catch unreachable;
269 \\ }
270 \\ stdout.print("OK\n", .{}) catch unreachable;
271 \\}
272 , "OK\n");
273
274 cases.add("defer with only fallthrough",
275 \\const io = @import("std").io;
276 \\pub fn main() void {
277 \\ const stdout = io.getStdOut().writer();
278 \\ stdout.print("before\n", .{}) catch unreachable;
279 \\ defer stdout.print("defer1\n", .{}) catch unreachable;
280 \\ defer stdout.print("defer2\n", .{}) catch unreachable;
281 \\ defer stdout.print("defer3\n", .{}) catch unreachable;
282 \\ stdout.print("after\n", .{}) catch unreachable;
283 \\}
284 , "before\nafter\ndefer3\ndefer2\ndefer1\n");
285
286 cases.add("defer with return",
287 \\const io = @import("std").io;
288 \\const os = @import("std").os;
289 \\pub fn main() void {
290 \\ const stdout = io.getStdOut().writer();
291 \\ stdout.print("before\n", .{}) catch unreachable;
292 \\ defer stdout.print("defer1\n", .{}) catch unreachable;
293 \\ defer stdout.print("defer2\n", .{}) catch unreachable;
294 \\ var gpa: @import("std").heap.GeneralPurposeAllocator(.{}) = .init;
295 \\ defer _ = gpa.deinit();
296 \\ var arena = @import("std").heap.ArenaAllocator.init(gpa.allocator());
297 \\ defer arena.deinit();
298 \\ var args_it = @import("std").process.argsWithAllocator(arena.allocator()) catch unreachable;
299 \\ if (args_it.skip() and !args_it.skip()) return;
300 \\ defer stdout.print("defer3\n", .{}) catch unreachable;
301 \\ stdout.print("after\n", .{}) catch unreachable;
302 \\}
303 , "before\ndefer2\ndefer1\n");
304
305 cases.add("errdefer and it fails",
306 \\const io = @import("std").io;
307 \\pub fn main() void {
308 \\ do_test() catch return;
309 \\}
310 \\fn do_test() !void {
311 \\ const stdout = io.getStdOut().writer();
312 \\ stdout.print("before\n", .{}) catch unreachable;
313 \\ defer stdout.print("defer1\n", .{}) catch unreachable;
314 \\ errdefer stdout.print("deferErr\n", .{}) catch unreachable;
315 \\ try its_gonna_fail();
316 \\ defer stdout.print("defer3\n", .{}) catch unreachable;
317 \\ stdout.print("after\n", .{}) catch unreachable;
318 \\}
319 \\fn its_gonna_fail() !void {
320 \\ return error.IToldYouItWouldFail;
321 \\}
322 , "before\ndeferErr\ndefer1\n");
323
324 cases.add("errdefer and it passes",
325 \\const io = @import("std").io;
326 \\pub fn main() void {
327 \\ do_test() catch return;
328 \\}
329 \\fn do_test() !void {
330 \\ const stdout = io.getStdOut().writer();
331 \\ stdout.print("before\n", .{}) catch unreachable;
332 \\ defer stdout.print("defer1\n", .{}) catch unreachable;
333 \\ errdefer stdout.print("deferErr\n", .{}) catch unreachable;
334 \\ try its_gonna_pass();
335 \\ defer stdout.print("defer3\n", .{}) catch unreachable;
336 \\ stdout.print("after\n", .{}) catch unreachable;
337 \\}
338 \\fn its_gonna_pass() anyerror!void { }
339 , "before\nafter\ndefer3\ndefer1\n");
340
341 cases.addCase(x: {
342 var tc = cases.create("@embedFile",
343 \\const foo_txt = @embedFile("foo.txt");
344 \\const io = @import("std").io;
345 \\
346 \\pub fn main() void {
347 \\ const stdout = io.getStdOut().writer();
348 \\ stdout.print(foo_txt, .{}) catch unreachable;
349 \\}
350 , "1234\nabcd\n");
351
352 tc.addSourceFile("foo.txt", "1234\nabcd\n");
353
354 break :x tc;
355 });
356
357 cases.addCase(x: {
358 var tc = cases.create("parsing args",
359 \\const std = @import("std");
360 \\const io = std.io;
361 \\const os = std.os;
362 \\
363 \\pub fn main() !void {
364 \\ var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
365 \\ defer _ = gpa.deinit();
366 \\ var arena = std.heap.ArenaAllocator.init(gpa.allocator());
367 \\ defer arena.deinit();
368 \\ var args_it = try std.process.argsWithAllocator(arena.allocator());
369 \\ const stdout = io.getStdOut().writer();
370 \\ var index: usize = 0;
371 \\ _ = args_it.skip();
372 \\ while (args_it.next()) |arg| : (index += 1) {
373 \\ try stdout.print("{}: {s}\n", .{index, arg});
374 \\ }
375 \\}
376 ,
377 \\0: first arg
378 \\1: 'a' 'b' \
379 \\2: bare
380 \\3: ba""re
381 \\4: "
382 \\5: last arg
383 \\
384 );
385
386 tc.setCommandLineArgs(&[_][]const u8{
387 "first arg",
388 "'a' 'b' \\",
389 "bare",
390 "ba\"\"re",
391 "\"",
392 "last arg",
393 });
394
395 break :x tc;
396 });
397
398 cases.addCase(x: {
399 var tc = cases.create("parsing args new API",
400 \\const std = @import("std");
401 \\const io = std.io;
402 \\const os = std.os;
403 \\
404 \\pub fn main() !void {
405 \\ var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
406 \\ defer _ = gpa.deinit();
407 \\ var arena = std.heap.ArenaAllocator.init(gpa.allocator());
408 \\ defer arena.deinit();
409 \\ var args_it = try std.process.argsWithAllocator(arena.allocator());
410 \\ const stdout = io.getStdOut().writer();
411 \\ var index: usize = 0;
412 \\ _ = args_it.skip();
413 \\ while (args_it.next()) |arg| : (index += 1) {
414 \\ try stdout.print("{}: {s}\n", .{index, arg});
415 \\ }
416 \\}
417 ,
418 \\0: first arg
419 \\1: 'a' 'b' \
420 \\2: bare
421 \\3: ba""re
422 \\4: "
423 \\5: last arg
424 \\
425 );
426
427 tc.setCommandLineArgs(&[_][]const u8{
428 "first arg",
429 "'a' 'b' \\",
430 "bare",
431 "ba\"\"re",
432 "\"",
433 "last arg",
434 });
435
436 break :x tc;
437 });
438
439 // It is required to override the log function in order to print to stdout instead of stderr
440 cases.add("std.log per scope log level override",
441 \\const std = @import("std");
442 \\
443 \\pub const std_options: std.Options = .{
444 \\ .log_level = .debug,
445 \\
446 \\ .log_scope_levels = &.{
447 \\ .{ .scope = .a, .level = .warn },
448 \\ .{ .scope = .c, .level = .err },
449 \\ },
450 \\ .logFn = log,
451 \\};
452 \\
453 \\const loga = std.log.scoped(.a);
454 \\const logb = std.log.scoped(.b);
455 \\const logc = std.log.scoped(.c);
456 \\
457 \\pub fn main() !void {
458 \\ loga.debug("", .{});
459 \\ logb.debug("", .{});
460 \\ logc.debug("", .{});
461 \\
462 \\ loga.info("", .{});
463 \\ logb.info("", .{});
464 \\ logc.info("", .{});
465 \\
466 \\ loga.warn("", .{});
467 \\ logb.warn("", .{});
468 \\ logc.warn("", .{});
469 \\
470 \\ loga.err("", .{});
471 \\ logb.err("", .{});
472 \\ logc.err("", .{});
473 \\}
474 \\pub fn log(
475 \\ comptime level: std.log.Level,
476 \\ comptime scope: @TypeOf(.EnumLiteral),
477 \\ comptime format: []const u8,
478 \\ args: anytype,
479 \\) void {
480 \\ const level_txt = comptime level.asText();
481 \\ const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "):";
482 \\ const stdout = std.io.getStdOut().writer();
483 \\ nosuspend stdout.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
484 \\}
485 ,
486 \\debug(b):
487 \\info(b):
488 \\warning(a):
489 \\warning(b):
490 \\error(a):
491 \\error(b):
492 \\error(c):
493 \\
494 );
495
496 cases.add("valid carriage return example", "const io = @import(\"std\").io;\r\n" ++ // Testing CRLF line endings are valid
212 cases.add("valid carriage return example", "const std = @import(\"std\");\r\n" ++ // Testing CRLF line endings are valid
497213 "\r\n" ++
498214 "pub \r fn main() void {\r\n" ++ // Testing isolated carriage return as whitespace is valid
499 " const stdout = io.getStdOut().writer();\r\n" ++
215 " var file_writer = std.fs.File.stdout().writerStreaming(&.{});\r\n" ++
216 " const stdout = &file_writer.interface;\r\n" ++
500217 " stdout.print(\\\\A Multiline\r\n" ++ // testing CRLF at end of multiline string line is valid and normalises to \n in the output
501218 " \\\\String\r\n" ++
502219 " , .{}) catch unreachable;\r\n" ++
test/incremental/add_decl+7-7
......@@ -6,7 +6,7 @@
66#file=main.zig
77const std = @import("std");
88pub fn main() !void {
9 try std.io.getStdOut().writeAll(foo);
9 try std.fs.File.stdout().writeAll(foo);
1010}
1111const foo = "good morning\n";
1212#expect_stdout="good morning\n"
......@@ -15,7 +15,7 @@ const foo = "good morning\n";
1515#file=main.zig
1616const std = @import("std");
1717pub fn main() !void {
18 try std.io.getStdOut().writeAll(foo);
18 try std.fs.File.stdout().writeAll(foo);
1919}
2020const foo = "good morning\n";
2121const bar = "good evening\n";
......@@ -25,7 +25,7 @@ const bar = "good evening\n";
2525#file=main.zig
2626const std = @import("std");
2727pub fn main() !void {
28 try std.io.getStdOut().writeAll(bar);
28 try std.fs.File.stdout().writeAll(bar);
2929}
3030const foo = "good morning\n";
3131const bar = "good evening\n";
......@@ -35,17 +35,17 @@ const bar = "good evening\n";
3535#file=main.zig
3636const std = @import("std");
3737pub fn main() !void {
38 try std.io.getStdOut().writeAll(qux);
38 try std.fs.File.stdout().writeAll(qux);
3939}
4040const foo = "good morning\n";
4141const bar = "good evening\n";
42#expect_error=main.zig:3:37: error: use of undeclared identifier 'qux'
42#expect_error=main.zig:3:39: error: use of undeclared identifier 'qux'
4343
4444#update=add missing declaration
4545#file=main.zig
4646const std = @import("std");
4747pub fn main() !void {
48 try std.io.getStdOut().writeAll(qux);
48 try std.fs.File.stdout().writeAll(qux);
4949}
5050const foo = "good morning\n";
5151const bar = "good evening\n";
......@@ -56,7 +56,7 @@ const qux = "good night\n";
5656#file=main.zig
5757const std = @import("std");
5858pub fn main() !void {
59 try std.io.getStdOut().writeAll(qux);
59 try std.fs.File.stdout().writeAll(qux);
6060}
6161const qux = "good night\n";
6262#expect_stdout="good night\n"
test/incremental/add_decl_namespaced+7-7
......@@ -6,7 +6,7 @@
66#file=main.zig
77const std = @import("std");
88pub fn main() !void {
9 try std.io.getStdOut().writeAll(@This().foo);
9 try std.fs.File.stdout().writeAll(@This().foo);
1010}
1111const foo = "good morning\n";
1212#expect_stdout="good morning\n"
......@@ -15,7 +15,7 @@ const foo = "good morning\n";
1515#file=main.zig
1616const std = @import("std");
1717pub fn main() !void {
18 try std.io.getStdOut().writeAll(@This().foo);
18 try std.fs.File.stdout().writeAll(@This().foo);
1919}
2020const foo = "good morning\n";
2121const bar = "good evening\n";
......@@ -25,7 +25,7 @@ const bar = "good evening\n";
2525#file=main.zig
2626const std = @import("std");
2727pub fn main() !void {
28 try std.io.getStdOut().writeAll(@This().bar);
28 try std.fs.File.stdout().writeAll(@This().bar);
2929}
3030const foo = "good morning\n";
3131const bar = "good evening\n";
......@@ -35,18 +35,18 @@ const bar = "good evening\n";
3535#file=main.zig
3636const std = @import("std");
3737pub fn main() !void {
38 try std.io.getStdOut().writeAll(@This().qux);
38 try std.fs.File.stdout().writeAll(@This().qux);
3939}
4040const foo = "good morning\n";
4141const bar = "good evening\n";
42#expect_error=main.zig:3:44: error: root source file struct 'main' has no member named 'qux'
42#expect_error=main.zig:3:46: error: root source file struct 'main' has no member named 'qux'
4343#expect_error=main.zig:1:1: note: struct declared here
4444
4545#update=add missing declaration
4646#file=main.zig
4747const std = @import("std");
4848pub fn main() !void {
49 try std.io.getStdOut().writeAll(@This().qux);
49 try std.fs.File.stdout().writeAll(@This().qux);
5050}
5151const foo = "good morning\n";
5252const bar = "good evening\n";
......@@ -57,7 +57,7 @@ const qux = "good night\n";
5757#file=main.zig
5858const std = @import("std");
5959pub fn main() !void {
60 try std.io.getStdOut().writeAll(@This().qux);
60 try std.fs.File.stdout().writeAll(@This().qux);
6161}
6262const qux = "good night\n";
6363#expect_stdout="good night\n"
test/incremental/bad_import+2-2
......@@ -7,7 +7,7 @@
77#file=main.zig
88pub fn main() !void {
99 _ = @import("foo.zig");
10 try std.io.getStdOut().writeAll("success\n");
10 try std.fs.File.stdout().writeAll("success\n");
1111}
1212const std = @import("std");
1313#file=foo.zig
......@@ -29,7 +29,7 @@ comptime {
2929#file=main.zig
3030pub fn main() !void {
3131 //_ = @import("foo.zig");
32 try std.io.getStdOut().writeAll("success\n");
32 try std.fs.File.stdout().writeAll("success\n");
3333}
3434const std = @import("std");
3535#expect_stdout="success\n"
test/incremental/change_embed_file+3-3
......@@ -7,7 +7,7 @@
77const std = @import("std");
88const string = @embedFile("string.txt");
99pub fn main() !void {
10 try std.io.getStdOut().writeAll(string);
10 try std.fs.File.stdout().writeAll(string);
1111}
1212#file=string.txt
1313Hello, World!
......@@ -27,7 +27,7 @@ Hello again, World!
2727const std = @import("std");
2828const string = @embedFile("string.txt");
2929pub fn main() !void {
30 try std.io.getStdOut().writeAll("a hardcoded string\n");
30 try std.fs.File.stdout().writeAll("a hardcoded string\n");
3131}
3232#expect_stdout="a hardcoded string\n"
3333
......@@ -36,7 +36,7 @@ pub fn main() !void {
3636const std = @import("std");
3737const string = @embedFile("string.txt");
3838pub fn main() !void {
39 try std.io.getStdOut().writeAll(string);
39 try std.fs.File.stdout().writeAll(string);
4040}
4141#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound
4242
test/incremental/change_enum_tag_type+6-3
......@@ -14,7 +14,8 @@ const Foo = enum(Tag) {
1414pub fn main() !void {
1515 var val: Foo = undefined;
1616 val = .a;
17 try std.io.getStdOut().writer().print("{s}\n", .{@tagName(val)});
17 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
18 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
1819}
1920const std = @import("std");
2021#expect_stdout="a\n"
......@@ -31,7 +32,8 @@ const Foo = enum(Tag) {
3132pub fn main() !void {
3233 var val: Foo = undefined;
3334 val = .a;
34 try std.io.getStdOut().writer().print("{s}\n", .{@tagName(val)});
35 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
36 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
3537}
3638comptime {
3739 // These can't be true at the same time; analysis should stop as soon as it sees `Foo`
......@@ -53,7 +55,8 @@ const Foo = enum(Tag) {
5355pub fn main() !void {
5456 var val: Foo = undefined;
5557 val = .a;
56 try std.io.getStdOut().writer().print("{s}\n", .{@tagName(val)});
58 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
59 try stdout_writer.interface.print("{s}\n", .{@tagName(val)});
5760}
5861const std = @import("std");
5962#expect_stdout="a\n"
test/incremental/change_exports+12-6
......@@ -16,7 +16,8 @@ pub fn main() !void {
1616 extern const bar: u32;
1717 };
1818 S.foo();
19 try std.io.getStdOut().writer().print("{}\n", .{S.bar});
19 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
20 try stdout_writer.interface.print("{}\n", .{S.bar});
2021}
2122const std = @import("std");
2223#expect_stdout="123\n"
......@@ -37,7 +38,8 @@ pub fn main() !void {
3738 extern const other: u32;
3839 };
3940 S.foo();
40 try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other });
41 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
42 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
4143}
4244const std = @import("std");
4345#expect_error=main.zig:6:5: error: exported symbol collision: foo
......@@ -59,7 +61,8 @@ pub fn main() !void {
5961 extern const other: u32;
6062 };
6163 S.foo();
62 try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other });
64 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
65 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
6366}
6467const std = @import("std");
6568#expect_stdout="123 456\n"
......@@ -83,7 +86,8 @@ pub fn main() !void {
8386 extern const other: u32;
8487 };
8588 S.foo();
86 try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other });
89 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
90 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
8791}
8892const std = @import("std");
8993#expect_stdout="123 456\n"
......@@ -128,7 +132,8 @@ pub fn main() !void {
128132 extern const other: u32;
129133 };
130134 S.foo();
131 try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other });
135 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
136 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
132137}
133138const std = @import("std");
134139#expect_stdout="123 456\n"
......@@ -152,7 +157,8 @@ pub fn main() !void {
152157 extern const other: u32;
153158 };
154159 S.foo();
155 try std.io.getStdOut().writer().print("{} {}\n", .{ S.bar, S.other });
160 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
161 try stdout_writer.interface.print("{} {}\n", .{ S.bar, S.other });
156162}
157163const std = @import("std");
158164#expect_error=main.zig:5:5: error: exported symbol collision: bar
test/incremental/change_fn_type+6-3
......@@ -7,7 +7,8 @@ pub fn main() !void {
77 try foo(123);
88}
99fn foo(x: u8) !void {
10 return std.io.getStdOut().writer().print("{d}\n", .{x});
10 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
11 return stdout_writer.interface.print("{d}\n", .{x});
1112}
1213const std = @import("std");
1314#expect_stdout="123\n"
......@@ -18,7 +19,8 @@ pub fn main() !void {
1819 try foo(123);
1920}
2021fn foo(x: i64) !void {
21 return std.io.getStdOut().writer().print("{d}\n", .{x});
22 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
23 return stdout_writer.interface.print("{d}\n", .{x});
2224}
2325const std = @import("std");
2426#expect_stdout="123\n"
......@@ -29,7 +31,8 @@ pub fn main() !void {
2931 try foo(-42);
3032}
3133fn foo(x: i64) !void {
32 return std.io.getStdOut().writer().print("{d}\n", .{x});
34 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
35 return stdout_writer.interface.print("{d}\n", .{x});
3336}
3437const std = @import("std");
3538#expect_stdout="-42\n"
test/incremental/change_generic_line_number+2-2
......@@ -6,7 +6,7 @@ const std = @import("std");
66fn Printer(message: []const u8) type {
77 return struct {
88 fn print() !void {
9 try std.io.getStdOut().writeAll(message);
9 try std.fs.File.stdout().writeAll(message);
1010 }
1111 };
1212}
......@@ -22,7 +22,7 @@ const std = @import("std");
2222fn Printer(message: []const u8) type {
2323 return struct {
2424 fn print() !void {
25 try std.io.getStdOut().writeAll(message);
25 try std.fs.File.stdout().writeAll(message);
2626 }
2727 };
2828}
test/incremental/change_line_number+2-2
......@@ -4,7 +4,7 @@
44#file=main.zig
55const std = @import("std");
66pub fn main() !void {
7 try std.io.getStdOut().writeAll("foo\n");
7 try std.fs.File.stdout().writeAll("foo\n");
88}
99#expect_stdout="foo\n"
1010#update=change line number
......@@ -12,6 +12,6 @@ pub fn main() !void {
1212const std = @import("std");
1313
1414pub fn main() !void {
15 try std.io.getStdOut().writeAll("foo\n");
15 try std.fs.File.stdout().writeAll("foo\n");
1616}
1717#expect_stdout="foo\n"
test/incremental/change_panic_handler+6-3
......@@ -11,7 +11,8 @@ pub fn main() !u8 {
1111}
1212pub const panic = std.debug.FullPanic(myPanic);
1313fn myPanic(msg: []const u8, _: ?usize) noreturn {
14 std.io.getStdOut().writer().print("panic message: {s}\n", .{msg}) catch {};
14 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
15 stdout_writer.interface.print("panic message: {s}\n", .{msg}) catch {};
1516 std.process.exit(0);
1617}
1718const std = @import("std");
......@@ -27,7 +28,8 @@ pub fn main() !u8 {
2728}
2829pub const panic = std.debug.FullPanic(myPanic);
2930fn myPanic(msg: []const u8, _: ?usize) noreturn {
30 std.io.getStdOut().writer().print("new panic message: {s}\n", .{msg}) catch {};
31 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
32 stdout_writer.interface.print("new panic message: {s}\n", .{msg}) catch {};
3133 std.process.exit(0);
3234}
3335const std = @import("std");
......@@ -43,7 +45,8 @@ pub fn main() !u8 {
4345}
4446pub const panic = std.debug.FullPanic(myPanicNew);
4547fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
46 std.io.getStdOut().writer().print("third panic message: {s}\n", .{msg}) catch {};
48 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
49 stdout_writer.interface.print("third panic message: {s}\n", .{msg}) catch {};
4750 std.process.exit(0);
4851}
4952const std = @import("std");
test/incremental/change_panic_handler_explicit+6-3
......@@ -41,7 +41,8 @@ pub const panic = struct {
4141 pub const noreturnReturned = no_panic.noreturnReturned;
4242};
4343fn myPanic(msg: []const u8, _: ?usize) noreturn {
44 std.io.getStdOut().writer().print("panic message: {s}\n", .{msg}) catch {};
44 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
45 stdout_writer.interface.print("panic message: {s}\n", .{msg}) catch {};
4546 std.process.exit(0);
4647}
4748const std = @import("std");
......@@ -87,7 +88,8 @@ pub const panic = struct {
8788 pub const noreturnReturned = no_panic.noreturnReturned;
8889};
8990fn myPanic(msg: []const u8, _: ?usize) noreturn {
90 std.io.getStdOut().writer().print("new panic message: {s}\n", .{msg}) catch {};
91 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
92 stdout_writer.interface.print("new panic message: {s}\n", .{msg}) catch {};
9193 std.process.exit(0);
9294}
9395const std = @import("std");
......@@ -133,7 +135,8 @@ pub const panic = struct {
133135 pub const noreturnReturned = no_panic.noreturnReturned;
134136};
135137fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
136 std.io.getStdOut().writer().print("third panic message: {s}\n", .{msg}) catch {};
138 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
139 stdout_writer.interface.print("third panic message: {s}\n", .{msg}) catch {};
137140 std.process.exit(0);
138141}
139142const std = @import("std");
test/incremental/change_shift_op+4-2
......@@ -8,7 +8,8 @@ pub fn main() !void {
88 try foo(0x1300);
99}
1010fn foo(x: u16) !void {
11 try std.io.getStdOut().writer().print("0x{x}\n", .{x << 4});
11 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
12 try stdout_writer.interface.print("0x{x}\n", .{x << 4});
1213}
1314const std = @import("std");
1415#expect_stdout="0x3000\n"
......@@ -18,7 +19,8 @@ pub fn main() !void {
1819 try foo(0x1300);
1920}
2021fn foo(x: u16) !void {
21 try std.io.getStdOut().writer().print("0x{x}\n", .{x >> 4});
22 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
23 try stdout_writer.interface.print("0x{x}\n", .{x >> 4});
2224}
2325const std = @import("std");
2426#expect_stdout="0x130\n"
test/incremental/change_struct_same_fields+6-3
......@@ -10,7 +10,8 @@ pub fn main() !void {
1010 try foo(&val);
1111}
1212fn foo(val: *const S) !void {
13 try std.io.getStdOut().writer().print(
13 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
14 try stdout_writer.interface.print(
1415 "{d} {d}\n",
1516 .{ val.x, val.y },
1617 );
......@@ -26,7 +27,8 @@ pub fn main() !void {
2627 try foo(&val);
2728}
2829fn foo(val: *const S) !void {
29 try std.io.getStdOut().writer().print(
30 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
31 try stdout_writer.interface.print(
3032 "{d} {d}\n",
3133 .{ val.x, val.y },
3234 );
......@@ -42,7 +44,8 @@ pub fn main() !void {
4244 try foo(&val);
4345}
4446fn foo(val: *const S) !void {
45 try std.io.getStdOut().writer().print(
47 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
48 try stdout_writer.interface.print(
4649 "{d} {d}\n",
4750 .{ val.x, val.y },
4851 );
test/incremental/change_zon_file+3-3
......@@ -7,7 +7,7 @@
77const std = @import("std");
88const message: []const u8 = @import("message.zon");
99pub fn main() !void {
10 try std.io.getStdOut().writeAll(message);
10 try std.fs.File.stdout().writeAll(message);
1111}
1212#file=message.zon
1313"Hello, World!\n"
......@@ -28,7 +28,7 @@ pub fn main() !void {
2828const std = @import("std");
2929const message: []const u8 = @import("message.zon");
3030pub fn main() !void {
31 try std.io.getStdOut().writeAll("a hardcoded string\n");
31 try std.fs.File.stdout().writeAll("a hardcoded string\n");
3232}
3333#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound
3434#expect_error=main.zig:2:37: note: file imported here
......@@ -43,6 +43,6 @@ pub fn main() !void {
4343const std = @import("std");
4444const message: []const u8 = @import("message.zon");
4545pub fn main() !void {
46 try std.io.getStdOut().writeAll(message);
46 try std.fs.File.stdout().writeAll(message);
4747}
4848#expect_stdout="We're back, World!\n"
test/incremental/change_zon_file_no_result_type+1-1
......@@ -6,7 +6,7 @@
66#file=main.zig
77const std = @import("std");
88pub fn main() !void {
9 try std.io.getStdOut().writeAll(@import("foo.zon").message);
9 try std.fs.File.stdout().writeAll(@import("foo.zon").message);
1010}
1111#file=foo.zon
1212.{
test/incremental/compile_log+3-3
......@@ -7,7 +7,7 @@
77#file=main.zig
88const std = @import("std");
99pub fn main() !void {
10 try std.io.getStdOut().writeAll("Hello, World!\n");
10 try std.fs.File.stdout().writeAll("Hello, World!\n");
1111}
1212#expect_stdout="Hello, World!\n"
1313
......@@ -15,7 +15,7 @@ pub fn main() !void {
1515#file=main.zig
1616const std = @import("std");
1717pub fn main() !void {
18 try std.io.getStdOut().writeAll("Hello, World!\n");
18 try std.fs.File.stdout().writeAll("Hello, World!\n");
1919 @compileLog("this is a log");
2020}
2121#expect_error=main.zig:4:5: error: found compile log statement
......@@ -25,6 +25,6 @@ pub fn main() !void {
2525#file=main.zig
2626const std = @import("std");
2727pub fn main() !void {
28 try std.io.getStdOut().writeAll("Hello, World!\n");
28 try std.fs.File.stdout().writeAll("Hello, World!\n");
2929}
3030#expect_stdout="Hello, World!\n"
test/incremental/fix_astgen_failure+5-5
......@@ -9,28 +9,28 @@ pub fn main() !void {
99}
1010#file=foo.zig
1111pub fn hello() !void {
12 try std.io.getStdOut().writeAll("Hello, World!\n");
12 try std.fs.File.stdout().writeAll("Hello, World!\n");
1313}
1414#expect_error=foo.zig:2:9: error: use of undeclared identifier 'std'
1515#update=fix the error
1616#file=foo.zig
1717const std = @import("std");
1818pub fn hello() !void {
19 try std.io.getStdOut().writeAll("Hello, World!\n");
19 try std.fs.File.stdout().writeAll("Hello, World!\n");
2020}
2121#expect_stdout="Hello, World!\n"
2222#update=add new error
2323#file=foo.zig
2424const std = @import("std");
2525pub fn hello() !void {
26 try std.io.getStdOut().writeAll(hello_str);
26 try std.fs.File.stdout().writeAll(hello_str);
2727}
28#expect_error=foo.zig:3:37: error: use of undeclared identifier 'hello_str'
28#expect_error=foo.zig:3:39: error: use of undeclared identifier 'hello_str'
2929#update=fix the new error
3030#file=foo.zig
3131const std = @import("std");
3232const hello_str = "Hello, World! Again!\n";
3333pub fn hello() !void {
34 try std.io.getStdOut().writeAll(hello_str);
34 try std.fs.File.stdout().writeAll(hello_str);
3535}
3636#expect_stdout="Hello, World! Again!\n"
test/incremental/function_becomes_inline+3-3
......@@ -7,7 +7,7 @@ pub fn main() !void {
77 try foo();
88}
99fn foo() !void {
10 try std.io.getStdOut().writer().writeAll("Hello, World!\n");
10 try std.fs.File.stdout().writeAll("Hello, World!\n");
1111}
1212const std = @import("std");
1313#expect_stdout="Hello, World!\n"
......@@ -18,7 +18,7 @@ pub fn main() !void {
1818 try foo();
1919}
2020inline fn foo() !void {
21 try std.io.getStdOut().writer().writeAll("Hello, World!\n");
21 try std.fs.File.stdout().writeAll("Hello, World!\n");
2222}
2323const std = @import("std");
2424#expect_stdout="Hello, World!\n"
......@@ -29,7 +29,7 @@ pub fn main() !void {
2929 try foo();
3030}
3131inline fn foo() !void {
32 try std.io.getStdOut().writer().writeAll("Hello, `inline` World!\n");
32 try std.fs.File.stdout().writeAll("Hello, `inline` World!\n");
3333}
3434const std = @import("std");
3535#expect_stdout="Hello, `inline` World!\n"
test/incremental/hello+2-2
......@@ -6,13 +6,13 @@
66#file=main.zig
77const std = @import("std");
88pub fn main() !void {
9 try std.io.getStdOut().writeAll("good morning\n");
9 try std.fs.File.stdout().writeAll("good morning\n");
1010}
1111#expect_stdout="good morning\n"
1212#update=change the string
1313#file=main.zig
1414const std = @import("std");
1515pub fn main() !void {
16 try std.io.getStdOut().writeAll("おはようございます\n");
16 try std.fs.File.stdout().writeAll("おはようございます\n");
1717}
1818#expect_stdout="おはようございます\n"
test/incremental/make_decl_pub+2-2
......@@ -11,7 +11,7 @@ pub fn main() !void {
1111#file=foo.zig
1212const std = @import("std");
1313fn hello() !void {
14 try std.io.getStdOut().writeAll("Hello, World!\n");
14 try std.fs.File.stdout().writeAll("Hello, World!\n");
1515}
1616#expect_error=main.zig:3:12: error: 'hello' is not marked 'pub'
1717#expect_error=foo.zig:2:1: note: declared here
......@@ -20,6 +20,6 @@ fn hello() !void {
2020#file=foo.zig
2121const std = @import("std");
2222pub fn hello() !void {
23 try std.io.getStdOut().writeAll("Hello, World!\n");
23 try std.fs.File.stdout().writeAll("Hello, World!\n");
2424}
2525#expect_stdout="Hello, World!\n"
test/incremental/modify_inline_fn+2-2
......@@ -7,7 +7,7 @@
77const std = @import("std");
88pub fn main() !void {
99 const str = getStr();
10 try std.io.getStdOut().writeAll(str);
10 try std.fs.File.stdout().writeAll(str);
1111}
1212inline fn getStr() []const u8 {
1313 return "foo\n";
......@@ -18,7 +18,7 @@ inline fn getStr() []const u8 {
1818const std = @import("std");
1919pub fn main() !void {
2020 const str = getStr();
21 try std.io.getStdOut().writeAll(str);
21 try std.fs.File.stdout().writeAll(str);
2222}
2323inline fn getStr() []const u8 {
2424 return "bar\n";
test/incremental/move_src+6-4
......@@ -6,7 +6,8 @@
66#file=main.zig
77const std = @import("std");
88pub fn main() !void {
9 try std.io.getStdOut().writer().print("{d} {d}\n", .{ foo(), bar() });
9 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
10 try stdout_writer.interface.print("{d} {d}\n", .{ foo(), bar() });
1011}
1112fn foo() u32 {
1213 return @src().line;
......@@ -14,13 +15,14 @@ fn foo() u32 {
1415fn bar() u32 {
1516 return 123;
1617}
17#expect_stdout="6 123\n"
18#expect_stdout="7 123\n"
1819
1920#update=add newline
2021#file=main.zig
2122const std = @import("std");
2223pub fn main() !void {
23 try std.io.getStdOut().writer().print("{d} {d}\n", .{ foo(), bar() });
24 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
25 try stdout_writer.interface.print("{d} {d}\n", .{ foo(), bar() });
2426}
2527
2628fn foo() u32 {
......@@ -29,4 +31,4 @@ fn foo() u32 {
2931fn bar() u32 {
3032 return 123;
3133}
32#expect_stdout="7 123\n"
34#expect_stdout="8 123\n"
test/incremental/no_change_preserves_tag_names+2-2
......@@ -7,7 +7,7 @@
77const std = @import("std");
88var some_enum: enum { first, second } = .first;
99pub fn main() !void {
10 try std.io.getStdOut().writeAll(@tagName(some_enum));
10 try std.fs.File.stdout().writeAll(@tagName(some_enum));
1111}
1212#expect_stdout="first"
1313#update=no change
......@@ -15,6 +15,6 @@ pub fn main() !void {
1515const std = @import("std");
1616var some_enum: enum { first, second } = .first;
1717pub fn main() !void {
18 try std.io.getStdOut().writeAll(@tagName(some_enum));
18 try std.fs.File.stdout().writeAll(@tagName(some_enum));
1919}
2020#expect_stdout="first"
test/incremental/recursive_function_becomes_non_recursive+2-2
......@@ -8,7 +8,7 @@ pub fn main() !void {
88 try foo(false);
99}
1010fn foo(recurse: bool) !void {
11 const stdout = std.io.getStdOut().writer();
11 const stdout = std.fs.File.stdout();
1212 if (recurse) return foo(true);
1313 try stdout.writeAll("non-recursive path\n");
1414}
......@@ -21,7 +21,7 @@ pub fn main() !void {
2121 try foo(true);
2222}
2323fn foo(recurse: bool) !void {
24 const stdout = std.io.getStdOut().writer();
24 const stdout = std.fs.File.stdout();
2525 if (recurse) return stdout.writeAll("x==1\n");
2626 try stdout.writeAll("non-recursive path\n");
2727}
test/incremental/remove_enum_field+5-3
......@@ -9,7 +9,8 @@ const MyEnum = enum(u8) {
99 bar = 2,
1010};
1111pub fn main() !void {
12 try std.io.getStdOut().writer().print("{}\n", .{@intFromEnum(MyEnum.foo)});
12 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
13 try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});
1314}
1415const std = @import("std");
1516#expect_stdout="1\n"
......@@ -20,8 +21,9 @@ const MyEnum = enum(u8) {
2021 bar = 2,
2122};
2223pub fn main() !void {
23 try std.io.getStdOut().writer().print("{}\n", .{@intFromEnum(MyEnum.foo)});
24 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
25 try stdout_writer.interface.print("{}\n", .{@intFromEnum(MyEnum.foo)});
2426}
2527const std = @import("std");
26#expect_error=main.zig:6:73: error: enum 'main.MyEnum' has no member named 'foo'
28#expect_error=main.zig:7:69: error: enum 'main.MyEnum' has no member named 'foo'
2729#expect_error=main.zig:1:16: note: enum declared here
test/incremental/unreferenced_error+4-4
......@@ -6,7 +6,7 @@
66#file=main.zig
77const std = @import("std");
88pub fn main() !void {
9 try std.io.getStdOut().writeAll(a);
9 try std.fs.File.stdout().writeAll(a);
1010}
1111const a = "Hello, World!\n";
1212#expect_stdout="Hello, World!\n"
......@@ -15,7 +15,7 @@ const a = "Hello, World!\n";
1515#file=main.zig
1616const std = @import("std");
1717pub fn main() !void {
18 try std.io.getStdOut().writeAll(a);
18 try std.fs.File.stdout().writeAll(a);
1919}
2020const a = @compileError("bad a");
2121#expect_error=main.zig:5:11: error: bad a
......@@ -24,7 +24,7 @@ const a = @compileError("bad a");
2424#file=main.zig
2525const std = @import("std");
2626pub fn main() !void {
27 try std.io.getStdOut().writeAll(b);
27 try std.fs.File.stdout().writeAll(b);
2828}
2929const a = @compileError("bad a");
3030const b = "Hi there!\n";
......@@ -34,7 +34,7 @@ const b = "Hi there!\n";
3434#file=main.zig
3535const std = @import("std");
3636pub fn main() !void {
37 try std.io.getStdOut().writeAll(a);
37 try std.fs.File.stdout().writeAll(a);
3838}
3939const a = "Back to a\n";
4040const b = @compileError("bad b");
test/link/bss/main.zig+4-1
......@@ -4,8 +4,11 @@ const std = @import("std");
44var buffer: [0x1000000]u64 = [1]u64{0} ** 0x1000000;
55
66pub fn main() anyerror!void {
7 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
8
79 buffer[0x10] = 1;
8 try std.io.getStdOut().writer().print("{d}, {d}, {d}\n", .{
10
11 try stdout_writer.interface.print("{d}, {d}, {d}\n", .{
912 // workaround the dreaded decl_val
1013 (&buffer)[0],
1114 (&buffer)[0x10],
test/link/elf.zig+4-4
......@@ -1315,8 +1315,8 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
13151315 \\extern var live_var2: i32;
13161316 \\extern fn live_fn2() void;
13171317 \\pub fn main() void {
1318 \\ const stdout = std.io.getStdOut();
1319 \\ stdout.writer().print("{d} {d}\n", .{ live_var1, live_var2 }) catch unreachable;
1318 \\ var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
1319 \\ stdout_writer.interface.print("{d} {d}\n", .{ live_var1, live_var2 }) catch @panic("fail");
13201320 \\ live_fn2();
13211321 \\}
13221322 ,
......@@ -1357,8 +1357,8 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
13571357 \\extern var live_var2: i32;
13581358 \\extern fn live_fn2() void;
13591359 \\pub fn main() void {
1360 \\ const stdout = std.io.getStdOut();
1361 \\ stdout.writer().print("{d} {d}\n", .{ live_var1, live_var2 }) catch unreachable;
1360 \\ var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
1361 \\ stdout_writer.interface.print("{d} {d}\n", .{ live_var1, live_var2 }) catch @panic("fail");
13621362 \\ live_fn2();
13631363 \\}
13641364 ,
test/link/macho.zig+4-3
......@@ -710,7 +710,7 @@ fn testHelloZig(b: *Build, opts: Options) *Step {
710710 const exe = addExecutable(b, opts, .{ .name = "main", .zig_source_bytes =
711711 \\const std = @import("std");
712712 \\pub fn main() void {
713 \\ std.io.getStdOut().writer().print("Hello world!\n", .{}) catch unreachable;
713 \\ std.fs.File.stdout().writeAll("Hello world!\n") catch @panic("fail");
714714 \\}
715715 });
716716
......@@ -2365,10 +2365,11 @@ fn testTlsZig(b: *Build, opts: Options) *Step {
23652365 \\threadlocal var x: i32 = 0;
23662366 \\threadlocal var y: i32 = -1;
23672367 \\pub fn main() void {
2368 \\ std.io.getStdOut().writer().print("{d} {d}\n", .{x, y}) catch unreachable;
2368 \\ var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
2369 \\ stdout_writer.interface.print("{d} {d}\n", .{x, y}) catch unreachable;
23692370 \\ x -= 1;
23702371 \\ y += 1;
2371 \\ std.io.getStdOut().writer().print("{d} {d}\n", .{x, y}) catch unreachable;
2372 \\ stdout_writer.interface.print("{d} {d}\n", .{x, y}) catch unreachable;
23722373 \\}
23732374 });
23742375
test/link/wasm/extern/main.zig+2-2
......@@ -3,6 +3,6 @@ const std = @import("std");
33extern const foo: u32;
44
55pub fn main() void {
6 const std_out = std.io.getStdOut();
7 std_out.writer().print("Result: {d}", .{foo}) catch {};
6 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
7 stdout_writer.interface.print("Result: {d}", .{foo}) catch {};
88}
test/src/check-stack-trace.zig+1-1
......@@ -84,5 +84,5 @@ pub fn main() !void {
8484 break :got_result try buf.toOwnedSlice();
8585 };
8686
87 try std.io.getStdOut().writeAll(got);
87 try std.fs.File.stdout().writeAll(got);
8888}
test/standalone/child_process/child.zig+4-3
......@@ -27,12 +27,12 @@ fn run(allocator: std.mem.Allocator) !void {
2727 }
2828
2929 // test stdout pipe; parent verifies
30 try std.io.getStdOut().writer().writeAll("hello from stdout");
30 try std.fs.File.stdout().writeAll("hello from stdout");
3131
3232 // test stdin pipe from parent
3333 const hello_stdin = "hello from stdin";
3434 var buf: [hello_stdin.len]u8 = undefined;
35 const stdin = std.io.getStdIn().reader();
35 const stdin: std.fs.File = .stdin();
3636 const n = try stdin.readAll(&buf);
3737 if (!std.mem.eql(u8, buf[0..n], hello_stdin)) {
3838 testError("stdin: '{s}'; want '{s}'", .{ buf[0..n], hello_stdin });
......@@ -40,7 +40,8 @@ fn run(allocator: std.mem.Allocator) !void {
4040}
4141
4242fn testError(comptime fmt: []const u8, args: anytype) void {
43 const stderr = std.io.getStdErr().writer();
43 var stderr_writer = std.fs.File.stderr().writer(&.{});
44 const stderr = &stderr_writer.interface;
4445 stderr.print("CHILD TEST ERROR: ", .{}) catch {};
4546 stderr.print(fmt, args) catch {};
4647 if (fmt[fmt.len - 1] != '\n') {
test/standalone/child_process/main.zig+4-3
......@@ -19,13 +19,13 @@ pub fn main() !void {
1919 child.stderr_behavior = .Inherit;
2020 try child.spawn();
2121 const child_stdin = child.stdin.?;
22 try child_stdin.writer().writeAll("hello from stdin"); // verified in child
22 try child_stdin.writeAll("hello from stdin"); // verified in child
2323 child_stdin.close();
2424 child.stdin = null;
2525
2626 const hello_stdout = "hello from stdout";
2727 var buf: [hello_stdout.len]u8 = undefined;
28 const n = try child.stdout.?.reader().readAll(&buf);
28 const n = try child.stdout.?.deprecatedReader().readAll(&buf);
2929 if (!std.mem.eql(u8, buf[0..n], hello_stdout)) {
3030 testError("child stdout: '{s}'; want '{s}'", .{ buf[0..n], hello_stdout });
3131 }
......@@ -45,7 +45,8 @@ pub fn main() !void {
4545var parent_test_error = false;
4646
4747fn testError(comptime fmt: []const u8, args: anytype) void {
48 const stderr = std.io.getStdErr().writer();
48 var stderr_writer = std.fs.File.stderr().writer(&.{});
49 const stderr = &stderr_writer.interface;
4950 stderr.print("PARENT TEST ERROR: ", .{}) catch {};
5051 stderr.print(fmt, args) catch {};
5152 if (fmt[fmt.len - 1] != '\n') {
test/standalone/run_output_paths/create_file.zig+1-1
......@@ -10,7 +10,7 @@ pub fn main() !void {
1010 dir_name, .{});
1111 const file_name = args.next().?;
1212 const file = try dir.createFile(file_name, .{});
13 try file.writer().print(
13 try file.deprecatedWriter().print(
1414 \\{s}
1515 \\{s}
1616 \\Hello, world!
test/standalone/sigpipe/breakpipe.zig+1-1
......@@ -10,7 +10,7 @@ pub fn main() !void {
1010 std.posix.close(pipe[0]);
1111 _ = std.posix.write(pipe[1], "a") catch |err| switch (err) {
1212 error.BrokenPipe => {
13 try std.io.getStdOut().writer().writeAll("BrokenPipe\n");
13 try std.fs.File.stdout().writeAll("BrokenPipe\n");
1414 std.posix.exit(123);
1515 },
1616 else => |e| return e,
test/standalone/simple/brace_expansion.zig deleted-292
......@@ -1,292 +0,0 @@
1const std = @import("std");
2const io = std.io;
3const mem = std.mem;
4const debug = std.debug;
5const assert = debug.assert;
6const testing = std.testing;
7const ArrayList = std.ArrayList;
8const maxInt = std.math.maxInt;
9
10const Token = union(enum) {
11 Word: []const u8,
12 OpenBrace,
13 CloseBrace,
14 Comma,
15 Eof,
16};
17
18var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
19var global_allocator = gpa.allocator();
20
21fn tokenize(input: []const u8) !ArrayList(Token) {
22 const State = enum {
23 Start,
24 Word,
25 };
26
27 var token_list = ArrayList(Token).init(global_allocator);
28 errdefer token_list.deinit();
29 var tok_begin: usize = undefined;
30 var state = State.Start;
31
32 for (input, 0..) |b, i| {
33 switch (state) {
34 .Start => switch (b) {
35 'a'...'z', 'A'...'Z' => {
36 state = State.Word;
37 tok_begin = i;
38 },
39 '{' => try token_list.append(Token.OpenBrace),
40 '}' => try token_list.append(Token.CloseBrace),
41 ',' => try token_list.append(Token.Comma),
42 else => return error.InvalidInput,
43 },
44 .Word => switch (b) {
45 'a'...'z', 'A'...'Z' => {},
46 '{', '}', ',' => {
47 try token_list.append(Token{ .Word = input[tok_begin..i] });
48 switch (b) {
49 '{' => try token_list.append(Token.OpenBrace),
50 '}' => try token_list.append(Token.CloseBrace),
51 ',' => try token_list.append(Token.Comma),
52 else => unreachable,
53 }
54 state = State.Start;
55 },
56 else => return error.InvalidInput,
57 },
58 }
59 }
60 switch (state) {
61 State.Start => {},
62 State.Word => try token_list.append(Token{ .Word = input[tok_begin..] }),
63 }
64 try token_list.append(Token.Eof);
65 return token_list;
66}
67
68const Node = union(enum) {
69 Scalar: []const u8,
70 List: ArrayList(Node),
71 Combine: []Node,
72
73 fn deinit(self: Node) void {
74 switch (self) {
75 .Scalar => {},
76 .Combine => |pair| {
77 pair[0].deinit();
78 pair[1].deinit();
79 global_allocator.free(pair);
80 },
81 .List => |list| {
82 for (list.items) |item| {
83 item.deinit();
84 }
85 list.deinit();
86 },
87 }
88 }
89};
90
91const ParseError = error{
92 InvalidInput,
93 OutOfMemory,
94};
95
96fn parse(tokens: *const ArrayList(Token), token_index: *usize) ParseError!Node {
97 const first_token = tokens.items[token_index.*];
98 token_index.* += 1;
99
100 const result_node = switch (first_token) {
101 .Word => |word| Node{ .Scalar = word },
102 .OpenBrace => blk: {
103 var list = ArrayList(Node).init(global_allocator);
104 errdefer {
105 for (list.items) |node| node.deinit();
106 list.deinit();
107 }
108 while (true) {
109 try list.append(try parse(tokens, token_index));
110
111 const token = tokens.items[token_index.*];
112 token_index.* += 1;
113
114 switch (token) {
115 .CloseBrace => break,
116 .Comma => continue,
117 else => return error.InvalidInput,
118 }
119 }
120 break :blk Node{ .List = list };
121 },
122 else => return error.InvalidInput,
123 };
124
125 switch (tokens.items[token_index.*]) {
126 .Word, .OpenBrace => {
127 const pair = try global_allocator.alloc(Node, 2);
128 errdefer global_allocator.free(pair);
129 pair[0] = result_node;
130 pair[1] = try parse(tokens, token_index);
131 return Node{ .Combine = pair };
132 },
133 else => return result_node,
134 }
135}
136
137fn expandString(input: []const u8, output: *ArrayList(u8)) !void {
138 const tokens = try tokenize(input);
139 defer tokens.deinit();
140 if (tokens.items.len == 1) {
141 return output.resize(0);
142 }
143
144 var token_index: usize = 0;
145 const root = try parse(&tokens, &token_index);
146 defer root.deinit();
147 const last_token = tokens.items[token_index];
148 switch (last_token) {
149 Token.Eof => {},
150 else => return error.InvalidInput,
151 }
152
153 var result_list = ArrayList(ArrayList(u8)).init(global_allocator);
154 defer {
155 for (result_list.items) |*buf| buf.deinit();
156 result_list.deinit();
157 }
158
159 try expandNode(root, &result_list);
160
161 try output.resize(0);
162 for (result_list.items, 0..) |buf, i| {
163 if (i != 0) {
164 try output.append(' ');
165 }
166 try output.appendSlice(buf.items);
167 }
168}
169
170const ExpandNodeError = error{OutOfMemory};
171
172fn expandNode(node: Node, output: *ArrayList(ArrayList(u8))) ExpandNodeError!void {
173 assert(output.items.len == 0);
174 switch (node) {
175 .Scalar => |scalar| {
176 var list = ArrayList(u8).init(global_allocator);
177 errdefer list.deinit();
178 try list.appendSlice(scalar);
179 try output.append(list);
180 },
181 .Combine => |pair| {
182 const a_node = pair[0];
183 const b_node = pair[1];
184
185 var child_list_a = ArrayList(ArrayList(u8)).init(global_allocator);
186 defer {
187 for (child_list_a.items) |*buf| buf.deinit();
188 child_list_a.deinit();
189 }
190 try expandNode(a_node, &child_list_a);
191
192 var child_list_b = ArrayList(ArrayList(u8)).init(global_allocator);
193 defer {
194 for (child_list_b.items) |*buf| buf.deinit();
195 child_list_b.deinit();
196 }
197 try expandNode(b_node, &child_list_b);
198
199 for (child_list_a.items) |buf_a| {
200 for (child_list_b.items) |buf_b| {
201 var combined_buf = ArrayList(u8).init(global_allocator);
202 errdefer combined_buf.deinit();
203
204 try combined_buf.appendSlice(buf_a.items);
205 try combined_buf.appendSlice(buf_b.items);
206 try output.append(combined_buf);
207 }
208 }
209 },
210 .List => |list| {
211 for (list.items) |child_node| {
212 var child_list = ArrayList(ArrayList(u8)).init(global_allocator);
213 errdefer for (child_list.items) |*buf| buf.deinit();
214 defer child_list.deinit();
215
216 try expandNode(child_node, &child_list);
217
218 for (child_list.items) |buf| {
219 try output.append(buf);
220 }
221 }
222 },
223 }
224}
225
226pub fn main() !void {
227 defer _ = gpa.deinit();
228 const stdin_file = io.getStdIn();
229 const stdout_file = io.getStdOut();
230
231 const stdin = try stdin_file.reader().readAllAlloc(global_allocator, std.math.maxInt(usize));
232 defer global_allocator.free(stdin);
233
234 var result_buf = ArrayList(u8).init(global_allocator);
235 defer result_buf.deinit();
236
237 try expandString(stdin, &result_buf);
238 try stdout_file.writeAll(result_buf.items);
239}
240
241test "invalid inputs" {
242 global_allocator = std.testing.allocator;
243
244 try expectError("}ABC", error.InvalidInput);
245 try expectError("{ABC", error.InvalidInput);
246 try expectError("}{", error.InvalidInput);
247 try expectError("{}", error.InvalidInput);
248 try expectError("A,B,C", error.InvalidInput);
249 try expectError("{A{B,C}", error.InvalidInput);
250 try expectError("{A,}", error.InvalidInput);
251
252 try expectError("\n", error.InvalidInput);
253}
254
255fn expectError(test_input: []const u8, expected_err: anyerror) !void {
256 var output_buf = ArrayList(u8).init(global_allocator);
257 defer output_buf.deinit();
258
259 try testing.expectError(expected_err, expandString(test_input, &output_buf));
260}
261
262test "valid inputs" {
263 global_allocator = std.testing.allocator;
264
265 try expectExpansion("{x,y,z}", "x y z");
266 try expectExpansion("{A,B}{x,y}", "Ax Ay Bx By");
267 try expectExpansion("{A,B{x,y}}", "A Bx By");
268
269 try expectExpansion("{ABC}", "ABC");
270 try expectExpansion("{A,B,C}", "A B C");
271 try expectExpansion("ABC", "ABC");
272
273 try expectExpansion("", "");
274 try expectExpansion("{A,B}{C,{x,y}}{g,h}", "ACg ACh Axg Axh Ayg Ayh BCg BCh Bxg Bxh Byg Byh");
275 try expectExpansion("{A,B}{C,C{x,y}}{g,h}", "ACg ACh ACxg ACxh ACyg ACyh BCg BCh BCxg BCxh BCyg BCyh");
276 try expectExpansion("{A,B}a", "Aa Ba");
277 try expectExpansion("{C,{x,y}}", "C x y");
278 try expectExpansion("z{C,{x,y}}", "zC zx zy");
279 try expectExpansion("a{b,c{d,e{f,g}}}", "ab acd acef aceg");
280 try expectExpansion("a{x,y}b", "axb ayb");
281 try expectExpansion("z{{a,b}}", "za zb");
282 try expectExpansion("a{b}", "ab");
283}
284
285fn expectExpansion(test_input: []const u8, expected_result: []const u8) !void {
286 var result = ArrayList(u8).init(global_allocator);
287 defer result.deinit();
288
289 expandString(test_input, &result) catch unreachable;
290
291 try testing.expectEqualSlices(u8, expected_result, result.items);
292}
test/standalone/simple/build.zig-4
......@@ -109,10 +109,6 @@ const cases = [_]Case{
109109 //.{
110110 // .src_path = "issue_9693/main.zig",
111111 //},
112 .{
113 .src_path = "brace_expansion.zig",
114 .is_test = true,
115 },
116112 .{
117113 .src_path = "issue_7030.zig",
118114 .target = .{
test/standalone/simple/cat/main.zig+10-10
......@@ -1,42 +1,42 @@
11const std = @import("std");
22const io = std.io;
3const process = std.process;
43const fs = std.fs;
54const mem = std.mem;
65const warn = std.log.warn;
6const fatal = std.process.fatal;
77
88pub fn main() !void {
99 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
1010 defer arena_instance.deinit();
1111 const arena = arena_instance.allocator();
1212
13 const args = try process.argsAlloc(arena);
13 const args = try std.process.argsAlloc(arena);
1414
1515 const exe = args[0];
1616 var catted_anything = false;
17 const stdout_file = io.getStdOut();
17 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
18 const stdout = &stdout_writer.interface;
19 var stdin_reader = std.fs.File.stdin().reader(&.{});
1820
1921 const cwd = fs.cwd();
2022
2123 for (args[1..]) |arg| {
2224 if (mem.eql(u8, arg, "-")) {
2325 catted_anything = true;
24 try stdout_file.writeFileAll(io.getStdIn(), .{});
26 _ = try stdout.sendFileAll(&stdin_reader, .unlimited);
2527 } else if (mem.startsWith(u8, arg, "-")) {
2628 return usage(exe);
2729 } else {
28 const file = cwd.openFile(arg, .{}) catch |err| {
29 warn("Unable to open file: {s}\n", .{@errorName(err)});
30 return err;
31 };
30 const file = cwd.openFile(arg, .{}) catch |err| fatal("unable to open file: {t}\n", .{err});
3231 defer file.close();
3332
3433 catted_anything = true;
35 try stdout_file.writeFileAll(file, .{});
34 var file_reader = file.reader(&.{});
35 _ = try stdout.sendFileAll(&file_reader, .unlimited);
3636 }
3737 }
3838 if (!catted_anything) {
39 try stdout_file.writeFileAll(io.getStdIn(), .{});
39 _ = try stdout.sendFileAll(&stdin_reader, .unlimited);
4040 }
4141}
4242
test/standalone/simple/guess_number/main.zig+11-13
......@@ -1,37 +1,35 @@
11const builtin = @import("builtin");
22const std = @import("std");
3const io = std.io;
4const fmt = std.fmt;
53
64pub fn main() !void {
7 const stdout = io.getStdOut().writer();
8 const stdin = io.getStdIn();
5 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
6 const out = &stdout_writer.interface;
7 const stdin: std.fs.File = .stdin();
98
10 try stdout.print("Welcome to the Guess Number Game in Zig.\n", .{});
9 try out.writeAll("Welcome to the Guess Number Game in Zig.\n");
1110
1211 const answer = std.crypto.random.intRangeLessThan(u8, 0, 100) + 1;
1312
1413 while (true) {
15 try stdout.print("\nGuess a number between 1 and 100: ", .{});
14 try out.writeAll("\nGuess a number between 1 and 100: ");
1615 var line_buf: [20]u8 = undefined;
17
1816 const amt = try stdin.read(&line_buf);
1917 if (amt == line_buf.len) {
20 try stdout.print("Input too long.\n", .{});
18 try out.writeAll("Input too long.\n");
2119 continue;
2220 }
2321 const line = std.mem.trimEnd(u8, line_buf[0..amt], "\r\n");
2422
25 const guess = fmt.parseUnsigned(u8, line, 10) catch {
26 try stdout.print("Invalid number.\n", .{});
23 const guess = std.fmt.parseUnsigned(u8, line, 10) catch {
24 try out.writeAll("Invalid number.\n");
2725 continue;
2826 };
2927 if (guess > answer) {
30 try stdout.print("Guess lower.\n", .{});
28 try out.writeAll("Guess lower.\n");
3129 } else if (guess < answer) {
32 try stdout.print("Guess higher.\n", .{});
30 try out.writeAll("Guess higher.\n");
3331 } else {
34 try stdout.print("You win!\n", .{});
32 try out.writeAll("You win!\n");
3533 return;
3634 }
3735 }
test/standalone/simple/hello_world/hello.zig+1-1
......@@ -1,5 +1,5 @@
11const std = @import("std");
22
33pub fn main() !void {
4 try std.io.getStdOut().writeAll("Hello, World!\n");
4 try std.fs.File.stdout().writeAll("Hello, World!\n");
55}
test/standalone/simple/std_enums_big_enums.zig+1
......@@ -6,6 +6,7 @@ pub fn main() void {
66 const Big = @Type(.{ .@"enum" = .{
77 .tag_type = u16,
88 .fields = make_fields: {
9 @setEvalBranchQuota(500000);
910 var fields: [1001]std.builtin.Type.EnumField = undefined;
1011 for (&fields, 0..) |*field, i| {
1112 field.* = .{ .name = std.fmt.comptimePrint("field_{d}", .{i}), .value = i };
test/standalone/windows_argv/fuzz.zig+1-1
......@@ -58,7 +58,7 @@ pub fn main() !void {
5858 std.debug.print(">>> found discrepancy <<<\n", .{});
5959 const cmd_line_wtf8 = try std.unicode.wtf16LeToWtf8Alloc(allocator, cmd_line_w);
6060 defer allocator.free(cmd_line_wtf8);
61 std.debug.print("\"{}\"\n\n", .{std.zig.fmtEscapes(cmd_line_wtf8)});
61 std.debug.print("\"{f}\"\n\n", .{std.zig.fmtString(cmd_line_wtf8)});
6262
6363 errors += 1;
6464 }
test/standalone/windows_argv/lib.zig+6-6
......@@ -27,8 +27,8 @@ fn testArgv(expected_args: []const [*:0]const u16) !void {
2727 wtf8_buf.clearRetainingCapacity();
2828 try std.unicode.wtf16LeToWtf8ArrayList(&wtf8_buf, std.mem.span(expected_arg));
2929 if (!std.mem.eql(u8, wtf8_buf.items, arg_wtf8)) {
30 std.debug.print("{}: expected: \"{}\"\n", .{ i, std.zig.fmtEscapes(wtf8_buf.items) });
31 std.debug.print("{}: actual: \"{}\"\n", .{ i, std.zig.fmtEscapes(arg_wtf8) });
30 std.debug.print("{}: expected: \"{f}\"\n", .{ i, std.zig.fmtString(wtf8_buf.items) });
31 std.debug.print("{}: actual: \"{f}\"\n", .{ i, std.zig.fmtString(arg_wtf8) });
3232 eql = false;
3333 }
3434 }
......@@ -36,22 +36,22 @@ fn testArgv(expected_args: []const [*:0]const u16) !void {
3636 for (expected_args[min_len..], min_len..) |arg, i| {
3737 wtf8_buf.clearRetainingCapacity();
3838 try std.unicode.wtf16LeToWtf8ArrayList(&wtf8_buf, std.mem.span(arg));
39 std.debug.print("{}: expected: \"{}\"\n", .{ i, std.zig.fmtEscapes(wtf8_buf.items) });
39 std.debug.print("{}: expected: \"{f}\"\n", .{ i, std.zig.fmtString(wtf8_buf.items) });
4040 }
4141 for (args[min_len..], min_len..) |arg, i| {
42 std.debug.print("{}: actual: \"{}\"\n", .{ i, std.zig.fmtEscapes(arg) });
42 std.debug.print("{}: actual: \"{f}\"\n", .{ i, std.zig.fmtString(arg) });
4343 }
4444 const peb = std.os.windows.peb();
4545 const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);
4646 wtf8_buf.clearRetainingCapacity();
4747 try std.unicode.wtf16LeToWtf8ArrayList(&wtf8_buf, std.mem.span(lpCmdLine));
48 std.debug.print("command line: \"{}\"\n", .{std.zig.fmtEscapes(wtf8_buf.items)});
48 std.debug.print("command line: \"{f}\"\n", .{std.zig.fmtString(wtf8_buf.items)});
4949 std.debug.print("expected argv:\n", .{});
5050 std.debug.print("&.{{\n", .{});
5151 for (expected_args) |arg| {
5252 wtf8_buf.clearRetainingCapacity();
5353 try std.unicode.wtf16LeToWtf8ArrayList(&wtf8_buf, std.mem.span(arg));
54 std.debug.print(" \"{}\",\n", .{std.zig.fmtEscapes(wtf8_buf.items)});
54 std.debug.print(" \"{f}\",\n", .{std.zig.fmtString(wtf8_buf.items)});
5555 }
5656 std.debug.print("}}\n", .{});
5757 return error.ArgvMismatch;
test/standalone/windows_bat_args/echo-args.zig+2-1
......@@ -5,7 +5,8 @@ pub fn main() !void {
55 defer arena_state.deinit();
66 const arena = arena_state.allocator();
77
8 const stdout = std.io.getStdOut().writer();
8 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
9 const stdout = &stdout_writer.interface;
910 var args = try std.process.argsAlloc(arena);
1011 for (args[1..], 1..) |arg, i| {
1112 try stdout.writeAll(arg);
test/standalone/windows_spawn/hello.zig+2-1
......@@ -1,6 +1,7 @@
11const std = @import("std");
22
33pub fn main() !void {
4 const stdout = std.io.getStdOut().writer();
4 var stdout_writer = std.fs.File.stdout().writerStreaming(&.{});
5 const stdout = &stdout_writer.interface;
56 try stdout.writeAll("hello from exe\n");
67}
test/tests.zig+11-9
......@@ -918,14 +918,16 @@ const test_targets = blk: {
918918 .link_libc = true,
919919 },
920920
921 .{
922 .target = std.Target.Query.parse(.{
923 .arch_os_abi = "riscv64-linux-none",
924 .cpu_features = "baseline+v+zbb",
925 }) catch unreachable,
926 .use_llvm = false,
927 .use_lld = false,
928 },
921 // TODO implement codegen airFieldParentPtr
922 // TODO implement airMemmove for riscv64
923 //.{
924 // .target = std.Target.Query.parse(.{
925 // .arch_os_abi = "riscv64-linux-none",
926 // .cpu_features = "baseline+v+zbb",
927 // }) catch unreachable,
928 // .use_llvm = false,
929 // .use_lld = false,
930 //},
929931 .{
930932 .target = .{
931933 .cpu_arch = .riscv64,
......@@ -2753,7 +2755,7 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {
27532755
27542756 run.addArg(b.graph.zig_exe);
27552757 run.addFileArg(b.path("test/incremental/").path(b, entry.path));
2756 run.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) });
2758 run.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) });
27572759
27582760 run.addCheck(.{ .expect_term = .{ .Exited = 0 } });
27592761
tools/docgen.zig+4-5
......@@ -43,8 +43,7 @@ pub fn main() !void {
4343 while (args_it.next()) |arg| {
4444 if (mem.startsWith(u8, arg, "-")) {
4545 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
46 const stdout = io.getStdOut().writer();
47 try stdout.writeAll(usage);
46 try fs.File.stdout().writeAll(usage);
4847 process.exit(0);
4948 } else if (mem.eql(u8, arg, "--code-dir")) {
5049 if (args_it.next()) |param| {
......@@ -76,9 +75,9 @@ pub fn main() !void {
7675 var code_dir = try fs.cwd().openDir(code_dir_path, .{});
7776 defer code_dir.close();
7877
79 const input_file_bytes = try in_file.reader().readAllAlloc(arena, max_doc_file_size);
78 const input_file_bytes = try in_file.deprecatedReader().readAllAlloc(arena, max_doc_file_size);
8079
81 var buffered_writer = io.bufferedWriter(out_file.writer());
80 var buffered_writer = io.bufferedWriter(out_file.deprecatedWriter());
8281
8382 var tokenizer = Tokenizer.init(input_path, input_file_bytes);
8483 var toc = try genToc(arena, &tokenizer);
......@@ -426,7 +425,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
426425 try toc.writeByte('\n');
427426 try toc.writeByteNTimes(' ', header_stack_size * 4);
428427 if (last_columns) |n| {
429 try toc.print("<ul style=\"columns: {}\">\n", .{n});
428 try toc.print("<ul style=\"columns: {d}\">\n", .{n});
430429 } else {
431430 try toc.writeAll("<ul>\n");
432431 }
tools/doctest.zig+2-2
......@@ -44,7 +44,7 @@ pub fn main() !void {
4444 while (args_it.next()) |arg| {
4545 if (mem.startsWith(u8, arg, "-")) {
4646 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
47 try std.io.getStdOut().writeAll(usage);
47 try std.fs.File.stdout().writeAll(usage);
4848 process.exit(0);
4949 } else if (mem.eql(u8, arg, "-i")) {
5050 opt_input = args_it.next() orelse fatal("expected parameter after -i", .{});
......@@ -85,7 +85,7 @@ pub fn main() !void {
8585 var out_file = try fs.cwd().createFile(output_path, .{});
8686 defer out_file.close();
8787
88 var bw = std.io.bufferedWriter(out_file.writer());
88 var bw = std.io.bufferedWriter(out_file.deprecatedWriter());
8989 const out = bw.writer();
9090
9191 try printSourceBlock(arena, out, source, fs.path.basename(input_path));
tools/dump-cov.zig+4-3
......@@ -48,8 +48,9 @@ pub fn main() !void {
4848 fatal("failed to load coverage file {}: {s}", .{ cov_path, @errorName(err) });
4949 };
5050
51 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
52 const stdout = bw.writer();
51 var stdout_buffer: [4000]u8 = undefined;
52 var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer);
53 const stdout = &stdout_writer.interface;
5354
5455 const header: *SeenPcsHeader = @ptrCast(cov_bytes);
5556 try stdout.print("{any}\n", .{header.*});
......@@ -83,5 +84,5 @@ pub fn main() !void {
8384 });
8485 }
8586
86 try bw.flush();
87 try stdout.flush();
8788}
tools/fetch_them_macos_headers.zig+2-13
......@@ -5,6 +5,8 @@ const mem = std.mem;
55const process = std.process;
66const assert = std.debug.assert;
77const tmpDir = std.testing.tmpDir;
8const fatal = std.process.fatal;
9const info = std.log.info;
810
911const Allocator = mem.Allocator;
1012const OsTag = std.Target.Os.Tag;
......@@ -245,19 +247,6 @@ const ArgsIterator = struct {
245247 }
246248};
247249
248fn info(comptime format: []const u8, args: anytype) void {
249 const msg = std.fmt.allocPrint(gpa, "info: " ++ format ++ "\n", args) catch return;
250 std.io.getStdOut().writeAll(msg) catch {};
251}
252
253fn fatal(comptime format: []const u8, args: anytype) noreturn {
254 ret: {
255 const msg = std.fmt.allocPrint(gpa, "fatal: " ++ format ++ "\n", args) catch break :ret;
256 std.io.getStdErr().writeAll(msg) catch {};
257 }
258 std.process.exit(1);
259}
260
261250const Version = struct {
262251 major: u16,
263252 minor: u8,
tools/gen_macos_headers_c.zig+9-17
......@@ -1,5 +1,7 @@
11const std = @import("std");
22const assert = std.debug.assert;
3const info = std.log.info;
4const fatal = std.process.fatal;
35
46const Allocator = std.mem.Allocator;
57
......@@ -13,19 +15,6 @@ const usage =
1315 \\-h, --help Print this help and exit
1416;
1517
16fn info(comptime format: []const u8, args: anytype) void {
17 const msg = std.fmt.allocPrint(gpa, "info: " ++ format ++ "\n", args) catch return;
18 std.io.getStdOut().writeAll(msg) catch {};
19}
20
21fn fatal(comptime format: []const u8, args: anytype) noreturn {
22 ret: {
23 const msg = std.fmt.allocPrint(gpa, "fatal: " ++ format ++ "\n", args) catch break :ret;
24 std.io.getStdErr().writeAll(msg) catch {};
25 }
26 std.process.exit(1);
27}
28
2918pub fn main() anyerror!void {
3019 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
3120 defer arena_allocator.deinit();
......@@ -58,16 +47,19 @@ pub fn main() anyerror!void {
5847
5948 std.mem.sort([]const u8, paths.items, {}, SortFn.lessThan);
6049
61 const stdout = std.io.getStdOut().writer();
62 try stdout.writeAll("#define _XOPEN_SOURCE\n");
50 var buffer: [2000]u8 = undefined;
51 var stdout_writer = std.fs.File.stdout().writerStreaming(&buffer);
52 const w = &stdout_writer.interface;
53 try w.writeAll("#define _XOPEN_SOURCE\n");
6354 for (paths.items) |path| {
64 try stdout.print("#include <{s}>\n", .{path});
55 try w.print("#include <{s}>\n", .{path});
6556 }
66 try stdout.writeAll(
57 try w.writeAll(
6758 \\int main(int argc, char **argv) {
6859 \\ return 0;
6960 \\}
7061 );
62 try w.flush();
7163}
7264
7365fn findHeaders(
tools/gen_outline_atomics.zig+4-3
......@@ -17,8 +17,9 @@ pub fn main() !void {
1717
1818 //const args = try std.process.argsAlloc(arena);
1919
20 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
21 const w = bw.writer();
20 var stdout_buffer: [2000]u8 = undefined;
21 var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer);
22 const w = &stdout_writer.interface;
2223
2324 try w.writeAll(
2425 \\//! This file is generated by tools/gen_outline_atomics.zig.
......@@ -57,7 +58,7 @@ pub fn main() !void {
5758
5859 try w.writeAll(footer.items);
5960 try w.writeAll("}\n");
60 try bw.flush();
61 try w.flush();
6162}
6263
6364fn writeFunction(
tools/gen_spirv_spec.zig+9-12
......@@ -91,9 +91,10 @@ pub fn main() !void {
9191
9292 try readExtRegistry(&exts, a, std.fs.cwd(), args[2]);
9393
94 var bw = std.io.bufferedWriter(std.io.getStdOut().writer());
95 try render(bw.writer(), a, core_spec, exts.items);
96 try bw.flush();
94 var buffer: [4000]u8 = undefined;
95 var w = std.fs.File.stdout().writerStreaming(&buffer);
96 try render(&w, a, core_spec, exts.items);
97 try w.flush();
9798}
9899
99100fn readExtRegistry(exts: *std.ArrayList(Extension), a: Allocator, dir: std.fs.Dir, sub_path: []const u8) !void {
......@@ -166,7 +167,7 @@ fn tagPriorityScore(tag: []const u8) usize {
166167 }
167168}
168169
169fn render(writer: anytype, a: Allocator, registry: CoreRegistry, extensions: []const Extension) !void {
170fn render(writer: *std.io.Writer, a: Allocator, registry: CoreRegistry, extensions: []const Extension) !void {
170171 try writer.writeAll(
171172 \\//! This file is auto-generated by tools/gen_spirv_spec.zig.
172173 \\
......@@ -188,15 +189,10 @@ fn render(writer: anytype, a: Allocator, registry: CoreRegistry, extensions: []c
188189 \\ none,
189190 \\ _,
190191 \\
191 \\ pub fn format(
192 \\ self: IdResult,
193 \\ comptime _: []const u8,
194 \\ _: std.fmt.FormatOptions,
195 \\ writer: anytype,
196 \\ ) @TypeOf(writer).Error!void {
192 \\ pub fn format(self: IdResult, writer: *std.io.Writer) std.io.Writer.Error!void {
197193 \\ switch (self) {
198194 \\ .none => try writer.writeAll("(none)"),
199 \\ else => try writer.print("%{}", .{@intFromEnum(self)}),
195 \\ else => try writer.print("%{d}", .{@intFromEnum(self)}),
200196 \\ }
201197 \\ }
202198 \\};
......@@ -899,7 +895,8 @@ fn parseHexInt(text: []const u8) !u31 {
899895}
900896
901897fn usageAndExit(arg0: []const u8, code: u8) noreturn {
902 std.io.getStdErr().writer().print(
898 const stderr = std.debug.lockStderrWriter(&.{});
899 stderr.print(
903900 \\Usage: {s} <SPIRV-Headers repository path> <path/to/zig/src/codegen/spirv/extinst.zig.grammar.json>
904901 \\
905902 \\Generates Zig bindings for SPIR-V specifications found in the SPIRV-Headers
tools/gen_stubs.zig+5-1
......@@ -333,7 +333,9 @@ pub fn main() !void {
333333 }
334334 }
335335
336 const stdout = std.io.getStdOut().writer();
336 var stdout_buffer: [2000]u8 = undefined;
337 var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer);
338 const stdout = &stdout_writer.interface;
337339 try stdout.writeAll(
338340 \\#ifdef PTR64
339341 \\#define WEAK64 .weak
......@@ -533,6 +535,8 @@ pub fn main() !void {
533535 .all => {},
534536 .single, .multi, .family, .time32 => try stdout.writeAll("#endif\n"),
535537 }
538
539 try stdout.flush();
536540}
537541
538542fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) !void {
tools/generate_JSONTestSuite.zig+5-1
......@@ -6,7 +6,9 @@ pub fn main() !void {
66 var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
77 var allocator = gpa.allocator();
88
9 var output = std.io.getStdOut().writer();
9 var stdout_buffer: [2000]u8 = undefined;
10 var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer);
11 const output = &stdout_writer.interface;
1012 try output.writeAll(
1113 \\// This file was generated by _generate_JSONTestSuite.zig
1214 \\// These test cases are sourced from: https://github.com/nst/JSONTestSuite
......@@ -44,6 +46,8 @@ pub fn main() !void {
4446 try writeString(output, contents);
4547 try output.writeAll(");\n}\n");
4648 }
49
50 try output.flush();
4751}
4852
4953const i_structure_500_nested_arrays = "[" ** 500 ++ "]" ** 500;
tools/generate_c_size_and_align_checks.zig+7-4
......@@ -42,20 +42,23 @@ pub fn main() !void {
4242 const query = try std.Target.Query.parse(.{ .arch_os_abi = args[1] });
4343 const target = try std.zig.system.resolveTargetQuery(query);
4444
45 const stdout = std.io.getStdOut().writer();
45 var buffer: [2000]u8 = undefined;
46 var stdout_writer = std.fs.File.stdout().writerStreaming(&buffer);
47 const w = &stdout_writer.interface;
4648 inline for (@typeInfo(std.Target.CType).@"enum".fields) |field| {
4749 const c_type: std.Target.CType = @enumFromInt(field.value);
48 try stdout.print("_Static_assert(sizeof({0s}) == {1d}, \"sizeof({0s}) == {1d}\");\n", .{
50 try w.print("_Static_assert(sizeof({0s}) == {1d}, \"sizeof({0s}) == {1d}\");\n", .{
4951 cName(c_type),
5052 target.cTypeByteSize(c_type),
5153 });
52 try stdout.print("_Static_assert(_Alignof({0s}) == {1d}, \"_Alignof({0s}) == {1d}\");\n", .{
54 try w.print("_Static_assert(_Alignof({0s}) == {1d}, \"_Alignof({0s}) == {1d}\");\n", .{
5355 cName(c_type),
5456 target.cTypeAlignment(c_type),
5557 });
56 try stdout.print("_Static_assert(__alignof({0s}) == {1d}, \"__alignof({0s}) == {1d}\");\n\n", .{
58 try w.print("_Static_assert(__alignof({0s}) == {1d}, \"__alignof({0s}) == {1d}\");\n\n", .{
5759 cName(c_type),
5860 target.cTypePreferredAlignment(c_type),
5961 });
6062 }
63 try w.flush();
6164}
tools/generate_linux_syscalls.zig+11-9
......@@ -666,13 +666,16 @@ pub fn main() !void {
666666 const allocator = arena.allocator();
667667
668668 const args = try std.process.argsAlloc(allocator);
669 if (args.len < 3 or mem.eql(u8, args[1], "--help"))
670 usageAndExit(std.io.getStdErr(), args[0], 1);
669 if (args.len < 3 or mem.eql(u8, args[1], "--help")) {
670 usage(std.debug.lockStderrWriter(&.{}), args[0]) catch std.process.exit(2);
671 std.process.exit(1);
672 }
671673 const zig_exe = args[1];
672674 const linux_path = args[2];
673675
674 var buf_out = std.io.bufferedWriter(std.io.getStdOut().writer());
675 const writer = buf_out.writer();
676 var stdout_buffer: [2000]u8 = undefined;
677 var stdout_writer = std.fs.File.stdout().writerStreaming(&stdout_buffer);
678 const writer = &stdout_writer.interface;
676679
677680 var linux_dir = try std.fs.cwd().openDir(linux_path, .{});
678681 defer linux_dir.close();
......@@ -714,17 +717,16 @@ pub fn main() !void {
714717 }
715718 }
716719
717 try buf_out.flush();
720 try writer.flush();
718721}
719722
720fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn {
721 file.writer().print(
723fn usage(w: *std.io.Writer, arg0: []const u8) std.io.Writer.Error!void {
724 try w.print(
722725 \\Usage: {s} /path/to/zig /path/to/linux
723726 \\Alternative Usage: zig run /path/to/git/zig/tools/generate_linux_syscalls.zig -- /path/to/zig /path/to/linux
724727 \\
725728 \\Generates the list of Linux syscalls for each supported cpu arch, using the Linux development tree.
726729 \\Prints to stdout Zig code which you can use to replace the file lib/std/os/linux/syscalls.zig.
727730 \\
728 , .{arg0}) catch std.process.exit(1);
729 std.process.exit(code);
731 , .{arg0});
730732}
tools/update_clang_options.zig+22-20
......@@ -634,25 +634,25 @@ pub fn main() anyerror!void {
634634 const allocator = arena.allocator();
635635 const args = try std.process.argsAlloc(allocator);
636636
637 if (args.len <= 1) {
638 usageAndExit(std.io.getStdErr(), args[0], 1);
639 }
637 var stdout_buffer: [4000]u8 = undefined;
638 var stdout_writer = fs.stdout().writerStreaming(&stdout_buffer);
639 const stdout = &stdout_writer.interface;
640
641 if (args.len <= 1) printUsageAndExit(args[0]);
642
640643 if (std.mem.eql(u8, args[1], "--help")) {
641 usageAndExit(std.io.getStdOut(), args[0], 0);
642 }
643 if (args.len < 3) {
644 usageAndExit(std.io.getStdErr(), args[0], 1);
644 printUsage(stdout, args[0]) catch std.process.exit(2);
645 stdout.flush() catch std.process.exit(2);
646 std.process.exit(0);
645647 }
646648
649 if (args.len < 3) printUsageAndExit(args[0]);
650
647651 const llvm_tblgen_exe = args[1];
648 if (std.mem.startsWith(u8, llvm_tblgen_exe, "-")) {
649 usageAndExit(std.io.getStdErr(), args[0], 1);
650 }
652 if (std.mem.startsWith(u8, llvm_tblgen_exe, "-")) printUsageAndExit(args[0]);
651653
652654 const llvm_src_root = args[2];
653 if (std.mem.startsWith(u8, llvm_src_root, "-")) {
654 usageAndExit(std.io.getStdErr(), args[0], 1);
655 }
655 if (std.mem.startsWith(u8, llvm_src_root, "-")) printUsageAndExit(args[0]);
656656
657657 var llvm_to_zig_cpu_features = std.StringHashMap([]const u8).init(allocator);
658658
......@@ -719,8 +719,6 @@ pub fn main() anyerror!void {
719719 // "W" and "Wl,". So we sort this list in order of descending priority.
720720 std.mem.sort(*json.ObjectMap, all_objects.items, {}, objectLessThan);
721721
722 var buffered_stdout = std.io.bufferedWriter(std.io.getStdOut().writer());
723 const stdout = buffered_stdout.writer();
724722 try stdout.writeAll(
725723 \\// This file is generated by tools/update_clang_options.zig.
726724 \\// zig fmt: off
......@@ -815,7 +813,7 @@ pub fn main() anyerror!void {
815813 \\
816814 );
817815
818 try buffered_stdout.flush();
816 try stdout.flush();
819817}
820818
821819// TODO we should be able to import clang_options.zig but currently this is problematic because it will
......@@ -966,13 +964,17 @@ fn objectLessThan(context: void, a: *json.ObjectMap, b: *json.ObjectMap) bool {
966964 return std.mem.lessThan(u8, a_key, b_key);
967965}
968966
969fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn {
970 file.writer().print(
967fn printUsageAndExit(arg0: []const u8) noreturn {
968 printUsage(std.debug.lockStderrWriter(&.{}), arg0) catch std.process.exit(2);
969 std.process.exit(1);
970}
971
972fn printUsage(w: *std.io.Writer, arg0: []const u8) std.io.Writer.Error!void {
973 try w.print(
971974 \\Usage: {s} /path/to/llvm-tblgen /path/to/git/llvm/llvm-project
972975 \\Alternative Usage: zig run /path/to/git/zig/tools/update_clang_options.zig -- /path/to/llvm-tblgen /path/to/git/llvm/llvm-project
973976 \\
974977 \\Prints to stdout Zig code which you can use to replace the file src/clang_options_data.zig.
975978 \\
976 , .{arg0}) catch std.process.exit(1);
977 std.process.exit(code);
979 , .{arg0});
978980}
tools/update_cpu_features.zig+2-2
......@@ -2082,8 +2082,8 @@ fn processOneTarget(job: Job) void {
20822082}
20832083
20842084fn usageAndExit(arg0: []const u8, code: u8) noreturn {
2085 const stderr = std.io.getStdErr();
2086 stderr.writer().print(
2085 const stderr = std.debug.lockStderrWriter(&.{});
2086 stderr.print(
20872087 \\Usage: {s} /path/to/llvm-tblgen /path/git/llvm-project /path/git/zig [zig_name filter]
20882088 \\
20892089 \\Updates lib/std/target/<target>.zig from llvm/lib/Target/<Target>/<Target>.td .
tools/update_crc_catalog.zig+10-10
......@@ -11,14 +11,10 @@ pub fn main() anyerror!void {
1111 const arena = arena_state.allocator();
1212
1313 const args = try std.process.argsAlloc(arena);
14 if (args.len <= 1) {
15 usageAndExit(std.io.getStdErr(), args[0], 1);
16 }
14 if (args.len <= 1) printUsageAndExit(args[0]);
1715
1816 const zig_src_root = args[1];
19 if (mem.startsWith(u8, zig_src_root, "-")) {
20 usageAndExit(std.io.getStdErr(), args[0], 1);
21 }
17 if (mem.startsWith(u8, zig_src_root, "-")) printUsageAndExit(args[0]);
2218
2319 var zig_src_dir = try fs.cwd().openDir(zig_src_root, .{});
2420 defer zig_src_dir.close();
......@@ -193,10 +189,14 @@ pub fn main() anyerror!void {
193189 }
194190}
195191
196fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn {
197 file.writer().print(
192fn printUsageAndExit(arg0: []const u8) noreturn {
193 printUsage(std.debug.lockStderrWriter(&.{}), arg0) catch std.process.exit(2);
194 std.process.exit(1);
195}
196
197fn printUsage(w: *std.io.Writer, arg0: []const u8) std.io.Writer.Error!void {
198 return w.print(
198199 \\Usage: {s} /path/git/zig
199200 \\
200 , .{arg0}) catch std.process.exit(1);
201 std.process.exit(code);
201 , .{arg0});
202202}