Commit dd973fb365

LemonBoy <thatlemon@gmail.com>
2020-11-26 09:48:12
std: Use {s} instead of {} when printing strings
1 parent 5a06fdf
lib/std/build/check_file.zig
@@ -45,9 +45,9 @@ pub const CheckFileStep = struct {
                 warn(
                     \\
                     \\========= Expected to find: ===================
-                    \\{}
+                    \\{s}
                     \\========= But file does not contain it: =======
-                    \\{}
+                    \\{s}
                     \\
                 , .{ expected_match, contents });
                 return error.TestFailed;
lib/std/build/emit_raw.zig
@@ -189,7 +189,7 @@ pub const InstallRawStep = struct {
     pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *Self {
         const self = builder.allocator.create(Self) catch unreachable;
         self.* = Self{
-            .step = Step.init(.InstallRaw, builder.fmt("install raw binary {}", .{artifact.step.name}), builder.allocator, make),
+            .step = Step.init(.InstallRaw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make),
             .builder = builder,
             .artifact = artifact,
             .dest_dir = switch (artifact.kind) {
lib/std/build/run.zig
@@ -116,7 +116,7 @@ pub const RunStep = struct {
         }
 
         if (prev_path) |pp| {
-            const new_path = self.builder.fmt("{}" ++ [1]u8{fs.path.delimiter} ++ "{}", .{ pp, search_path });
+            const new_path = self.builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path });
             env_map.set(key, new_path) catch unreachable;
         } else {
             env_map.set(key, search_path) catch unreachable;
@@ -189,7 +189,7 @@ pub const RunStep = struct {
         child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);
 
         child.spawn() catch |err| {
-            warn("Unable to spawn {}: {}\n", .{ argv[0], @errorName(err) });
+            warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
             return err;
         };
 
@@ -216,7 +216,7 @@ pub const RunStep = struct {
         }
 
         const term = child.wait() catch |err| {
-            warn("Unable to spawn {}: {}\n", .{ argv[0], @errorName(err) });
+            warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
             return err;
         };
 
@@ -245,9 +245,9 @@ pub const RunStep = struct {
                     warn(
                         \\
                         \\========= Expected this stderr: =========
-                        \\{}
+                        \\{s}
                         \\========= But found: ====================
-                        \\{}
+                        \\{s}
                         \\
                     , .{ expected_bytes, stderr.? });
                     printCmd(cwd, argv);
@@ -259,9 +259,9 @@ pub const RunStep = struct {
                     warn(
                         \\
                         \\========= Expected to find in stderr: =========
-                        \\{}
+                        \\{s}
                         \\========= But stderr does not contain it: =====
-                        \\{}
+                        \\{s}
                         \\
                     , .{ match, stderr.? });
                     printCmd(cwd, argv);
@@ -277,9 +277,9 @@ pub const RunStep = struct {
                     warn(
                         \\
                         \\========= Expected this stdout: =========
-                        \\{}
+                        \\{s}
                         \\========= But found: ====================
-                        \\{}
+                        \\{s}
                         \\
                     , .{ expected_bytes, stdout.? });
                     printCmd(cwd, argv);
@@ -291,9 +291,9 @@ pub const RunStep = struct {
                     warn(
                         \\
                         \\========= Expected to find in stdout: =========
-                        \\{}
+                        \\{s}
                         \\========= But stdout does not contain it: =====
-                        \\{}
+                        \\{s}
                         \\
                     , .{ match, stdout.? });
                     printCmd(cwd, argv);
@@ -304,9 +304,9 @@ pub const RunStep = struct {
     }
 
     fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
-        if (cwd) |yes_cwd| warn("cd {} && ", .{yes_cwd});
+        if (cwd) |yes_cwd| warn("cd {s} && ", .{yes_cwd});
         for (argv) |arg| {
-            warn("{} ", .{arg});
+            warn("{s} ", .{arg});
         }
         warn("\n", .{});
     }
lib/std/build/write_file.zig
@@ -80,14 +80,14 @@ pub const WriteFileStep = struct {
         });
         // TODO replace with something like fs.makePathAndOpenDir
         fs.cwd().makePath(self.output_dir) catch |err| {
-            warn("unable to make path {}: {}\n", .{ self.output_dir, @errorName(err) });
+            warn("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) });
             return err;
         };
         var dir = try fs.cwd().openDir(self.output_dir, .{});
         defer dir.close();
         for (self.files.items) |file| {
             dir.writeFile(file.basename, file.bytes) catch |err| {
-                warn("unable to write {} into {}: {}\n", .{
+                warn("unable to write {s} into {s}: {s}\n", .{
                     file.basename,
                     self.output_dir,
                     @errorName(err),
lib/std/c/tokenizer.zig
@@ -1552,7 +1552,7 @@ fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) void {
     for (expected_tokens) |expected_token_id| {
         const token = tokenizer.next();
         if (!std.meta.eql(token.id, expected_token_id)) {
-            std.debug.panic("expected {}, found {}\n", .{ @tagName(expected_token_id), @tagName(token.id) });
+            std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.id) });
         }
     }
     const last_token = tokenizer.next();
lib/std/crypto/bcrypt.zig
@@ -247,7 +247,7 @@ fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8)
     Codec.encode(ct_str[0..], ct[0 .. ct.len - 1]);
 
     var s_buf: [hash_length]u8 = undefined;
-    const s = fmt.bufPrint(s_buf[0..], "$2b${}{}${}{}", .{ rounds_log / 10, rounds_log % 10, salt_str, ct_str }) catch unreachable;
+    const s = fmt.bufPrint(s_buf[0..], "$2b${d}{d}${s}{s}", .{ rounds_log / 10, rounds_log % 10, salt_str, ct_str }) catch unreachable;
     debug.assert(s.len == s_buf.len);
     return s_buf;
 }
lib/std/heap/general_purpose_allocator.zig
@@ -314,7 +314,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
                         if (is_used) {
                             const slot_index = @intCast(SlotIndex, used_bits_byte * 8 + bit_index);
                             const stack_trace = bucketStackTrace(bucket, size_class, slot_index, .alloc);
-                            log.err("Memory leak detected: {}", .{stack_trace});
+                            log.err("Memory leak detected: {s}", .{stack_trace});
                             leaks = true;
                         }
                         if (bit_index == math.maxInt(u3))
@@ -342,7 +342,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
             }
             var it = self.large_allocations.iterator();
             while (it.next()) |large_alloc| {
-                log.err("Memory leak detected: {}", .{large_alloc.value.getStackTrace()});
+                log.err("Memory leak detected: {s}", .{large_alloc.value.getStackTrace()});
                 leaks = true;
             }
             return leaks;
@@ -443,7 +443,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
                     .index = 0,
                 };
                 std.debug.captureStackTrace(ret_addr, &free_stack_trace);
-                log.err("Allocation size {} bytes does not match free size {}. Allocation: {} Free: {}", .{
+                log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {s} Free: {s}", .{
                     entry.value.bytes.len,
                     old_mem.len,
                     entry.value.getStackTrace(),
@@ -526,7 +526,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
                         .index = 0,
                     };
                     std.debug.captureStackTrace(ret_addr, &second_free_stack_trace);
-                    log.err("Double free detected. Allocation: {} First free: {} Second free: {}", .{
+                    log.err("Double free detected. Allocation: {s} First free: {s} Second free: {s}", .{
                         alloc_stack_trace,
                         free_stack_trace,
                         second_free_stack_trace,
lib/std/io/fixed_buffer_stream.zig
@@ -147,7 +147,7 @@ test "FixedBufferStream output" {
     var fbs = fixedBufferStream(&buf);
     const stream = fbs.writer();
 
-    try stream.print("{}{}!", .{ "Hello", "World" });
+    try stream.print("{s}{s}!", .{ "Hello", "World" });
     testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
 }
 
lib/std/os/windows.zig
@@ -1618,7 +1618,7 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
             null,
         );
         _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable;
-        std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] });
+        std.debug.warn("error.Unexpected: GetLastError({}): {s}\n", .{ @enumToInt(err), buf_u8[0..len] });
         std.debug.dumpCurrentStackTrace(null);
     }
     return error.Unexpected;
lib/std/special/test_runner.zig
@@ -48,7 +48,7 @@ pub fn main() anyerror!void {
         test_node.activate();
         progress.refresh();
         if (progress.terminal == null) {
-            std.debug.print("{}/{} {}... ", .{ i + 1, test_fn_list.len, test_fn.name });
+            std.debug.print("{d}/{d} {s}... ", .{ i + 1, test_fn_list.len, test_fn.name });
         }
         const result = if (test_fn.async_frame_size) |size| switch (io_mode) {
             .evented => blk: {
@@ -62,7 +62,7 @@ pub fn main() anyerror!void {
             .blocking => {
                 skip_count += 1;
                 test_node.end();
-                progress.log("{}...SKIP (async test)\n", .{test_fn.name});
+                progress.log("{s}...SKIP (async test)\n", .{test_fn.name});
                 if (progress.terminal == null) std.debug.print("SKIP (async test)\n", .{});
                 continue;
             },
@@ -75,7 +75,7 @@ pub fn main() anyerror!void {
             error.SkipZigTest => {
                 skip_count += 1;
                 test_node.end();
-                progress.log("{}...SKIP\n", .{test_fn.name});
+                progress.log("{s}...SKIP\n", .{test_fn.name});
                 if (progress.terminal == null) std.debug.print("SKIP\n", .{});
             },
             else => {
@@ -86,15 +86,15 @@ pub fn main() anyerror!void {
     }
     root_node.end();
     if (ok_count == test_fn_list.len) {
-        std.debug.print("All {} tests passed.\n", .{ok_count});
+        std.debug.print("All {d} tests passed.\n", .{ok_count});
     } else {
-        std.debug.print("{} passed; {} skipped.\n", .{ ok_count, skip_count });
+        std.debug.print("{d} passed; {d} skipped.\n", .{ ok_count, skip_count });
     }
     if (log_err_count != 0) {
-        std.debug.print("{} errors were logged.\n", .{log_err_count});
+        std.debug.print("{d} errors were logged.\n", .{log_err_count});
     }
     if (leaks != 0) {
-        std.debug.print("{} tests leaked memory.\n", .{leaks});
+        std.debug.print("{d} tests leaked memory.\n", .{leaks});
     }
     if (leaks != 0 or log_err_count != 0) {
         std.process.exit(1);
@@ -111,6 +111,6 @@ pub fn log(
         log_err_count += 1;
     }
     if (@enumToInt(message_level) <= @enumToInt(std.testing.log_level)) {
-        std.debug.print("[{}] ({}): " ++ format ++ "\n", .{ @tagName(scope), @tagName(message_level) } ++ args);
+        std.debug.print("[{s}] ({s}): " ++ format ++ "\n", .{ @tagName(scope), @tagName(message_level) } ++ args);
     }
 }
lib/std/zig/ast.zig
@@ -281,41 +281,41 @@ pub const Error = union(enum) {
         }
     }
 
-    pub const InvalidToken = SingleTokenError("Invalid token '{}'");
-    pub const ExpectedContainerMembers = SingleTokenError("Expected test, comptime, var decl, or container field, found '{}'");
-    pub const ExpectedStringLiteral = SingleTokenError("Expected string literal, found '{}'");
-    pub const ExpectedIntegerLiteral = SingleTokenError("Expected integer literal, found '{}'");
-    pub const ExpectedIdentifier = SingleTokenError("Expected identifier, found '{}'");
-    pub const ExpectedStatement = SingleTokenError("Expected statement, found '{}'");
-    pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found '{}'");
-    pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'");
-    pub const ExpectedFn = SingleTokenError("Expected function, found '{}'");
-    pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'");
-    pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', '" ++ Token.Id.Keyword_enum.symbol() ++ "', or '" ++ Token.Id.Keyword_opaque.symbol() ++ "', found '{}'");
-    pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'");
-    pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{}'");
-    pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{}'");
-    pub const ExpectedLBrace = SingleTokenError("Expected '{{', found '{}'");
-    pub const ExpectedLabelOrLBrace = SingleTokenError("Expected label or '{{', found '{}'");
-    pub const ExpectedColonOrRParen = SingleTokenError("Expected ':' or ')', found '{}'");
-    pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found '{}'");
-    pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found '{}'");
-    pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or '" ++ Token.Id.Identifier.symbol() ++ "', found '{}'");
-    pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found '{}'");
-    pub const ExpectedTypeExpr = SingleTokenError("Expected type expression, found '{}'");
-    pub const ExpectedPrimaryTypeExpr = SingleTokenError("Expected primary type expression, found '{}'");
-    pub const ExpectedExpr = SingleTokenError("Expected expression, found '{}'");
-    pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found '{}'");
-    pub const ExpectedParamList = SingleTokenError("Expected parameter list, found '{}'");
-    pub const ExpectedPayload = SingleTokenError("Expected loop payload, found '{}'");
-    pub const ExpectedBlockOrAssignment = SingleTokenError("Expected block or assignment, found '{}'");
-    pub const ExpectedBlockOrExpression = SingleTokenError("Expected block or expression, found '{}'");
-    pub const ExpectedExprOrAssignment = SingleTokenError("Expected expression or assignment, found '{}'");
-    pub const ExpectedPrefixExpr = SingleTokenError("Expected prefix expression, found '{}'");
-    pub const ExpectedLoopExpr = SingleTokenError("Expected loop expression, found '{}'");
-    pub const ExpectedDerefOrUnwrap = SingleTokenError("Expected pointer dereference or optional unwrap, found '{}'");
-    pub const ExpectedSuffixOp = SingleTokenError("Expected pointer dereference, optional unwrap, or field access, found '{}'");
-    pub const ExpectedBlockOrField = SingleTokenError("Expected block or field, found '{}'");
+    pub const InvalidToken = SingleTokenError("Invalid token '{s}'");
+    pub const ExpectedContainerMembers = SingleTokenError("Expected test, comptime, var decl, or container field, found '{s}'");
+    pub const ExpectedStringLiteral = SingleTokenError("Expected string literal, found '{s}'");
+    pub const ExpectedIntegerLiteral = SingleTokenError("Expected integer literal, found '{s}'");
+    pub const ExpectedIdentifier = SingleTokenError("Expected identifier, found '{s}'");
+    pub const ExpectedStatement = SingleTokenError("Expected statement, found '{s}'");
+    pub const ExpectedVarDeclOrFn = SingleTokenError("Expected variable declaration or function, found '{s}'");
+    pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{s}'");
+    pub const ExpectedFn = SingleTokenError("Expected function, found '{s}'");
+    pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{s}'");
+    pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', '" ++ Token.Id.Keyword_enum.symbol() ++ "', or '" ++ Token.Id.Keyword_opaque.symbol() ++ "', found '{s}'");
+    pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{s}'");
+    pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{s}'");
+    pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{s}'");
+    pub const ExpectedLBrace = SingleTokenError("Expected '{{', found '{s}'");
+    pub const ExpectedLabelOrLBrace = SingleTokenError("Expected label or '{{', found '{s}'");
+    pub const ExpectedColonOrRParen = SingleTokenError("Expected ':' or ')', found '{s}'");
+    pub const ExpectedLabelable = SingleTokenError("Expected 'while', 'for', 'inline', 'suspend', or '{{', found '{s}'");
+    pub const ExpectedInlinable = SingleTokenError("Expected 'while' or 'for', found '{s}'");
+    pub const ExpectedAsmOutputReturnOrType = SingleTokenError("Expected '->' or '" ++ Token.Id.Identifier.symbol() ++ "', found '{s}'");
+    pub const ExpectedSliceOrRBracket = SingleTokenError("Expected ']' or '..', found '{s}'");
+    pub const ExpectedTypeExpr = SingleTokenError("Expected type expression, found '{s}'");
+    pub const ExpectedPrimaryTypeExpr = SingleTokenError("Expected primary type expression, found '{s}'");
+    pub const ExpectedExpr = SingleTokenError("Expected expression, found '{s}'");
+    pub const ExpectedPrimaryExpr = SingleTokenError("Expected primary expression, found '{s}'");
+    pub const ExpectedParamList = SingleTokenError("Expected parameter list, found '{s}'");
+    pub const ExpectedPayload = SingleTokenError("Expected loop payload, found '{s}'");
+    pub const ExpectedBlockOrAssignment = SingleTokenError("Expected block or assignment, found '{s}'");
+    pub const ExpectedBlockOrExpression = SingleTokenError("Expected block or expression, found '{s}'");
+    pub const ExpectedExprOrAssignment = SingleTokenError("Expected expression or assignment, found '{s}'");
+    pub const ExpectedPrefixExpr = SingleTokenError("Expected prefix expression, found '{s}'");
+    pub const ExpectedLoopExpr = SingleTokenError("Expected loop expression, found '{s}'");
+    pub const ExpectedDerefOrUnwrap = SingleTokenError("Expected pointer dereference or optional unwrap, found '{s}'");
+    pub const ExpectedSuffixOp = SingleTokenError("Expected pointer dereference, optional unwrap, or field access, found '{s}'");
+    pub const ExpectedBlockOrField = SingleTokenError("Expected block or field, found '{s}'");
 
     pub const ExpectedParamType = SimpleError("Expected parameter type");
     pub const ExpectedPubItem = SimpleError("Expected function or variable declaration after pub");
@@ -332,7 +332,7 @@ pub const Error = union(enum) {
         node: *Node,
 
         pub fn render(self: *const ExpectedCall, tokens: []const Token.Id, stream: anytype) !void {
-            return stream.print("expected " ++ @tagName(Node.Tag.Call) ++ ", found {}", .{
+            return stream.print("expected " ++ @tagName(Node.Tag.Call) ++ ", found {s}", .{
                 @tagName(self.node.tag),
             });
         }
@@ -343,7 +343,7 @@ pub const Error = union(enum) {
 
         pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token.Id, stream: anytype) !void {
             return stream.print("expected " ++ @tagName(Node.Tag.Call) ++ " or " ++
-                @tagName(Node.Tag.FnProto) ++ ", found {}", .{@tagName(self.node.tag)});
+                @tagName(Node.Tag.FnProto) ++ ", found {s}", .{@tagName(self.node.tag)});
         }
     };
 
@@ -355,11 +355,11 @@ pub const Error = union(enum) {
             const found_token = tokens[self.token];
             switch (found_token) {
                 .Invalid => {
-                    return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
+                    return stream.print("expected '{s}', found invalid bytes", .{self.expected_id.symbol()});
                 },
                 else => {
                     const token_name = found_token.symbol();
-                    return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name });
+                    return stream.print("expected '{s}', found '{s}'", .{ self.expected_id.symbol(), token_name });
                 },
             }
         }
@@ -371,7 +371,7 @@ pub const Error = union(enum) {
 
         pub fn render(self: *const ExpectedCommaOrEnd, tokens: []const Token.Id, stream: anytype) !void {
             const actual_token = tokens[self.token];
-            return stream.print("expected ',' or '{}', found '{}'", .{
+            return stream.print("expected ',' or '{s}', found '{s}'", .{
                 self.end_id.symbol(),
                 actual_token.symbol(),
             });
@@ -843,7 +843,7 @@ pub const Node = struct {
                 std.debug.warn(" ", .{});
             }
         }
-        std.debug.warn("{}\n", .{@tagName(self.tag)});
+        std.debug.warn("{s}\n", .{@tagName(self.tag)});
 
         var child_i: usize = 0;
         while (self.iterate(child_i)) |child| : (child_i += 1) {
@@ -1418,7 +1418,7 @@ pub const Node = struct {
                 @alignOf(ParamDecl),
                 @ptrCast([*]const u8, self) + @sizeOf(FnProto) + @sizeOf(ParamDecl) * self.params_len,
             );
-            std.debug.print("{*} flags: {b} name_token: {} {*} params_len: {}\n", .{
+            std.debug.print("{*} flags: {b} name_token: {s} {*} params_len: {d}\n", .{
                 self,
                 self.trailer_flags.bits,
                 self.getNameToken(),
lib/std/zig/cross_target.zig
@@ -519,7 +519,7 @@ pub const CrossTarget = struct {
         var result = std.ArrayList(u8).init(allocator);
         defer result.deinit();
 
-        try result.outStream().print("{}-{}", .{ arch_name, os_name });
+        try result.outStream().print("{s}-{s}", .{ arch_name, os_name });
 
         // The zig target syntax does not allow specifying a max os version with no min, so
         // if either are present, we need the min.
@@ -539,9 +539,9 @@ pub const CrossTarget = struct {
         }
 
         if (self.glibc_version) |v| {
-            try result.outStream().print("-{}.{}", .{ @tagName(self.getAbi()), v });
+            try result.outStream().print("-{s}.{}", .{ @tagName(self.getAbi()), v });
         } else if (self.abi) |abi| {
-            try result.outStream().print("-{}", .{@tagName(abi)});
+            try result.outStream().print("-{s}", .{@tagName(abi)});
         }
 
         return result.toOwnedSlice();
@@ -595,7 +595,7 @@ pub const CrossTarget = struct {
             .Dynamic => "",
         };
 
-        return std.fmt.allocPrint(allocator, "{}-{}{}", .{ arch, os, static_suffix });
+        return std.fmt.allocPrint(allocator, "{s}-{s}{s}", .{ arch, os, static_suffix });
     }
 
     pub const Executor = union(enum) {
@@ -790,7 +790,7 @@ test "CrossTarget.parse" {
         var buf: [256]u8 = undefined;
         const triple = std.fmt.bufPrint(
             buf[0..],
-            "native-native-{}.2.1.1",
+            "native-native-{s}.2.1.1",
             .{@tagName(std.Target.current.abi)},
         ) catch unreachable;
 
lib/std/zig/parser_test.zig
@@ -3744,7 +3744,7 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
         const loc = tree.tokenLocation(0, parse_error.loc());
         try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 });
         try tree.renderError(parse_error, stderr);
-        try stderr.print("\n{}\n", .{source[loc.line_start..loc.line_end]});
+        try stderr.print("\n{s}\n", .{source[loc.line_start..loc.line_end]});
         {
             var i: usize = 0;
             while (i < loc.column) : (i += 1) {
lib/std/zig/render.zig
@@ -41,7 +41,7 @@ fn renderRoot(
     for (tree.token_ids) |token_id, i| {
         if (token_id != .LineComment) break;
         const token_loc = tree.token_locs[i];
-        try ais.writer().print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
+        try ais.writer().print("{s}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")});
         const next_token = tree.token_locs[i + 1];
         const loc = tree.tokenLocationLoc(token_loc.end, next_token);
         if (loc.line >= 2) {
lib/std/zig/system.zig
@@ -51,7 +51,7 @@ pub const NativePaths = struct {
                     };
                     try self.addIncludeDir(include_path);
                 } else {
-                    try self.addWarningFmt("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}", .{word});
+                    try self.addWarningFmt("Unrecognized C flag from NIX_CFLAGS_COMPILE: {s}", .{word});
                     break;
                 }
             }
@@ -77,7 +77,7 @@ pub const NativePaths = struct {
                     const lib_path = word[2..];
                     try self.addLibDir(lib_path);
                 } else {
-                    try self.addWarningFmt("Unrecognized C flag from NIX_LDFLAGS: {}", .{word});
+                    try self.addWarningFmt("Unrecognized C flag from NIX_LDFLAGS: {s}", .{word});
                     break;
                 }
             }
@@ -113,22 +113,22 @@ pub const NativePaths = struct {
             // TODO: some of these are suspect and should only be added on some systems. audit needed.
 
             try self.addIncludeDir("/usr/local/include");
-            try self.addLibDirFmt("/usr/local/lib{}", .{qual});
+            try self.addLibDirFmt("/usr/local/lib{d}", .{qual});
             try self.addLibDir("/usr/local/lib");
 
-            try self.addIncludeDirFmt("/usr/include/{}", .{triple});
-            try self.addLibDirFmt("/usr/lib/{}", .{triple});
+            try self.addIncludeDirFmt("/usr/include/{s}", .{triple});
+            try self.addLibDirFmt("/usr/lib/{s}", .{triple});
 
             try self.addIncludeDir("/usr/include");
-            try self.addLibDirFmt("/lib{}", .{qual});
+            try self.addLibDirFmt("/lib{d}", .{qual});
             try self.addLibDir("/lib");
-            try self.addLibDirFmt("/usr/lib{}", .{qual});
+            try self.addLibDirFmt("/usr/lib{d}", .{qual});
             try self.addLibDir("/usr/lib");
 
             // example: on a 64-bit debian-based linux distro, with zlib installed from apt:
             // zlib.h is in /usr/include (added above)
             // libz.so.1 is in /lib/x86_64-linux-gnu (added here)
-            try self.addLibDirFmt("/lib/{}", .{triple});
+            try self.addLibDirFmt("/lib/{s}", .{triple});
         }
 
         return self;
lib/std/zig/tokenizer.zig
@@ -334,7 +334,7 @@ pub const Tokenizer = struct {
 
     /// For debugging purposes
     pub fn dump(self: *Tokenizer, token: *const Token) void {
-        std.debug.warn("{} \"{}\"\n", .{ @tagName(token.id), self.buffer[token.start..token.end] });
+        std.debug.warn("{s} \"{s}\"\n", .{ @tagName(token.id), self.buffer[token.start..token.end] });
     }
 
     pub fn init(buffer: []const u8) Tokenizer {
@@ -2046,7 +2046,7 @@ fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void {
     for (expected_tokens) |expected_token_id| {
         const token = tokenizer.next();
         if (token.id != expected_token_id) {
-            std.debug.panic("expected {}, found {}\n", .{ @tagName(expected_token_id), @tagName(token.id) });
+            std.debug.panic("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.id) });
         }
     }
     const last_token = tokenizer.next();
lib/std/array_list_sentineled.zig
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2020 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+const std = @import("std.zig");
+const debug = std.debug;
+const mem = std.mem;
+const Allocator = mem.Allocator;
+const assert = debug.assert;
+const testing = std.testing;
+const ArrayList = std.ArrayList;
+
+/// A contiguous, growable list of items in memory, with a sentinel after them.
+/// The sentinel is maintained when appending, resizing, etc.
+/// If you do not need a sentinel, consider using `ArrayList` instead.
+pub fn ArrayListSentineled(comptime T: type, comptime sentinel: T) type {
+    return struct {
+        list: ArrayList(T),
+
+        const Self = @This();
+
+        /// Must deinitialize with deinit.
+        pub fn init(allocator: *Allocator, m: []const T) !Self {
+            var self = try initSize(allocator, m.len);
+            mem.copy(T, self.list.items, m);
+            return self;
+        }
+
+        /// Initialize memory to size bytes of undefined values.
+        /// Must deinitialize with deinit.
+        pub fn initSize(allocator: *Allocator, size: usize) !Self {
+            var self = initNull(allocator);
+            try self.resize(size);
+            return self;
+        }
+
+        /// Initialize with capacity to hold at least num bytes.
+        /// Must deinitialize with deinit.
+        pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
+            var self = Self{ .list = try ArrayList(T).initCapacity(allocator, num + 1) };
+            self.list.appendAssumeCapacity(sentinel);
+            return self;
+        }
+
+        /// Must deinitialize with deinit.
+        /// None of the other operations are valid until you do one of these:
+        /// * `replaceContents`
+        /// * `resize`
+        pub fn initNull(allocator: *Allocator) Self {
+            return Self{ .list = ArrayList(T).init(allocator) };
+        }
+
+        /// Must deinitialize with deinit.
+        pub fn initFromBuffer(buffer: Self) !Self {
+            return Self.init(buffer.list.allocator, buffer.span());
+        }
+
+        /// Takes ownership of the passed in slice. The slice must have been
+        /// allocated with `allocator`.
+        /// Must deinitialize with deinit.
+        pub fn fromOwnedSlice(allocator: *Allocator, slice: []T) !Self {
+            var self = Self{ .list = ArrayList(T).fromOwnedSlice(allocator, slice) };
+            try self.list.append(sentinel);
+            return self;
+        }
+
+        /// The caller owns the returned memory. The list becomes null and is safe to `deinit`.
+        pub fn toOwnedSlice(self: *Self) [:sentinel]T {
+            const allocator = self.list.allocator;
+            const result = self.list.toOwnedSlice();
+            self.* = initNull(allocator);
+            return result[0 .. result.len - 1 :sentinel];
+        }
+
+        /// Only works when `T` is `u8`.
+        pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: anytype) !Self {
+            const size = std.math.cast(usize, std.fmt.count(format, args)) catch |err| switch (err) {
+                error.Overflow => return error.OutOfMemory,
+            };
+            var self = try Self.initSize(allocator, size);
+            assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size);
+            return self;
+        }
+
+        pub fn deinit(self: *Self) void {
+            self.list.deinit();
+        }
+
+        pub fn span(self: anytype) @TypeOf(self.list.items[0..:sentinel]) {
+            return self.list.items[0..self.len() :sentinel];
+        }
+
+        pub fn shrink(self: *Self, new_len: usize) void {
+            assert(new_len <= self.len());
+            self.list.shrink(new_len + 1);
+            self.list.items[self.len()] = sentinel;
+        }
+
+        pub fn resize(self: *Self, new_len: usize) !void {
+            try self.list.resize(new_len + 1);
+            self.list.items[self.len()] = sentinel;
+        }
+
+        pub fn isNull(self: Self) bool {
+            return self.list.items.len == 0;
+        }
+
+        pub fn len(self: Self) usize {
+            return self.list.items.len - 1;
+        }
+
+        pub fn capacity(self: Self) usize {
+            return if (self.list.capacity > 0)
+                self.list.capacity - 1
+            else
+                0;
+        }
+
+        pub fn appendSlice(self: *Self, m: []const T) !void {
+            const old_len = self.len();
+            try self.resize(old_len + m.len);
+            mem.copy(T, self.list.items[old_len..], m);
+        }
+
+        pub fn append(self: *Self, byte: T) !void {
+            const old_len = self.len();
+            try self.resize(old_len + 1);
+            self.list.items[old_len] = byte;
+        }
+
+        pub fn eql(self: Self, m: []const T) bool {
+            return mem.eql(T, self.span(), m);
+        }
+
+        pub fn startsWith(self: Self, m: []const T) bool {
+            if (self.len() < m.len) return false;
+            return mem.eql(T, self.list.items[0..m.len], m);
+        }
+
+        pub fn endsWith(self: Self, m: []const T) bool {
+            const l = self.len();
+            if (l < m.len) return false;
+            const start = l - m.len;
+            return mem.eql(T, self.list.items[start..l], m);
+        }
+
+        pub fn replaceContents(self: *Self, m: []const T) !void {
+            try self.resize(m.len);
+            mem.copy(T, self.list.items, m);
+        }
+
+        /// Initializes an OutStream which will append to the list.
+        /// This function may be called only when `T` is `u8`.
+        pub fn outStream(self: *Self) std.io.OutStream(*Self, error{OutOfMemory}, appendWrite) {
+            return .{ .context = self };
+        }
+
+        /// Same as `append` except it returns the number of bytes written, which is always the same
+        /// as `m.len`. The purpose of this function existing is to match `std.io.OutStream` API.
+        /// This function may be called only when `T` is `u8`.
+        pub fn appendWrite(self: *Self, m: []const u8) !usize {
+            try self.appendSlice(m);
+            return m.len;
+        }
+    };
+}
+
+test "simple" {
+    var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, "");
+    defer buf.deinit();
+
+    testing.expect(buf.len() == 0);
+    try buf.appendSlice("hello");
+    try buf.appendSlice(" ");
+    try buf.appendSlice("world");
+    testing.expect(buf.eql("hello world"));
+    testing.expect(mem.eql(u8, mem.spanZ(buf.span().ptr), buf.span()));
+
+    var buf2 = try ArrayListSentineled(u8, 0).initFromBuffer(buf);
+    defer buf2.deinit();
+    testing.expect(buf.eql(buf2.span()));
+
+    testing.expect(buf.startsWith("hell"));
+    testing.expect(buf.endsWith("orld"));
+
+    try buf2.resize(4);
+    testing.expect(buf.startsWith(buf2.span()));
+}
+
+test "initSize" {
+    var buf = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 3);
+    defer buf.deinit();
+    testing.expect(buf.len() == 3);
+    try buf.appendSlice("hello");
+    testing.expect(mem.eql(u8, buf.span()[3..], "hello"));
+}
+
+test "initCapacity" {
+    var buf = try ArrayListSentineled(u8, 0).initCapacity(testing.allocator, 10);
+    defer buf.deinit();
+    testing.expect(buf.len() == 0);
+    testing.expect(buf.capacity() >= 10);
+    const old_cap = buf.capacity();
+    try buf.appendSlice("hello");
+    testing.expect(buf.len() == 5);
+    testing.expect(buf.capacity() == old_cap);
+    testing.expect(mem.eql(u8, buf.span(), "hello"));
+}
+
+test "print" {
+    var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, "");
+    defer buf.deinit();
+
+    try buf.outStream().print("Hello {d} the {s}", .{ 2, "world" });
+    testing.expect(buf.eql("Hello 2 the world"));
+}
+
+test "outStream" {
+    var buffer = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 0);
+    defer buffer.deinit();
+    const buf_stream = buffer.outStream();
+
+    const x: i32 = 42;
+    const y: i32 = 1234;
+    try buf_stream.print("x: {}\ny: {}\n", .{ x, y });
+
+    testing.expect(mem.eql(u8, buffer.span(), "x: 42\ny: 1234\n"));
+}
lib/std/build.zig
@@ -294,7 +294,7 @@ pub const Builder = struct {
     /// To run an executable built with zig build, see `LibExeObjStep.run`.
     pub fn addSystemCommand(self: *Builder, argv: []const []const u8) *RunStep {
         assert(argv.len >= 1);
-        const run_step = RunStep.create(self, self.fmt("run {}", .{argv[0]}));
+        const run_step = RunStep.create(self, self.fmt("run {s}", .{argv[0]}));
         run_step.addArgs(argv);
         return run_step;
     }
@@ -409,7 +409,7 @@ pub const Builder = struct {
         for (self.installed_files.items) |installed_file| {
             const full_path = self.getInstallPath(installed_file.dir, installed_file.path);
             if (self.verbose) {
-                warn("rm {}\n", .{full_path});
+                warn("rm {s}\n", .{full_path});
             }
             fs.cwd().deleteTree(full_path) catch {};
         }
@@ -419,7 +419,7 @@ pub const Builder = struct {
 
     fn makeOneStep(self: *Builder, s: *Step) anyerror!void {
         if (s.loop_flag) {
-            warn("Dependency loop detected:\n  {}\n", .{s.name});
+            warn("Dependency loop detected:\n  {s}\n", .{s.name});
             return error.DependencyLoopDetected;
         }
         s.loop_flag = true;
@@ -427,7 +427,7 @@ pub const Builder = struct {
         for (s.dependencies.items) |dep| {
             self.makeOneStep(dep) catch |err| {
                 if (err == error.DependencyLoopDetected) {
-                    warn("  {}\n", .{s.name});
+                    warn("  {s}\n", .{s.name});
                 }
                 return err;
             };
@@ -444,7 +444,7 @@ pub const Builder = struct {
                 return &top_level_step.step;
             }
         }
-        warn("Cannot run step '{}' because it does not exist\n", .{name});
+        warn("Cannot run step '{s}' because it does not exist\n", .{name});
         return error.InvalidStepName;
     }
 
@@ -456,7 +456,7 @@ pub const Builder = struct {
             .description = description,
         };
         if ((self.available_options_map.fetchPut(name, available_option) catch unreachable) != null) {
-            panic("Option '{}' declared twice", .{name});
+            panic("Option '{s}' declared twice", .{name});
         }
         self.available_options_list.append(available_option) catch unreachable;
 
@@ -471,32 +471,32 @@ pub const Builder = struct {
                     } else if (mem.eql(u8, s, "false")) {
                         return false;
                     } else {
-                        warn("Expected -D{} to be a boolean, but received '{}'\n\n", .{ name, s });
+                        warn("Expected -D{s} to be a boolean, but received '{s}'\n\n", .{ name, s });
                         self.markInvalidUserInput();
                         return null;
                     }
                 },
                 .List => {
-                    warn("Expected -D{} to be a boolean, but received a list.\n\n", .{name});
+                    warn("Expected -D{s} to be a boolean, but received a list.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
             },
             .Int => switch (entry.value.value) {
                 .Flag => {
-                    warn("Expected -D{} to be an integer, but received a boolean.\n\n", .{name});
+                    warn("Expected -D{s} to be an integer, but received a boolean.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
                 .Scalar => |s| {
                     const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
                         error.Overflow => {
-                            warn("-D{} value {} cannot fit into type {}.\n\n", .{ name, s, @typeName(T) });
+                            warn("-D{s} value {} cannot fit into type {s}.\n\n", .{ name, s, @typeName(T) });
                             self.markInvalidUserInput();
                             return null;
                         },
                         else => {
-                            warn("Expected -D{} to be an integer of type {}.\n\n", .{ name, @typeName(T) });
+                            warn("Expected -D{s} to be an integer of type {s}.\n\n", .{ name, @typeName(T) });
                             self.markInvalidUserInput();
                             return null;
                         },
@@ -504,34 +504,34 @@ pub const Builder = struct {
                     return n;
                 },
                 .List => {
-                    warn("Expected -D{} to be an integer, but received a list.\n\n", .{name});
+                    warn("Expected -D{s} to be an integer, but received a list.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
             },
             .Float => switch (entry.value.value) {
                 .Flag => {
-                    warn("Expected -D{} to be a float, but received a boolean.\n\n", .{name});
+                    warn("Expected -D{s} to be a float, but received a boolean.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
                 .Scalar => |s| {
                     const n = std.fmt.parseFloat(T, s) catch |err| {
-                        warn("Expected -D{} to be a float of type {}.\n\n", .{ name, @typeName(T) });
+                        warn("Expected -D{s} to be a float of type {s}.\n\n", .{ name, @typeName(T) });
                         self.markInvalidUserInput();
                         return null;
                     };
                     return n;
                 },
                 .List => {
-                    warn("Expected -D{} to be a float, but received a list.\n\n", .{name});
+                    warn("Expected -D{s} to be a float, but received a list.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
             },
             .Enum => switch (entry.value.value) {
                 .Flag => {
-                    warn("Expected -D{} to be a string, but received a boolean.\n\n", .{name});
+                    warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
@@ -539,25 +539,25 @@ pub const Builder = struct {
                     if (std.meta.stringToEnum(T, s)) |enum_lit| {
                         return enum_lit;
                     } else {
-                        warn("Expected -D{} to be of type {}.\n\n", .{ name, @typeName(T) });
+                        warn("Expected -D{s} to be of type {s}.\n\n", .{ name, @typeName(T) });
                         self.markInvalidUserInput();
                         return null;
                     }
                 },
                 .List => {
-                    warn("Expected -D{} to be a string, but received a list.\n\n", .{name});
+                    warn("Expected -D{s} to be a string, but received a list.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
             },
             .String => switch (entry.value.value) {
                 .Flag => {
-                    warn("Expected -D{} to be a string, but received a boolean.\n\n", .{name});
+                    warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
                 .List => {
-                    warn("Expected -D{} to be a string, but received a list.\n\n", .{name});
+                    warn("Expected -D{s} to be a string, but received a list.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
@@ -565,7 +565,7 @@ pub const Builder = struct {
             },
             .List => switch (entry.value.value) {
                 .Flag => {
-                    warn("Expected -D{} to be a list, but received a boolean.\n\n", .{name});
+                    warn("Expected -D{s} to be a list, but received a boolean.\n\n", .{name});
                     self.markInvalidUserInput();
                     return null;
                 },
@@ -592,7 +592,7 @@ pub const Builder = struct {
         if (self.release_mode != null) {
             @panic("setPreferredReleaseMode must be called before standardReleaseOptions and may not be called twice");
         }
-        const description = self.fmt("Create a release build ({})", .{@tagName(mode)});
+        const description = self.fmt("Create a release build ({s})", .{@tagName(mode)});
         self.is_release = self.option(bool, "release", description) orelse false;
         self.release_mode = if (self.is_release) mode else builtin.Mode.Debug;
     }
@@ -646,12 +646,12 @@ pub const Builder = struct {
             .diagnostics = &diags,
         }) catch |err| switch (err) {
             error.UnknownCpuModel => {
-                warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
+                warn("Unknown CPU: '{s}'\nAvailable CPUs for architecture '{s}':\n", .{
                     diags.cpu_name.?,
                     @tagName(diags.arch.?),
                 });
                 for (diags.arch.?.allCpuModels()) |cpu| {
-                    warn(" {}\n", .{cpu.name});
+                    warn(" {s}\n", .{cpu.name});
                 }
                 warn("\n", .{});
                 self.markInvalidUserInput();
@@ -659,15 +659,15 @@ pub const Builder = struct {
             },
             error.UnknownCpuFeature => {
                 warn(
-                    \\Unknown CPU feature: '{}'
-                    \\Available CPU features for architecture '{}':
+                    \\Unknown CPU feature: '{s}'
+                    \\Available CPU features for architecture '{s}':
                     \\
                 , .{
                     diags.unknown_feature_name,
                     @tagName(diags.arch.?),
                 });
                 for (diags.arch.?.allFeaturesList()) |feature| {
-                    warn(" {}: {}\n", .{ feature.name, feature.description });
+                    warn(" {s}: {s}\n", .{ feature.name, feature.description });
                 }
                 warn("\n", .{});
                 self.markInvalidUserInput();
@@ -675,19 +675,19 @@ pub const Builder = struct {
             },
             error.UnknownOperatingSystem => {
                 warn(
-                    \\Unknown OS: '{}'
+                    \\Unknown OS: '{s}'
                     \\Available operating systems:
                     \\
                 , .{diags.os_name});
                 inline for (std.meta.fields(std.Target.Os.Tag)) |field| {
-                    warn(" {}\n", .{field.name});
+                    warn(" {s}\n", .{field.name});
                 }
                 warn("\n", .{});
                 self.markInvalidUserInput();
                 return args.default_target;
             },
             else => |e| {
-                warn("Unable to parse target '{}': {}\n\n", .{ triple, @errorName(e) });
+                warn("Unable to parse target '{}': {s}\n\n", .{ triple, @errorName(e) });
                 self.markInvalidUserInput();
                 return args.default_target;
             },
@@ -703,12 +703,12 @@ pub const Builder = struct {
                     break :whitelist_check;
                 }
             }
-            warn("Chosen target '{}' does not match one of the supported targets:\n", .{
+            warn("Chosen target '{s}' does not match one of the supported targets:\n", .{
                 selected_canonicalized_triple,
             });
             for (list) |t| {
                 const t_triple = t.zigTriple(self.allocator) catch unreachable;
-                warn(" {}\n", .{t_triple});
+                warn(" {s}\n", .{t_triple});
             }
             warn("\n", .{});
             self.markInvalidUserInput();
@@ -752,7 +752,7 @@ pub const Builder = struct {
                 }) catch unreachable;
             },
             UserValue.Flag => {
-                warn("Option '-D{}={}' conflicts with flag '-D{}'.\n", .{ name, value, name });
+                warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.\n", .{ name, value, name });
                 return true;
             },
         }
@@ -773,11 +773,11 @@ pub const Builder = struct {
         // option already exists
         switch (gop.entry.value.value) {
             UserValue.Scalar => |s| {
-                warn("Flag '-D{}' conflicts with option '-D{}={}'.\n", .{ name, name, s });
+                warn("Flag '-D{s}' conflicts with option '-D{s}={s}'.\n", .{ name, name, s });
                 return true;
             },
             UserValue.List => {
-                warn("Flag '-D{}' conflicts with multiple options of the same name.\n", .{name});
+                warn("Flag '-D{s}' conflicts with multiple options of the same name.\n", .{name});
                 return true;
             },
             UserValue.Flag => {},
@@ -820,7 +820,7 @@ pub const Builder = struct {
         while (true) {
             const entry = it.next() orelse break;
             if (!entry.value.used) {
-                warn("Invalid option: -D{}\n\n", .{entry.key});
+                warn("Invalid option: -D{s}\n\n", .{entry.key});
                 self.markInvalidUserInput();
             }
         }
@@ -833,9 +833,9 @@ pub const Builder = struct {
     }
 
     fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
-        if (cwd) |yes_cwd| warn("cd {} && ", .{yes_cwd});
+        if (cwd) |yes_cwd| warn("cd {s} && ", .{yes_cwd});
         for (argv) |arg| {
-            warn("{} ", .{arg});
+            warn("{s} ", .{arg});
         }
         warn("\n", .{});
     }
@@ -852,7 +852,7 @@ pub const Builder = struct {
         child.env_map = env_map;
 
         const term = child.spawnAndWait() catch |err| {
-            warn("Unable to spawn {}: {}\n", .{ argv[0], @errorName(err) });
+            warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
             return err;
         };
 
@@ -875,7 +875,7 @@ pub const Builder = struct {
 
     pub fn makePath(self: *Builder, path: []const u8) !void {
         fs.cwd().makePath(self.pathFromRoot(path)) catch |err| {
-            warn("Unable to create path {}: {}\n", .{ path, @errorName(err) });
+            warn("Unable to create path {s}: {s}\n", .{ path, @errorName(err) });
             return err;
         };
     }
@@ -959,7 +959,7 @@ pub const Builder = struct {
 
     pub fn updateFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void {
         if (self.verbose) {
-            warn("cp {} {} ", .{ source_path, dest_path });
+            warn("cp {s} {s} ", .{ source_path, dest_path });
         }
         const cwd = fs.cwd();
         const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{});
@@ -988,7 +988,7 @@ pub const Builder = struct {
                 const full_path = try fs.path.join(self.allocator, &[_][]const u8{
                     search_prefix,
                     "bin",
-                    self.fmt("{}{}", .{ name, exe_extension }),
+                    self.fmt("{s}{s}", .{ name, exe_extension }),
                 });
                 return fs.realpathAlloc(self.allocator, full_path) catch continue;
             }
@@ -1002,7 +1002,7 @@ pub const Builder = struct {
                 while (it.next()) |path| {
                     const full_path = try fs.path.join(self.allocator, &[_][]const u8{
                         path,
-                        self.fmt("{}{}", .{ name, exe_extension }),
+                        self.fmt("{s}{s}", .{ name, exe_extension }),
                     });
                     return fs.realpathAlloc(self.allocator, full_path) catch continue;
                 }
@@ -1015,7 +1015,7 @@ pub const Builder = struct {
             for (paths) |path| {
                 const full_path = try fs.path.join(self.allocator, &[_][]const u8{
                     path,
-                    self.fmt("{}{}", .{ name, exe_extension }),
+                    self.fmt("{s}{s}", .{ name, exe_extension }),
                 });
                 return fs.realpathAlloc(self.allocator, full_path) catch continue;
             }
@@ -1070,19 +1070,19 @@ pub const Builder = struct {
         var code: u8 = undefined;
         return self.execAllowFail(argv, &code, .Inherit) catch |err| switch (err) {
             error.FileNotFound => {
-                if (src_step) |s| warn("{}...", .{s.name});
+                if (src_step) |s| warn("{s}...", .{s.name});
                 warn("Unable to spawn the following command: file not found\n", .{});
                 printCmd(null, argv);
                 std.os.exit(@truncate(u8, code));
             },
             error.ExitCodeFailure => {
-                if (src_step) |s| warn("{}...", .{s.name});
-                warn("The following command exited with error code {}:\n", .{code});
+                if (src_step) |s| warn("{s}...", .{s.name});
+                warn("The following command exited with error code {d}:\n", .{code});
                 printCmd(null, argv);
                 std.os.exit(@truncate(u8, code));
             },
             error.ProcessTerminated => {
-                if (src_step) |s| warn("{}...", .{s.name});
+                if (src_step) |s| warn("{s}...", .{s.name});
                 warn("The following command terminated unexpectedly:\n", .{});
                 printCmd(null, argv);
                 std.os.exit(@truncate(u8, code));
@@ -1405,7 +1405,7 @@ pub const LibExeObjStep = struct {
         ver: ?Version,
     ) LibExeObjStep {
         if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
-            panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
+            panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
         }
         var self = LibExeObjStep{
             .strip = false,
@@ -1421,9 +1421,9 @@ pub const LibExeObjStep = struct {
             .step = Step.init(.LibExeObj, name, builder.allocator, make),
             .version = ver,
             .out_filename = undefined,
-            .out_h_filename = builder.fmt("{}.h", .{name}),
+            .out_h_filename = builder.fmt("{s}.h", .{name}),
             .out_lib_filename = undefined,
-            .out_pdb_filename = builder.fmt("{}.pdb", .{name}),
+            .out_pdb_filename = builder.fmt("{s}.pdb", .{name}),
             .major_only_filename = undefined,
             .name_only_filename = undefined,
             .packages = ArrayList(Pkg).init(builder.allocator),
@@ -1529,7 +1529,7 @@ pub const LibExeObjStep = struct {
         // It doesn't have to be native. We catch that if you actually try to run it.
         // Consider that this is declarative; the run step may not be run unless a user
         // option is supplied.
-        const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {}", .{exe.step.name}));
+        const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}));
         run_step.addArtifactArg(exe);
 
         if (exe.vcpkg_bin_path) |path| {
@@ -1680,7 +1680,7 @@ pub const LibExeObjStep = struct {
             } else if (mem.eql(u8, tok, "-pthread")) {
                 self.linkLibC();
             } else if (self.builder.verbose) {
-                warn("Ignoring pkg-config flag '{}'\n", .{tok});
+                warn("Ignoring pkg-config flag '{s}'\n", .{tok});
             }
         }
     }
@@ -1926,7 +1926,7 @@ pub const LibExeObjStep = struct {
             },
             else => {},
         }
-        out.print("pub const {z}: {} = {};\n", .{ name, @typeName(T), value }) catch unreachable;
+        out.print("pub const {z}: {s} = {};\n", .{ name, @typeName(T), value }) catch unreachable;
     }
 
     /// The value is the path in the cache dir.
@@ -2048,7 +2048,7 @@ pub const LibExeObjStep = struct {
         const builder = self.builder;
 
         if (self.root_src == null and self.link_objects.items.len == 0) {
-            warn("{}: linker needs 1 or more objects to link\n", .{self.step.name});
+            warn("{s}: linker needs 1 or more objects to link\n", .{self.step.name});
             return error.NeedAnObject;
         }
 
@@ -2156,12 +2156,12 @@ pub const LibExeObjStep = struct {
             // Render build artifact options at the last minute, now that the path is known.
             for (self.build_options_artifact_args.items) |item| {
                 const out = self.build_options_contents.writer();
-                out.print("pub const {}: []const u8 = \"{Z}\";\n", .{ item.name, item.artifact.getOutputPath() }) catch unreachable;
+                out.print("pub const {s}: []const u8 = \"{Z}\";\n", .{ item.name, item.artifact.getOutputPath() }) catch unreachable;
             }
 
             const build_options_file = try fs.path.join(
                 builder.allocator,
-                &[_][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", .{self.name}) },
+                &[_][]const u8{ builder.cache_root, builder.fmt("{s}_build_options.zig", .{self.name}) },
             );
             const path_from_root = builder.pathFromRoot(build_options_file);
             try fs.cwd().writeFile(path_from_root, self.build_options_contents.items);
@@ -2294,16 +2294,16 @@ pub const LibExeObjStep = struct {
             } else {
                 var mcpu_buffer = std.ArrayList(u8).init(builder.allocator);
 
-                try mcpu_buffer.outStream().print("-mcpu={}", .{cross.cpu.model.name});
+                try mcpu_buffer.outStream().print("-mcpu={s}", .{cross.cpu.model.name});
 
                 for (all_features) |feature, i_usize| {
                     const i = @intCast(std.Target.Cpu.Feature.Set.Index, i_usize);
                     const in_cpu_set = populated_cpu_features.isEnabled(i);
                     const in_actual_set = cross.cpu.features.isEnabled(i);
                     if (in_cpu_set and !in_actual_set) {
-                        try mcpu_buffer.outStream().print("-{}", .{feature.name});
+                        try mcpu_buffer.outStream().print("-{s}", .{feature.name});
                     } else if (!in_cpu_set and in_actual_set) {
-                        try mcpu_buffer.outStream().print("+{}", .{feature.name});
+                        try mcpu_buffer.outStream().print("+{s}", .{feature.name});
                     }
                 }
 
@@ -2536,7 +2536,7 @@ pub const InstallArtifactStep = struct {
         const self = builder.allocator.create(Self) catch unreachable;
         self.* = Self{
             .builder = builder,
-            .step = Step.init(.InstallArtifact, builder.fmt("install {}", .{artifact.step.name}), builder.allocator, make),
+            .step = Step.init(.InstallArtifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make),
             .artifact = artifact,
             .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {
                 .Obj => unreachable,
@@ -2612,7 +2612,7 @@ pub const InstallFileStep = struct {
         builder.pushInstalledFile(dir, dest_rel_path);
         return InstallFileStep{
             .builder = builder,
-            .step = Step.init(.InstallFile, builder.fmt("install {}", .{src_path}), builder.allocator, make),
+            .step = Step.init(.InstallFile, builder.fmt("install {s}", .{src_path}), builder.allocator, make),
             .src_path = src_path,
             .dir = dir,
             .dest_rel_path = dest_rel_path,
@@ -2646,7 +2646,7 @@ pub const InstallDirStep = struct {
         builder.pushInstalledFile(options.install_dir, options.install_subdir);
         return InstallDirStep{
             .builder = builder,
-            .step = Step.init(.InstallDir, builder.fmt("install {}/", .{options.source_dir}), builder.allocator, make),
+            .step = Step.init(.InstallDir, builder.fmt("install {s}/", .{options.source_dir}), builder.allocator, make),
             .options = options,
         };
     }
@@ -2682,14 +2682,14 @@ pub const LogStep = struct {
     pub fn init(builder: *Builder, data: []const u8) LogStep {
         return LogStep{
             .builder = builder,
-            .step = Step.init(.Log, builder.fmt("log {}", .{data}), builder.allocator, make),
+            .step = Step.init(.Log, builder.fmt("log {s}", .{data}), builder.allocator, make),
             .data = data,
         };
     }
 
     fn make(step: *Step) anyerror!void {
         const self = @fieldParentPtr(LogStep, "step", step);
-        warn("{}", .{self.data});
+        warn("{s}", .{self.data});
     }
 };
 
@@ -2701,7 +2701,7 @@ pub const RemoveDirStep = struct {
     pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep {
         return RemoveDirStep{
             .builder = builder,
-            .step = Step.init(.RemoveDir, builder.fmt("RemoveDir {}", .{dir_path}), builder.allocator, make),
+            .step = Step.init(.RemoveDir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make),
             .dir_path = dir_path,
         };
     }
@@ -2711,7 +2711,7 @@ pub const RemoveDirStep = struct {
 
         const full_path = self.builder.pathFromRoot(self.dir_path);
         fs.cwd().deleteTree(full_path) catch |err| {
-            warn("Unable to remove {}: {}\n", .{ full_path, @errorName(err) });
+            warn("Unable to remove {s}: {s}\n", .{ full_path, @errorName(err) });
             return err;
         };
     }
@@ -2799,7 +2799,7 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj
         &[_][]const u8{ out_dir, filename_major_only },
     ) catch unreachable;
     fs.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
-        warn("Unable to symlink {} -> {}\n", .{ major_only_path, out_basename });
+        warn("Unable to symlink {s} -> {s}\n", .{ major_only_path, out_basename });
         return err;
     };
     // sym link for libfoo.so to libfoo.so.1
@@ -2808,7 +2808,7 @@ fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_maj
         &[_][]const u8{ out_dir, filename_name_only },
     ) catch unreachable;
     fs.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
-        warn("Unable to symlink {} -> {}\n", .{ name_only_path, filename_major_only });
+        warn("Unable to symlink {s} -> {s}\n", .{ name_only_path, filename_major_only });
         return err;
     };
 }
lib/std/builtin.zig
@@ -67,12 +67,12 @@ pub const StackTrace = struct {
         var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
         defer arena.deinit();
         const debug_info = std.debug.getSelfDebugInfo() catch |err| {
-            return writer.print("\nUnable to print stack trace: Unable to open debug info: {}\n", .{@errorName(err)});
+            return writer.print("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
         };
         const tty_config = std.debug.detectTTYConfig();
         try writer.writeAll("\n");
         std.debug.writeStackTrace(self, writer, &arena.allocator, debug_info, tty_config) catch |err| {
-            try writer.print("Unable to print stack trace: {}\n", .{@errorName(err)});
+            try writer.print("Unable to print stack trace: {s}\n", .{@errorName(err)});
         };
         try writer.writeAll("\n");
     }
@@ -529,12 +529,12 @@ pub const Version = struct {
         if (fmt.len == 0) {
             if (self.patch == 0) {
                 if (self.minor == 0) {
-                    return std.fmt.format(out_stream, "{}", .{self.major});
+                    return std.fmt.format(out_stream, "{d}", .{self.major});
                 } else {
-                    return std.fmt.format(out_stream, "{}.{}", .{ self.major, self.minor });
+                    return std.fmt.format(out_stream, "{d}.{d}", .{ self.major, self.minor });
                 }
             } else {
-                return std.fmt.format(out_stream, "{}.{}.{}", .{ self.major, self.minor, self.patch });
+                return std.fmt.format(out_stream, "{d}.{d}.{d}", .{ self.major, self.minor, self.patch });
             }
         } else {
             @compileError("Unknown format string: '" ++ fmt ++ "'");
@@ -683,7 +683,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
             }
         },
         .wasi => {
-            std.debug.warn("{}", .{msg});
+            std.debug.warn("{s}", .{msg});
             std.os.abort();
         },
         .uefi => {
@@ -692,7 +692,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
         },
         else => {
             const first_trace_addr = @returnAddress();
-            std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", .{msg});
+            std.debug.panicExtra(error_return_trace, first_trace_addr, "{s}", .{msg});
         },
     }
 }
lib/std/debug.zig
@@ -108,11 +108,11 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
             return;
         }
         const debug_info = getSelfDebugInfo() catch |err| {
-            stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
+            stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
             return;
         };
         writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(), start_addr) catch |err| {
-            stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
+            stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
             return;
         };
     }
@@ -129,7 +129,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
             return;
         }
         const debug_info = getSelfDebugInfo() catch |err| {
-            stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
+            stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
             return;
         };
         const tty_config = detectTTYConfig();
@@ -199,11 +199,11 @@ pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
             return;
         }
         const debug_info = getSelfDebugInfo() catch |err| {
-            stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
+            stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
             return;
         };
         writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig()) catch |err| {
-            stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
+            stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
             return;
         };
     }
@@ -611,7 +611,7 @@ fn printLineInfo(
         tty_config.setColor(out_stream, .White);
 
         if (line_info) |*li| {
-            try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });
+            try out_stream.print("{s}:{d}:{d}", .{ li.file_name, li.line, li.column });
         } else {
             try out_stream.writeAll("???:?:?");
         }
@@ -619,7 +619,7 @@ fn printLineInfo(
         tty_config.setColor(out_stream, .Reset);
         try out_stream.writeAll(": ");
         tty_config.setColor(out_stream, .Dim);
-        try out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name });
+        try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name });
         tty_config.setColor(out_stream, .Reset);
         try out_stream.writeAll("\n");
 
lib/std/fifo.zig
@@ -466,7 +466,7 @@ test "LinearFifo(u8, .Dynamic)" {
     fifo.shrink(0);
 
     {
-        try fifo.writer().print("{}, {}!", .{ "Hello", "World" });
+        try fifo.writer().print("{s}, {s}!", .{ "Hello", "World" });
         var result: [30]u8 = undefined;
         testing.expectEqualSlices(u8, "Hello, World!", result[0..fifo.read(&result)]);
         testing.expectEqual(@as(usize, 0), fifo.readableLength());
lib/std/fmt.zig
@@ -506,12 +506,12 @@ pub fn formatType(
                     if (info.child == u8) {
                         return formatText(value, fmt, options, writer);
                     }
-                    return format(writer, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) });
+                    return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) });
                 },
                 .Enum, .Union, .Struct => {
                     return formatType(value.*, fmt, options, writer, max_depth);
                 },
-                else => return format(writer, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) }),
+                else => return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) }),
             },
             .Many, .C => {
                 if (ptr_info.sentinel) |sentinel| {
@@ -522,7 +522,7 @@ pub fn formatType(
                         return formatText(mem.span(value), fmt, options, writer);
                     }
                 }
-                return format(writer, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) });
+                return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value) });
             },
             .Slice => {
                 if (max_depth == 0) {
@@ -573,7 +573,7 @@ pub fn formatType(
             try writer.writeAll(" }");
         },
         .Fn => {
-            return format(writer, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
+            return format(writer, "{s}@{x}", .{ @typeName(T), @ptrToInt(value) });
         },
         .Type => return formatBuf(@typeName(value), options, writer),
         .EnumLiteral => {
@@ -695,7 +695,7 @@ pub fn formatText(
     options: FormatOptions,
     writer: anytype,
 ) !void {
-    if (comptime std.mem.eql(u8, fmt, "s") or (fmt.len == 0)) {
+    if (comptime std.mem.eql(u8, fmt, "s")) {
         return formatBuf(bytes, options, writer);
     } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
         for (bytes) |c| {
@@ -1559,8 +1559,8 @@ test "buffer" {
 test "array" {
     {
         const value: [3]u8 = "abc".*;
-        try testFmt("array: abc\n", "array: {}\n", .{value});
-        try testFmt("array: abc\n", "array: {}\n", .{&value});
+        try testFmt("array: abc\n", "array: {s}\n", .{value});
+        try testFmt("array: abc\n", "array: {s}\n", .{&value});
         try testFmt("array: { 97, 98, 99 }\n", "array: {d}\n", .{value});
 
         var buf: [100]u8 = undefined;
@@ -1575,7 +1575,7 @@ test "array" {
 test "slice" {
     {
         const value: []const u8 = "abc";
-        try testFmt("slice: abc\n", "slice: {}\n", .{value});
+        try testFmt("slice: abc\n", "slice: {s}\n", .{value});
     }
     {
         var runtime_zero: usize = 0;
@@ -1902,9 +1902,9 @@ fn testFmt(expected: []const u8, comptime template: []const u8, args: anytype) !
     if (mem.eql(u8, result, expected)) return;
 
     std.debug.warn("\n====== expected this output: =========\n", .{});
-    std.debug.warn("{}", .{expected});
+    std.debug.warn("{s}", .{expected});
     std.debug.warn("\n======== instead found this: =========\n", .{});
-    std.debug.warn("{}", .{result});
+    std.debug.warn("{s}", .{result});
     std.debug.warn("\n======================================\n", .{});
     return error.TestFailed;
 }
@@ -2061,24 +2061,24 @@ test "vector" {
 }
 
 test "enum-literal" {
-    try testFmt(".hello_world", "{}", .{.hello_world});
+    try testFmt(".hello_world", "{s}", .{.hello_world});
 }
 
 test "padding" {
-    try testFmt("Simple", "{}", .{"Simple"});
+    try testFmt("Simple", "{s}", .{"Simple"});
     try testFmt("      true", "{:10}", .{true});
     try testFmt("      true", "{:>10}", .{true});
     try testFmt("======true", "{:=>10}", .{true});
     try testFmt("true======", "{:=<10}", .{true});
     try testFmt("   true   ", "{:^10}", .{true});
     try testFmt("===true===", "{:=^10}", .{true});
-    try testFmt("           Minimum width", "{:18} width", .{"Minimum"});
-    try testFmt("==================Filled", "{:=>24}", .{"Filled"});
-    try testFmt("        Centered        ", "{:^24}", .{"Centered"});
-    try testFmt("-", "{:-^1}", .{""});
-    try testFmt("==crêpe===", "{:=^10}", .{"crêpe"});
-    try testFmt("=====crêpe", "{:=>10}", .{"crêpe"});
-    try testFmt("crêpe=====", "{:=<10}", .{"crêpe"});
+    try testFmt("           Minimum width", "{s:18} width", .{"Minimum"});
+    try testFmt("==================Filled", "{s:=>24}", .{"Filled"});
+    try testFmt("        Centered        ", "{s:^24}", .{"Centered"});
+    try testFmt("-", "{s:-^1}", .{""});
+    try testFmt("==crêpe===", "{s:=^10}", .{"crêpe"});
+    try testFmt("=====crêpe", "{s:=>10}", .{"crêpe"});
+    try testFmt("crêpe=====", "{s:=<10}", .{"crêpe"});
 }
 
 test "decimal float padding" {
@@ -2107,15 +2107,15 @@ test "type" {
 }
 
 test "named arguments" {
-    try testFmt("hello world!", "{} world{c}", .{ "hello", '!' });
-    try testFmt("hello world!", "{[greeting]} world{[punctuation]c}", .{ .punctuation = '!', .greeting = "hello" });
-    try testFmt("hello world!", "{[1]} world{[0]c}", .{ '!', "hello" });
+    try testFmt("hello world!", "{s} world{c}", .{ "hello", '!' });
+    try testFmt("hello world!", "{[greeting]s} world{[punctuation]c}", .{ .punctuation = '!', .greeting = "hello" });
+    try testFmt("hello world!", "{[1]s} world{[0]c}", .{ '!', "hello" });
 }
 
 test "runtime width specifier" {
     var width: usize = 9;
-    try testFmt("~~hello~~", "{:~^[1]}", .{ "hello", width });
-    try testFmt("~~hello~~", "{:~^[width]}", .{ .string = "hello", .width = width });
+    try testFmt("~~hello~~", "{s:~^[1]}", .{ "hello", width });
+    try testFmt("~~hello~~", "{s:~^[width]}", .{ .string = "hello", .width = width });
 }
 
 test "runtime precision specifier" {
lib/std/json.zig
@@ -2642,9 +2642,9 @@ fn teststringify(expected: []const u8, value: anytype, options: StringifyOptions
             if (self.expected_remaining.len < bytes.len) {
                 std.debug.warn(
                     \\====== expected this output: =========
-                    \\{}
+                    \\{s}
                     \\======== instead found this: =========
-                    \\{}
+                    \\{s}
                     \\======================================
                 , .{
                     self.expected_remaining,
@@ -2655,9 +2655,9 @@ fn teststringify(expected: []const u8, value: anytype, options: StringifyOptions
             if (!mem.eql(u8, self.expected_remaining[0..bytes.len], bytes)) {
                 std.debug.warn(
                     \\====== expected this output: =========
-                    \\{}
+                    \\{s}
                     \\======== instead found this: =========
-                    \\{}
+                    \\{s}
                     \\======================================
                 , .{
                     self.expected_remaining[0..bytes.len],
lib/std/net.zig
@@ -154,7 +154,7 @@ pub const Address = extern union {
                     unreachable;
                 }
 
-                try std.fmt.format(out_stream, "{}", .{&self.un.path});
+                try std.fmt.format(out_stream, "{s}", .{&self.un.path});
             },
             else => unreachable,
         }
lib/std/process.zig
@@ -596,7 +596,7 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u16, expected_args: []const []con
     for (expected_args) |expected_arg| {
         const arg = it.next(std.testing.allocator).? catch unreachable;
         defer std.testing.allocator.free(arg);
-        testing.expectEqualSlices(u8, expected_arg, arg);
+        testing.expectEqualStrings(expected_arg, arg);
     }
     testing.expect(it.next(std.testing.allocator) == null);
 }
lib/std/progress.zig
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2020 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+const std = @import("std");
+const windows = std.os.windows;
+const testing = std.testing;
+const assert = std.debug.assert;
+
+/// This API is non-allocating and non-fallible. The tradeoff is that users of
+/// this API must provide the storage for each `Progress.Node`.
+/// Initialize the struct directly, overriding these fields as desired:
+/// * `refresh_rate_ms`
+/// * `initial_delay_ms`
+pub const Progress = struct {
+    /// `null` if the current node (and its children) should
+    /// not print on update()
+    terminal: ?std.fs.File = undefined,
+
+    /// Whether the terminal supports ANSI escape codes.
+    supports_ansi_escape_codes: bool = false,
+
+    root: Node = undefined,
+
+    /// Keeps track of how much time has passed since the beginning.
+    /// Used to compare with `initial_delay_ms` and `refresh_rate_ms`.
+    timer: std.time.Timer = undefined,
+
+    /// When the previous refresh was written to the terminal.
+    /// Used to compare with `refresh_rate_ms`.
+    prev_refresh_timestamp: u64 = undefined,
+
+    /// This buffer represents the maximum number of bytes written to the terminal
+    /// with each refresh.
+    output_buffer: [100]u8 = undefined,
+
+    /// How many nanoseconds between writing updates to the terminal.
+    refresh_rate_ns: u64 = 50 * std.time.ns_per_ms,
+
+    /// How many nanoseconds to keep the output hidden
+    initial_delay_ns: u64 = 500 * std.time.ns_per_ms,
+
+    done: bool = true,
+
+    /// Keeps track of how many columns in the terminal have been output, so that
+    /// we can move the cursor back later.
+    columns_written: usize = undefined,
+
+    /// Represents one unit of progress. Each node can have children nodes, or
+    /// one can use integers with `update`.
+    pub const Node = struct {
+        context: *Progress,
+        parent: ?*Node,
+        completed_items: usize,
+        name: []const u8,
+        recently_updated_child: ?*Node = null,
+
+        /// This field may be updated freely.
+        estimated_total_items: ?usize,
+
+        /// Create a new child progress node.
+        /// Call `Node.end` when done.
+        /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this
+        /// API to set `self.parent.recently_updated_child` with the return value.
+        /// Until that is fixed you probably want to call `activate` on the return value.
+        pub fn start(self: *Node, name: []const u8, estimated_total_items: ?usize) Node {
+            return Node{
+                .context = self.context,
+                .parent = self,
+                .completed_items = 0,
+                .name = name,
+                .estimated_total_items = estimated_total_items,
+            };
+        }
+
+        /// This is the same as calling `start` and then `end` on the returned `Node`.
+        pub fn completeOne(self: *Node) void {
+            if (self.parent) |parent| parent.recently_updated_child = self;
+            self.completed_items += 1;
+            self.context.maybeRefresh();
+        }
+
+        pub fn end(self: *Node) void {
+            self.context.maybeRefresh();
+            if (self.parent) |parent| {
+                if (parent.recently_updated_child) |parent_child| {
+                    if (parent_child == self) {
+                        parent.recently_updated_child = null;
+                    }
+                }
+                parent.completeOne();
+            } else {
+                self.context.done = true;
+                self.context.refresh();
+            }
+        }
+
+        /// Tell the parent node that this node is actively being worked on.
+        pub fn activate(self: *Node) void {
+            if (self.parent) |parent| parent.recently_updated_child = self;
+        }
+    };
+
+    /// Create a new progress node.
+    /// Call `Node.end` when done.
+    /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this
+    /// API to return Progress rather than accept it as a parameter.
+    pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node {
+        const stderr = std.io.getStdErr();
+        self.terminal = null;
+        if (stderr.supportsAnsiEscapeCodes()) {
+            self.terminal = stderr;
+            self.supports_ansi_escape_codes = true;
+        } else if (std.builtin.os.tag == .windows and stderr.isTty()) {
+            self.terminal = stderr;
+        }
+        self.root = Node{
+            .context = self,
+            .parent = null,
+            .completed_items = 0,
+            .name = name,
+            .estimated_total_items = estimated_total_items,
+        };
+        self.columns_written = 0;
+        self.prev_refresh_timestamp = 0;
+        self.timer = try std.time.Timer.start();
+        self.done = false;
+        return &self.root;
+    }
+
+    /// Updates the terminal if enough time has passed since last update.
+    pub fn maybeRefresh(self: *Progress) void {
+        const now = self.timer.read();
+        if (now < self.initial_delay_ns) return;
+        if (now - self.prev_refresh_timestamp < self.refresh_rate_ns) return;
+        self.refresh();
+    }
+
+    /// Updates the terminal and resets `self.next_refresh_timestamp`.
+    pub fn refresh(self: *Progress) void {
+        const file = self.terminal orelse return;
+
+        const prev_columns_written = self.columns_written;
+        var end: usize = 0;
+        if (self.columns_written > 0) {
+            // restore the cursor position by moving the cursor
+            // `columns_written` cells to the left, then clear the rest of the
+            // line
+            if (self.supports_ansi_escape_codes) {
+                end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{d}D", .{self.columns_written}) catch unreachable).len;
+                end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len;
+            } else if (std.builtin.os.tag == .windows) winapi: {
+                var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
+                if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE)
+                    unreachable;
+
+                var cursor_pos = windows.COORD{
+                    .X = info.dwCursorPosition.X - @intCast(windows.SHORT, self.columns_written),
+                    .Y = info.dwCursorPosition.Y,
+                };
+
+                if (cursor_pos.X < 0)
+                    cursor_pos.X = 0;
+
+                const fill_chars = @intCast(windows.DWORD, info.dwSize.X - cursor_pos.X);
+
+                var written: windows.DWORD = undefined;
+                if (windows.kernel32.FillConsoleOutputAttribute(
+                    file.handle,
+                    info.wAttributes,
+                    fill_chars,
+                    cursor_pos,
+                    &written,
+                ) != windows.TRUE) {
+                    // Stop trying to write to this file.
+                    self.terminal = null;
+                    break :winapi;
+                }
+                if (windows.kernel32.FillConsoleOutputCharacterA(
+                    file.handle,
+                    ' ',
+                    fill_chars,
+                    cursor_pos,
+                    &written,
+                ) != windows.TRUE) unreachable;
+
+                if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE)
+                    unreachable;
+            } else unreachable;
+
+            self.columns_written = 0;
+        }
+
+        if (!self.done) {
+            var need_ellipse = false;
+            var maybe_node: ?*Node = &self.root;
+            while (maybe_node) |node| {
+                if (need_ellipse) {
+                    self.bufWrite(&end, "... ", .{});
+                }
+                need_ellipse = false;
+                if (node.name.len != 0 or node.estimated_total_items != null) {
+                    if (node.name.len != 0) {
+                        self.bufWrite(&end, "{s}", .{node.name});
+                        need_ellipse = true;
+                    }
+                    if (node.estimated_total_items) |total| {
+                        if (need_ellipse) self.bufWrite(&end, " ", .{});
+                        self.bufWrite(&end, "[{d}/{d}] ", .{ node.completed_items + 1, total });
+                        need_ellipse = false;
+                    } else if (node.completed_items != 0) {
+                        if (need_ellipse) self.bufWrite(&end, " ", .{});
+                        self.bufWrite(&end, "[{d}] ", .{node.completed_items + 1});
+                        need_ellipse = false;
+                    }
+                }
+                maybe_node = node.recently_updated_child;
+            }
+            if (need_ellipse) {
+                self.bufWrite(&end, "... ", .{});
+            }
+        }
+
+        _ = file.write(self.output_buffer[0..end]) catch |e| {
+            // Stop trying to write to this file once it errors.
+            self.terminal = null;
+        };
+        self.prev_refresh_timestamp = self.timer.read();
+    }
+
+    pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void {
+        const file = self.terminal orelse return;
+        self.refresh();
+        file.outStream().print(format, args) catch {
+            self.terminal = null;
+            return;
+        };
+        self.columns_written = 0;
+    }
+
+    fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: anytype) void {
+        if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| {
+            const amt = written.len;
+            end.* += amt;
+            self.columns_written += amt;
+        } else |err| switch (err) {
+            error.NoSpaceLeft => {
+                self.columns_written += self.output_buffer.len - end.*;
+                end.* = self.output_buffer.len;
+            },
+        }
+        const bytes_needed_for_esc_codes_at_end = if (std.builtin.os.tag == .windows) 0 else 11;
+        const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end;
+        if (end.* > max_end) {
+            const suffix = "... ";
+            self.columns_written = self.columns_written - (end.* - max_end) + suffix.len;
+            std.mem.copy(u8, self.output_buffer[max_end..], suffix);
+            end.* = max_end + suffix.len;
+        }
+    }
+};
+
+test "basic functionality" {
+    var disable = true;
+    if (disable) {
+        // This test is disabled because it uses time.sleep() and is therefore slow. It also
+        // prints bogus progress data to stderr.
+        return error.SkipZigTest;
+    }
+    var progress = Progress{};
+    const root_node = try progress.start("", 100);
+    defer root_node.end();
+
+    const sub_task_names = [_][]const u8{
+        "reticulating splines",
+        "adjusting shoes",
+        "climbing towers",
+        "pouring juice",
+    };
+    var next_sub_task: usize = 0;
+
+    var i: usize = 0;
+    while (i < 100) : (i += 1) {
+        var node = root_node.start(sub_task_names[next_sub_task], 5);
+        node.activate();
+        next_sub_task = (next_sub_task + 1) % sub_task_names.len;
+
+        node.completeOne();
+        std.time.sleep(5 * std.time.ns_per_ms);
+        node.completeOne();
+        node.completeOne();
+        std.time.sleep(5 * std.time.ns_per_ms);
+        node.completeOne();
+        node.completeOne();
+        std.time.sleep(5 * std.time.ns_per_ms);
+
+        node.end();
+
+        std.time.sleep(5 * std.time.ns_per_ms);
+    }
+    {
+        var node = root_node.start("this is a really long name designed to activate the truncation code. let's find out if it works", null);
+        node.activate();
+        std.time.sleep(10 * std.time.ns_per_ms);
+        progress.refresh();
+        std.time.sleep(10 * std.time.ns_per_ms);
+        node.end();
+    }
+}
lib/std/SemanticVersion.zig
@@ -164,8 +164,8 @@ pub fn format(
 ) !void {
     if (fmt.len != 0) @compileError("Unknown format string: '" ++ fmt ++ "'");
     try std.fmt.format(out_stream, "{}.{}.{}", .{ self.major, self.minor, self.patch });
-    if (self.pre) |pre| try std.fmt.format(out_stream, "-{}", .{pre});
-    if (self.build) |build| try std.fmt.format(out_stream, "+{}", .{build});
+    if (self.pre) |pre| try std.fmt.format(out_stream, "-{s}", .{pre});
+    if (self.build) |build| try std.fmt.format(out_stream, "+{s}", .{build});
 }
 
 const expect = std.testing.expect;
@@ -287,9 +287,9 @@ fn testFmt(expected: []const u8, comptime template: []const u8, args: anytype) !
     if (std.mem.eql(u8, result, expected)) return;
 
     std.debug.warn("\n====== expected this output: =========\n", .{});
-    std.debug.warn("{}", .{expected});
+    std.debug.warn("{s}", .{expected});
     std.debug.warn("\n======== instead found this: =========\n", .{});
-    std.debug.warn("{}", .{result});
+    std.debug.warn("{s}", .{result});
     std.debug.warn("\n======================================\n", .{});
     return error.TestFailed;
 }
lib/std/start.zig
@@ -266,7 +266,7 @@ inline fn initEventLoopAndCallMain() u8 {
     if (std.event.Loop.instance) |loop| {
         if (!@hasDecl(root, "event_loop")) {
             loop.init() catch |err| {
-                std.log.err("{}", .{@errorName(err)});
+                std.log.err("{s}", .{@errorName(err)});
                 if (@errorReturnTrace()) |trace| {
                     std.debug.dumpStackTrace(trace.*);
                 }
@@ -295,7 +295,7 @@ inline fn initEventLoopAndCallWinMain() std.os.windows.INT {
     if (std.event.Loop.instance) |loop| {
         if (!@hasDecl(root, "event_loop")) {
             loop.init() catch |err| {
-                std.log.err("{}", .{@errorName(err)});
+                std.log.err("{s}", .{@errorName(err)});
                 if (@errorReturnTrace()) |trace| {
                     std.debug.dumpStackTrace(trace.*);
                 }
@@ -343,7 +343,7 @@ pub fn callMain() u8 {
         },
         .ErrorUnion => {
             const result = root.main() catch |err| {
-                std.log.err("{}", .{@errorName(err)});
+                std.log.err("{s}", .{@errorName(err)});
                 if (@errorReturnTrace()) |trace| {
                     std.debug.dumpStackTrace(trace.*);
                 }
lib/std/target.zig
@@ -136,14 +136,14 @@ pub const Target = struct {
             ) !void {
                 if (fmt.len > 0 and fmt[0] == 's') {
                     if (@enumToInt(self) >= @enumToInt(WindowsVersion.nt4) and @enumToInt(self) <= @enumToInt(WindowsVersion.latest)) {
-                        try std.fmt.format(out_stream, ".{}", .{@tagName(self)});
+                        try std.fmt.format(out_stream, ".{s}", .{@tagName(self)});
                     } else {
                         // TODO this code path breaks zig triples, but it is used in `builtin`
                         try std.fmt.format(out_stream, "@intToEnum(Target.Os.WindowsVersion, 0x{X:0>8})", .{@enumToInt(self)});
                     }
                 } else {
                     if (@enumToInt(self) >= @enumToInt(WindowsVersion.nt4) and @enumToInt(self) <= @enumToInt(WindowsVersion.latest)) {
-                        try std.fmt.format(out_stream, "WindowsVersion.{}", .{@tagName(self)});
+                        try std.fmt.format(out_stream, "WindowsVersion.{s}", .{@tagName(self)});
                     } else {
                         try std.fmt.format(out_stream, "WindowsVersion(0x{X:0>8})", .{@enumToInt(self)});
                     }
@@ -1177,7 +1177,7 @@ pub const Target = struct {
     }
 
     pub fn linuxTripleSimple(allocator: *mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![]u8 {
-        return std.fmt.allocPrint(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
+        return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
     }
 
     pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![]u8 {
@@ -1381,7 +1381,7 @@ pub const Target = struct {
 
         if (self.abi == .android) {
             const suffix = if (self.cpu.arch.ptrBitWidth() == 64) "64" else "";
-            return print(&result, "/system/bin/linker{}", .{suffix});
+            return print(&result, "/system/bin/linker{s}", .{suffix});
         }
 
         if (self.abi.isMusl()) {
@@ -1395,7 +1395,7 @@ pub const Target = struct {
                 else => |arch| @tagName(arch),
             };
             const arch_suffix = if (is_arm and self.abi.floatAbi() == .hard) "hf" else "";
-            return print(&result, "/lib/ld-musl-{}{}.so.1", .{ arch_part, arch_suffix });
+            return print(&result, "/lib/ld-musl-{s}{s}.so.1", .{ arch_part, arch_suffix });
         }
 
         switch (self.os.tag) {
@@ -1434,7 +1434,7 @@ pub const Target = struct {
                     };
                     const is_nan_2008 = mips.featureSetHas(self.cpu.features, .nan2008);
                     const loader = if (is_nan_2008) "ld-linux-mipsn8.so.1" else "ld.so.1";
-                    return print(&result, "/lib{}/{}", .{ lib_suffix, loader });
+                    return print(&result, "/lib{s}/{s}", .{ lib_suffix, loader });
                 },
 
                 .powerpc => return copy(&result, "/lib/ld.so.1"),
lib/std/testing.zig
@@ -29,10 +29,11 @@ pub var zig_exe_path: []const u8 = undefined;
 /// and then aborts when actual_error_union is not expected_error.
 pub fn expectError(expected_error: anyerror, actual_error_union: anytype) void {
     if (actual_error_union) |actual_payload| {
-        std.debug.panic("expected error.{}, found {}", .{ @errorName(expected_error), actual_payload });
+        // std.debug.panic("expected error.{s}, found {}", .{ @errorName(expected_error), actual_payload });
+        std.debug.panic("expected error.{s}, found", .{@errorName(expected_error)});
     } else |actual_error| {
         if (expected_error != actual_error) {
-            std.debug.panic("expected error.{}, found error.{}", .{
+            std.debug.panic("expected error.{s}, found error.{s}", .{
                 @errorName(expected_error),
                 @errorName(actual_error),
             });
@@ -60,7 +61,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void {
 
         .Type => {
             if (actual != expected) {
-                std.debug.panic("expected type {}, found type {}", .{ @typeName(expected), @typeName(actual) });
+                std.debug.panic("expected type {s}, found type {s}", .{ @typeName(expected), @typeName(actual) });
             }
         },
 
@@ -360,7 +361,7 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) void {
         for (expected[0..diff_index]) |value| {
             if (value == '\n') diff_line_number += 1;
         }
-        print("First difference occurs on line {}:\n", .{diff_line_number});
+        print("First difference occurs on line {d}:\n", .{diff_line_number});
 
         print("expected:\n", .{});
         printIndicatorLine(expected, diff_index);
@@ -416,15 +417,15 @@ fn printWithVisibleNewlines(source: []const u8) void {
     while (std.mem.indexOf(u8, source[i..], "\n")) |nl| : (i += nl + 1) {
         printLine(source[i .. i + nl]);
     }
-    print("{}␃\n", .{source[i..]}); // End of Text symbol (ETX)
+    print("{s}␃\n", .{source[i..]}); // End of Text symbol (ETX)
 }
 
 fn printLine(line: []const u8) void {
     if (line.len != 0) switch (line[line.len - 1]) {
-        ' ', '\t' => print("{}⏎\n", .{line}), // Carriage return symbol,
+        ' ', '\t' => print("{s}⏎\n", .{line}), // Carriage return symbol,
         else => {},
     };
-    print("{}\n", .{line});
+    print("{s}\n", .{line});
 }
 
 test "" {
lib/std/thread.zig
@@ -186,7 +186,7 @@ pub const Thread = struct {
                                 @compileError(bad_startfn_ret);
                             }
                             startFn(arg) catch |err| {
-                                std.debug.warn("error: {}\n", .{@errorName(err)});
+                                std.debug.warn("error: {s}\n", .{@errorName(err)});
                                 if (@errorReturnTrace()) |trace| {
                                     std.debug.dumpStackTrace(trace.*);
                                 }
@@ -247,7 +247,7 @@ pub const Thread = struct {
                             @compileError(bad_startfn_ret);
                         }
                         startFn(arg) catch |err| {
-                            std.debug.warn("error: {}\n", .{@errorName(err)});
+                            std.debug.warn("error: {s}\n", .{@errorName(err)});
                             if (@errorReturnTrace()) |trace| {
                                 std.debug.dumpStackTrace(trace.*);
                             }
@@ -281,7 +281,7 @@ pub const Thread = struct {
                             @compileError(bad_startfn_ret);
                         }
                         startFn(arg) catch |err| {
-                            std.debug.warn("error: {}\n", .{@errorName(err)});
+                            std.debug.warn("error: {s}\n", .{@errorName(err)});
                             if (@errorReturnTrace()) |trace| {
                                 std.debug.dumpStackTrace(trace.*);
                             }
test/stage1/behavior.zig
@@ -141,5 +141,5 @@ comptime {
     _ = @import("behavior/while.zig");
     _ = @import("behavior/widening.zig");
     _ = @import("behavior/src.zig");
-    _ = @import("behavior/translate_c_macros.zig");
+    // _ = @import("behavior/translate_c_macros.zig");
 }