Skip to content

Commit 8a58185

Browse files
authored
Make invalidFmtError public and use in place of compileErrors for bad format strings (#13526)
* Export invalidFmtErr To allow consistent use of "invalid format string" compile error response for badly formatted format strings. See #13489 (comment). * Replace format compile errors with invalidFmtErr - Provides more consistent compile errors. - Gives user info about the type of the badly formated value. * Rename invalidFmtErr as invalidFmtError For consistency. Zig seems to use “Error” more often than “Err”. * std: add invalid format string checks to remaining custom formatters * pass reference-trace to comp when building build file; fix checkobjectstep
1 parent 32b97df commit 8a58185

18 files changed

+52
-43
lines changed

lib/std/SemanticVersion.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ pub fn format(
157157
out_stream: anytype,
158158
) !void {
159159
_ = options;
160-
if (fmt.len != 0) @compileError("Unknown format string: '" ++ fmt ++ "'");
160+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
161161
try std.fmt.format(out_stream, "{d}.{d}.{d}", .{ self.major, self.minor, self.patch });
162162
if (self.pre) |pre| try std.fmt.format(out_stream, "-{s}", .{pre});
163163
if (self.build) |build| try std.fmt.format(out_stream, "+{s}", .{build});

lib/std/build/CheckObjectStep.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ const ComputeCompareExpected = struct {
187187
options: std.fmt.FormatOptions,
188188
writer: anytype,
189189
) !void {
190-
_ = fmt;
190+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, value);
191191
_ = options;
192192
try writer.print("{s} ", .{@tagName(value.op)});
193193
switch (value.value) {
@@ -360,7 +360,7 @@ fn make(step: *Step) !void {
360360
std.debug.print(
361361
\\
362362
\\========= Comparison failed for action: ===========
363-
\\{s} {s}
363+
\\{s} {}
364364
\\========= From parsed file: =======================
365365
\\{s}
366366
\\

lib/std/builtin.zig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ pub const StackTrace = struct {
3838
options: std.fmt.FormatOptions,
3939
writer: anytype,
4040
) !void {
41+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
42+
4143
// TODO: re-evaluate whether to use format() methods at all.
4244
// Until then, avoid an error when using GeneralPurposeAllocator with WebAssembly
4345
// where it tries to call detectTTYConfig here.
4446
if (builtin.os.tag == .freestanding) return;
4547

46-
_ = fmt;
4748
_ = options;
4849
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
4950
defer arena.deinit();
@@ -534,7 +535,7 @@ pub const Version = struct {
534535
return std.fmt.format(out_stream, "{d}.{d}.{d}", .{ self.major, self.minor, self.patch });
535536
}
536537
} else {
537-
@compileError("Unknown format string: '" ++ fmt ++ "'");
538+
std.fmt.invalidFmtError(fmt, self);
538539
}
539540
}
540541
};

lib/std/debug.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2123,7 +2123,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
21232123
options: std.fmt.FormatOptions,
21242124
writer: anytype,
21252125
) !void {
2126-
_ = fmt;
2126+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, t);
21272127
_ = options;
21282128
if (enabled) {
21292129
try writer.writeAll("\n");

lib/std/fmt.zig

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ fn stripOptionalOrErrorUnionSpec(comptime fmt: []const u8) []const u8 {
454454
fmt[1..];
455455
}
456456

457-
fn invalidFmtErr(comptime fmt: []const u8, value: anytype) void {
457+
pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) void {
458458
@compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
459459
}
460460

@@ -486,11 +486,11 @@ pub fn formatType(
486486
return formatValue(value, actual_fmt, options, writer);
487487
},
488488
.Void => {
489-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
489+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
490490
return formatBuf("void", options, writer);
491491
},
492492
.Bool => {
493-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
493+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
494494
return formatBuf(if (value) "true" else "false", options, writer);
495495
},
496496
.Optional => {
@@ -514,14 +514,14 @@ pub fn formatType(
514514
}
515515
},
516516
.ErrorSet => {
517-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
517+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
518518
try writer.writeAll("error.");
519519
return writer.writeAll(@errorName(value));
520520
},
521521
.Enum => |enumInfo| {
522522
try writer.writeAll(@typeName(T));
523523
if (enumInfo.is_exhaustive) {
524-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
524+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
525525
try writer.writeAll(".");
526526
try writer.writeAll(@tagName(value));
527527
return;
@@ -542,7 +542,7 @@ pub fn formatType(
542542
try writer.writeAll(")");
543543
},
544544
.Union => |info| {
545-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
545+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
546546
try writer.writeAll(@typeName(T));
547547
if (max_depth == 0) {
548548
return writer.writeAll("{ ... }");
@@ -562,7 +562,7 @@ pub fn formatType(
562562
}
563563
},
564564
.Struct => |info| {
565-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
565+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
566566
if (info.is_tuple) {
567567
// Skip the type and field names when formatting tuples.
568568
if (max_depth == 0) {
@@ -618,7 +618,7 @@ pub fn formatType(
618618
}
619619
return;
620620
}
621-
invalidFmtErr(fmt, value);
621+
invalidFmtError(fmt, value);
622622
},
623623
.Enum, .Union, .Struct => {
624624
return formatType(value.*, actual_fmt, options, writer, max_depth);
@@ -640,7 +640,7 @@ pub fn formatType(
640640
else => {},
641641
}
642642
}
643-
invalidFmtErr(fmt, value);
643+
invalidFmtError(fmt, value);
644644
},
645645
.Slice => {
646646
if (actual_fmt.len == 0)
@@ -703,20 +703,20 @@ pub fn formatType(
703703
try writer.writeAll(" }");
704704
},
705705
.Fn => {
706-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
706+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
707707
return format(writer, "{s}@{x}", .{ @typeName(T), @ptrToInt(value) });
708708
},
709709
.Type => {
710-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
710+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
711711
return formatBuf(@typeName(value), options, writer);
712712
},
713713
.EnumLiteral => {
714-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
714+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
715715
const buffer = [_]u8{'.'} ++ @tagName(value);
716716
return formatBuf(buffer, options, writer);
717717
},
718718
.Null => {
719-
if (actual_fmt.len != 0) invalidFmtErr(fmt, value);
719+
if (actual_fmt.len != 0) invalidFmtError(fmt, value);
720720
return formatBuf("null", options, writer);
721721
},
722722
else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"),
@@ -786,7 +786,7 @@ pub fn formatIntValue(
786786
radix = 8;
787787
case = .lower;
788788
} else {
789-
invalidFmtErr(fmt, value);
789+
invalidFmtError(fmt, value);
790790
}
791791

792792
return formatInt(int_value, radix, case, options, writer);
@@ -815,7 +815,7 @@ fn formatFloatValue(
815815
error.NoSpaceLeft => unreachable,
816816
};
817817
} else {
818-
invalidFmtErr(fmt, value);
818+
invalidFmtError(fmt, value);
819819
}
820820

821821
return formatBuf(buf_stream.getWritten(), options, writer);

lib/std/fs/wasi.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub const PreopenType = union(PreopenTypeTag) {
6262
}
6363

6464
pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: anytype) !void {
65-
_ = fmt;
65+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
6666
_ = options;
6767
try out_stream.print("PreopenType{{ ", .{});
6868
switch (self) {

lib/std/heap/general_purpose_allocator.zig

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
326326
const slot_index = @intCast(SlotIndex, used_bits_byte * 8 + bit_index);
327327
const stack_trace = bucketStackTrace(bucket, size_class, slot_index, .alloc);
328328
const addr = bucket.page + slot_index * size_class;
329-
log.err("memory address 0x{x} leaked: {s}", .{
329+
log.err("memory address 0x{x} leaked: {}", .{
330330
@ptrToInt(addr), stack_trace,
331331
});
332332
leaks = true;
@@ -358,7 +358,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
358358
while (it.next()) |large_alloc| {
359359
if (config.retain_metadata and large_alloc.freed) continue;
360360
const stack_trace = large_alloc.getStackTrace(.alloc);
361-
log.err("memory address 0x{x} leaked: {s}", .{
361+
log.err("memory address 0x{x} leaked: {}", .{
362362
@ptrToInt(large_alloc.bytes.ptr), stack_trace,
363363
});
364364
leaks = true;
@@ -443,7 +443,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
443443
.index = 0,
444444
};
445445
std.debug.captureStackTrace(ret_addr, &second_free_stack_trace);
446-
log.err("Double free detected. Allocation: {s} First free: {s} Second free: {s}", .{
446+
log.err("Double free detected. Allocation: {} First free: {} Second free: {}", .{
447447
alloc_stack_trace, free_stack_trace, second_free_stack_trace,
448448
});
449449
}
@@ -533,7 +533,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
533533
.index = 0,
534534
};
535535
std.debug.captureStackTrace(ret_addr, &free_stack_trace);
536-
log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {s} Free: {s}", .{
536+
log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{
537537
entry.value_ptr.bytes.len,
538538
old_mem.len,
539539
entry.value_ptr.getStackTrace(.alloc),
@@ -606,7 +606,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
606606
.index = 0,
607607
};
608608
std.debug.captureStackTrace(ret_addr, &free_stack_trace);
609-
log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {s} Free: {s}", .{
609+
log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{
610610
entry.value_ptr.bytes.len,
611611
old_mem.len,
612612
entry.value_ptr.getStackTrace(.alloc),

lib/std/math/big/int.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2061,7 +2061,7 @@ pub const Const = struct {
20612061
radix = 16;
20622062
case = .upper;
20632063
} else {
2064-
@compileError("Unknown format string: '" ++ fmt ++ "'");
2064+
std.fmt.invalidFmtError(fmt, self);
20652065
}
20662066

20672067
var limbs: [128]Limb = undefined;

lib/std/net.zig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ pub const Address = extern union {
149149
options: std.fmt.FormatOptions,
150150
out_stream: anytype,
151151
) !void {
152+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
152153
switch (self.any.family) {
153154
os.AF.INET => try self.in.format(fmt, options, out_stream),
154155
os.AF.INET6 => try self.in6.format(fmt, options, out_stream),
@@ -274,7 +275,7 @@ pub const Ip4Address = extern struct {
274275
options: std.fmt.FormatOptions,
275276
out_stream: anytype,
276277
) !void {
277-
_ = fmt;
278+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
278279
_ = options;
279280
const bytes = @ptrCast(*const [4]u8, &self.sa.addr);
280281
try std.fmt.format(out_stream, "{}.{}.{}.{}:{}", .{
@@ -563,7 +564,7 @@ pub const Ip6Address = extern struct {
563564
options: std.fmt.FormatOptions,
564565
out_stream: anytype,
565566
) !void {
566-
_ = fmt;
567+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
567568
_ = options;
568569
const port = mem.bigToNative(u16, self.sa.port);
569570
if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {

lib/std/os/uefi.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub const Guid = extern struct {
6868
fmt(std.mem.asBytes(&self.node)),
6969
});
7070
} else {
71-
@compileError("Unknown format character: '" ++ f ++ "'");
71+
std.fmt.invalidFmtError(f, self);
7272
}
7373
}
7474

lib/std/target.zig

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,19 +167,21 @@ pub const Target = struct {
167167
_: std.fmt.FormatOptions,
168168
out_stream: anytype,
169169
) !void {
170-
if (fmt.len > 0 and fmt[0] == 's') {
170+
if (comptime std.mem.eql(u8, fmt, "s")) {
171171
if (@enumToInt(self) >= @enumToInt(WindowsVersion.nt4) and @enumToInt(self) <= @enumToInt(WindowsVersion.latest)) {
172172
try std.fmt.format(out_stream, ".{s}", .{@tagName(self)});
173173
} else {
174174
// TODO this code path breaks zig triples, but it is used in `builtin`
175175
try std.fmt.format(out_stream, "@intToEnum(Target.Os.WindowsVersion, 0x{X:0>8})", .{@enumToInt(self)});
176176
}
177-
} else {
177+
} else if (fmt.len == 0) {
178178
if (@enumToInt(self) >= @enumToInt(WindowsVersion.nt4) and @enumToInt(self) <= @enumToInt(WindowsVersion.latest)) {
179179
try std.fmt.format(out_stream, "WindowsVersion.{s}", .{@tagName(self)});
180180
} else {
181181
try std.fmt.format(out_stream, "WindowsVersion(0x{X:0>8})", .{@enumToInt(self)});
182182
}
183+
} else {
184+
std.fmt.invalidFmtError(fmt, self);
183185
}
184186
}
185187
};

lib/std/testing.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
700700
error.OutOfMemory => {
701701
if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) {
702702
print(
703-
"\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {s}",
703+
"\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {}",
704704
.{
705705
fail_index,
706706
needed_alloc_count,

lib/std/wasm.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ pub const Type = struct {
356356
returns: []const Valtype,
357357

358358
pub fn format(self: Type, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
359-
_ = fmt;
359+
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
360360
_ = opt;
361361
try writer.writeByte('(');
362362
for (self.params) |param, i| {

lib/std/x/net/bpf.zig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,7 @@ pub const Insn = extern struct {
282282
writer: anytype,
283283
) !void {
284284
_ = opts;
285-
if (comptime layout.len != 0 and layout[0] != 's')
286-
@compileError("Unsupported format specifier for BPF Insn type '" ++ layout ++ "'.");
285+
if (layout.len != 0) std.fmt.invalidFmtError(layout, self);
287286

288287
try std.fmt.format(
289288
writer,

lib/std/x/net/ip.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ pub const Address = union(enum) {
4747
opts: fmt.FormatOptions,
4848
writer: anytype,
4949
) !void {
50+
if (layout.len != 0) std.fmt.invalidFmtError(layout, self);
5051
_ = opts;
51-
_ = layout;
5252
switch (self) {
5353
.ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
5454
.ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),

lib/std/x/os/net.zig

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,7 @@ pub const IPv4 = extern struct {
168168
writer: anytype,
169169
) !void {
170170
_ = opts;
171-
if (comptime layout.len != 0 and layout[0] != 's') {
172-
@compileError("Unsupported format specifier for IPv4 type '" ++ layout ++ "'.");
173-
}
171+
if (layout.len != 0) std.fmt.invalidFmtError(layout, self);
174172

175173
try fmt.format(writer, "{}.{}.{}.{}", .{
176174
self.octets[0],
@@ -382,7 +380,7 @@ pub const IPv6 = extern struct {
382380
'x', 'X' => |specifier| specifier,
383381
's' => 'x',
384382
'S' => 'X',
385-
else => @compileError("Unsupported format specifier for IPv6 type '" ++ layout ++ "'."),
383+
else => std.fmt.invalidFmtError(layout, self),
386384
}};
387385

388386
if (mem.startsWith(u8, &self.octets, &v4_mapped_prefix)) {

lib/std/x/os/socket.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ pub const Socket = struct {
127127
opts: fmt.FormatOptions,
128128
writer: anytype,
129129
) !void {
130+
if (layout.len != 0) std.fmt.invalidFmtError(layout, self);
130131
_ = opts;
131-
_ = layout;
132132
switch (self) {
133133
.ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
134134
.ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),

0 commit comments

Comments
 (0)