From c25d9417d34fc7745ed50fdfe2984895657254d5 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 7 Mar 2020 15:14:47 -0500
Subject: [PATCH 001/111] fix std.fs.makeDirAbsolute
closes #4671
---
lib/std/fs.zig | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 88806f69b..3a1076d08 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -266,7 +266,7 @@ const default_new_dir_mode = 0o755;
/// Asserts that the path is absolute. See `Dir.makeDir` for a function that operates
/// on both absolute and relative paths.
pub fn makeDirAbsolute(absolute_path: []const u8) !void {
- assert(path.isAbsoluteC(absolute_path));
+ assert(path.isAbsolute(absolute_path));
return os.mkdir(absolute_path, default_new_dir_mode);
}
@@ -1669,6 +1669,8 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
}
test "" {
+ _ = makeDirAbsolute;
+ _ = makeDirAbsoluteZ;
_ = @import("fs/path.zig");
_ = @import("fs/file.zig");
_ = @import("fs/get_app_data_dir.zig");
From c5885f012a2d8785d505bb3ec03a8dfab99331d2 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 7 Mar 2020 23:37:07 +0100
Subject: [PATCH 002/111] std: Fix version detection on x86
Call xgetbv only if X{SAVE,RESTORE} and AVX are detected.
Closes #4670
---
lib/std/zig/system/x86.zig | 64 ++++++++++++++++++--------------------
1 file changed, 30 insertions(+), 34 deletions(-)
diff --git a/lib/std/zig/system/x86.zig b/lib/std/zig/system/x86.zig
index b7d2c6a22..c85b646f8 100644
--- a/lib/std/zig/system/x86.zig
+++ b/lib/std/zig/system/x86.zig
@@ -30,18 +30,15 @@ pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, cross_ta
leaf = cpuid(0x1, 0);
const brand_id = leaf.ebx & 0xff;
- var family: u32 = 0;
- var model: u32 = 0;
- { // Detect model and family
- family = (leaf.eax >> 8) & 0xf;
- model = (leaf.eax >> 4) & 0xf;
- if (family == 6 or family == 0xf) {
- if (family == 0xf) {
- family += (leaf.eax >> 20) & 0xff;
- }
- model += ((leaf.eax >> 16) & 0xf) << 4;
+ // Detect model and family
+ var family = (leaf.eax >> 8) & 0xf;
+ var model = (leaf.eax >> 4) & 0xf;
+ if (family == 6 or family == 0xf) {
+ if (family == 0xf) {
+ family += (leaf.eax >> 20) & 0xff;
}
+ model += ((leaf.eax >> 16) & 0xf) << 4;
}
// Now we detect the model.
@@ -330,11 +327,11 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
setFeature(cpu, .aes, bit(leaf.ecx, 25));
setFeature(cpu, .rdrnd, bit(leaf.ecx, 30));
- leaf.eax = getXCR0();
-
- const has_avx = bit(leaf.ecx, 27) and
+ // If the CPU supports XSAVE/XRESTORE (bit 27) and AVX (bit 28) also check
+ // if the AVX registers are saved & restored on context switch
+ const has_avx_save = bit(leaf.ecx, 27) and
bit(leaf.ecx, 28) and
- ((leaf.eax & 0x6) == 0x6);
+ ((getXCR0() & 0x6) == 0x6);
// LLVM approaches avx512_save by hardcoding it to true on Darwin,
// because the kernel saves the context even if the bit is not set.
@@ -358,14 +355,14 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
// set right now.
const has_avx512_save = switch (os_tag.isDarwin()) {
true => true,
- false => has_avx and ((leaf.eax & 0xE0) == 0xE0),
+ false => has_avx_save and ((leaf.eax & 0xE0) == 0xE0),
};
- setFeature(cpu, .avx, has_avx);
- setFeature(cpu, .fma, has_avx and bit(leaf.ecx, 12));
+ setFeature(cpu, .avx, has_avx_save);
+ setFeature(cpu, .fma, has_avx_save and bit(leaf.ecx, 12));
// Only enable XSAVE if OS has enabled support for saving YMM state.
- setFeature(cpu, .xsave, has_avx and bit(leaf.ecx, 26));
- setFeature(cpu, .f16c, has_avx and bit(leaf.ecx, 29));
+ setFeature(cpu, .xsave, has_avx_save and bit(leaf.ecx, 26));
+ setFeature(cpu, .f16c, has_avx_save and bit(leaf.ecx, 29));
leaf = cpuid(0x80000000, 0);
const max_ext_level = leaf.eax;
@@ -376,9 +373,9 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
setFeature(cpu, .lzcnt, bit(leaf.ecx, 5));
setFeature(cpu, .sse4a, bit(leaf.ecx, 6));
setFeature(cpu, .prfchw, bit(leaf.ecx, 8));
- setFeature(cpu, .xop, bit(leaf.ecx, 11) and has_avx);
+ setFeature(cpu, .xop, bit(leaf.ecx, 11) and has_avx_save);
setFeature(cpu, .lwp, bit(leaf.ecx, 15));
- setFeature(cpu, .fma4, bit(leaf.ecx, 16) and has_avx);
+ setFeature(cpu, .fma4, bit(leaf.ecx, 16) and has_avx_save);
setFeature(cpu, .tbm, bit(leaf.ecx, 21));
setFeature(cpu, .mwaitx, bit(leaf.ecx, 29));
setFeature(cpu, .@"64bit", bit(leaf.edx, 29));
@@ -409,7 +406,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
setFeature(cpu, .sgx, bit(leaf.ebx, 2));
setFeature(cpu, .bmi, bit(leaf.ebx, 3));
// AVX2 is only supported if we have the OS save support from AVX.
- setFeature(cpu, .avx2, bit(leaf.ebx, 5) and has_avx);
+ setFeature(cpu, .avx2, bit(leaf.ebx, 5) and has_avx_save);
setFeature(cpu, .bmi2, bit(leaf.ebx, 8));
setFeature(cpu, .invpcid, bit(leaf.ebx, 10));
setFeature(cpu, .rtm, bit(leaf.ebx, 11));
@@ -435,8 +432,8 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
setFeature(cpu, .avx512vbmi2, bit(leaf.ecx, 6) and has_avx512_save);
setFeature(cpu, .shstk, bit(leaf.ecx, 7));
setFeature(cpu, .gfni, bit(leaf.ecx, 8));
- setFeature(cpu, .vaes, bit(leaf.ecx, 9) and has_avx);
- setFeature(cpu, .vpclmulqdq, bit(leaf.ecx, 10) and has_avx);
+ setFeature(cpu, .vaes, bit(leaf.ecx, 9) and has_avx_save);
+ setFeature(cpu, .vpclmulqdq, bit(leaf.ecx, 10) and has_avx_save);
setFeature(cpu, .avx512vnni, bit(leaf.ecx, 11) and has_avx512_save);
setFeature(cpu, .avx512bitalg, bit(leaf.ecx, 12) and has_avx512_save);
setFeature(cpu, .avx512vpopcntdq, bit(leaf.ecx, 14) and has_avx512_save);
@@ -487,7 +484,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
}
}
- if (max_level >= 0xD and has_avx) {
+ if (max_level >= 0xD and has_avx_save) {
leaf = cpuid(0xD, 0x1);
// Only enable XSAVE if OS has enabled support for saving YMM state.
setFeature(cpu, .xsaveopt, bit(leaf.eax, 0));
@@ -518,20 +515,19 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
// Workaround for https://github.com/ziglang/zig/issues/215
// Inline assembly in zig only supports one output,
// so we pass a pointer to the struct.
- var cpuid_leaf = CpuidLeaf{ .eax = 0, .ebx = 0, .ecx = 0, .edx = 0 };
- const leaf_ptr = &cpuid_leaf;
+ var cpuid_leaf: CpuidLeaf = undefined;
// valid for both x86 and x86_64
asm volatile (
\\ cpuid
- \\ movl %%eax, (%[leaf_ptr])
+ \\ movl %%eax, 0(%[leaf_ptr])
\\ movl %%ebx, 4(%[leaf_ptr])
\\ movl %%ecx, 8(%[leaf_ptr])
\\ movl %%edx, 12(%[leaf_ptr])
:
: [leaf_id] "{eax}" (leaf_id),
[subid] "{ecx}" (subid),
- [leaf_ptr] "r" (leaf_ptr)
+ [leaf_ptr] "r" (&cpuid_leaf)
: "eax", "ebx", "ecx", "edx"
);
return cpuid_leaf;
@@ -539,11 +535,11 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
// Read control register 0 (XCR0). Used to detect features such as AVX.
fn getXCR0() u32 {
- return asm (
- \\ .byte 0x0F, 0x01, 0xD0
+ return asm volatile (
+ \\ xor %%ecx, %%ecx
+ \\ xgetbv
: [ret] "={eax}" (-> u32)
- : [number] "{eax}" (@as(u32, 0)),
- [number] "{edx}" (@as(u32, 0)),
- [number] "{ecx}" (@as(u32, 0))
+ :
+ : "eax", "edx", "ecx"
);
}
From 0720f338d4979578498aaa86766171774230a7e9 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 7 Mar 2020 19:11:03 -0500
Subject: [PATCH 003/111] add std.event.Loop pread and faccessat
progress towards std lib tests passing with evented I/O mode
---
lib/std/event/loop.zig | 78 ++++++++++++++++++++++++++++++++++++++++++
lib/std/fs.zig | 2 +-
2 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig
index e62f15d59..7db6fe98d 100644
--- a/lib/std/event/loop.zig
+++ b/lib/std/event/loop.zig
@@ -809,6 +809,28 @@ pub const Loop = struct {
return req_node.data.msg.readv.result;
}
+ /// Performs an async `os.pread` using a separate thread.
+ /// `fd` must block and not return EAGAIN.
+ pub fn pread(self: *Loop, fd: os.fd_t, buf: []u8, offset: u64) os.PReadError!usize {
+ var req_node = Request.Node{
+ .data = .{
+ .msg = .{
+ .pread = .{
+ .fd = fd,
+ .buf = buf,
+ .offset = offset,
+ .result = undefined,
+ },
+ },
+ .finish = .{ .TickNode = .{ .data = @frame() } },
+ },
+ };
+ suspend {
+ self.posixFsRequest(&req_node);
+ }
+ return req_node.data.msg.pread.result;
+ }
+
/// Performs an async `os.preadv` using a separate thread.
/// `fd` must block and not return EAGAIN.
pub fn preadv(self: *Loop, fd: os.fd_t, iov: []const os.iovec, offset: u64) os.ReadError!usize {
@@ -895,6 +917,35 @@ pub const Loop = struct {
return req_node.data.msg.pwritev.result;
}
+ /// Performs an async `os.faccessatZ` using a separate thread.
+ /// `fd` must block and not return EAGAIN.
+ pub fn faccessatZ(
+ self: *Loop,
+ dirfd: os.fd_t,
+ path_z: [*:0]const u8,
+ mode: u32,
+ flags: u32,
+ ) os.AccessError!void {
+ var req_node = Request.Node{
+ .data = .{
+ .msg = .{
+ .faccessat = .{
+ .dirfd = dirfd,
+ .path = path_z,
+ .mode = mode,
+ .flags = flags,
+ .result = undefined,
+ },
+ },
+ .finish = .{ .TickNode = .{ .data = @frame() } },
+ },
+ };
+ suspend {
+ self.posixFsRequest(&req_node);
+ }
+ return req_node.data.msg.faccessat.result;
+ }
+
fn workerRun(self: *Loop) void {
while (true) {
while (true) {
@@ -1038,6 +1089,9 @@ pub const Loop = struct {
.pwritev => |*msg| {
msg.result = noasync os.pwritev(msg.fd, msg.iov, msg.offset);
},
+ .pread => |*msg| {
+ msg.result = noasync os.pread(msg.fd, msg.buf, msg.offset);
+ },
.preadv => |*msg| {
msg.result = noasync os.preadv(msg.fd, msg.iov, msg.offset);
},
@@ -1047,6 +1101,9 @@ pub const Loop = struct {
.openat => |*msg| {
msg.result = noasync os.openatC(msg.fd, msg.path, msg.flags, msg.mode);
},
+ .faccessat => |*msg| {
+ msg.result = noasync os.faccessatZ(msg.dirfd, msg.path, msg.mode, msg.flags);
+ },
.close => |*msg| noasync os.close(msg.fd),
}
switch (node.data.finish) {
@@ -1120,10 +1177,12 @@ pub const Loop = struct {
write: Write,
writev: WriteV,
pwritev: PWriteV,
+ pread: PRead,
preadv: PReadV,
open: Open,
openat: OpenAt,
close: Close,
+ faccessat: FAccessAt,
/// special - means the fs thread should exit
end,
@@ -1161,6 +1220,15 @@ pub const Loop = struct {
pub const Error = os.PWriteError;
};
+ pub const PRead = struct {
+ fd: os.fd_t,
+ buf: []u8,
+ offset: usize,
+ result: Error!usize,
+
+ pub const Error = os.PReadError;
+ };
+
pub const PReadV = struct {
fd: os.fd_t,
iov: []const os.iovec,
@@ -1192,6 +1260,16 @@ pub const Loop = struct {
pub const Close = struct {
fd: os.fd_t,
};
+
+ pub const FAccessAt = struct {
+ dirfd: os.fd_t,
+ path: [*:0]const u8,
+ mode: u32,
+ flags: u32,
+ result: Error!void,
+
+ pub const Error = os.AccessError;
+ };
};
};
};
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 3a1076d08..1f20a14f7 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -1365,7 +1365,7 @@ pub const Dir = struct {
else
@as(u32, os.F_OK);
const result = if (need_async_thread)
- std.event.Loop.instance.?.faccessatZ(self.fd, sub_path, os_mode)
+ std.event.Loop.instance.?.faccessatZ(self.fd, sub_path, os_mode, 0)
else
os.faccessatZ(self.fd, sub_path, os_mode, 0);
return result;
From 6ac76bc25e2636bd9b2f7bb2fc5710e2aef4f8ed Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 7 Mar 2020 19:13:05 -0500
Subject: [PATCH 004/111] add missing errors to
std.os.windows.CreateDirectoryError
---
lib/std/os/windows.zig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index ba55845a4..d1201108d 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -591,6 +591,8 @@ pub const CreateDirectoryError = error{
FileNotFound,
NoDevice,
AccessDenied,
+ InvalidUtf8,
+ BadPathName,
Unexpected,
};
From cf38ce970155512577cfb0cc281d1a308af7e7e9 Mon Sep 17 00:00:00 2001
From: Jared Miller <1668550+Jared-Miller@users.noreply.github.com>
Date: Thu, 20 Feb 2020 15:25:24 -0500
Subject: [PATCH 005/111] Implement UTF-8 to UTF-16LE literal conversion
---
lib/std/unicode.zig | 68 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig
index 85c91602d..8ed51fa14 100644
--- a/lib/std/unicode.zig
+++ b/lib/std/unicode.zig
@@ -629,3 +629,71 @@ test "utf8ToUtf16LeWithNull" {
testing.expect(utf16[2] == 0);
}
}
+
+/// Converts a UTF-8 string literal into a UTF-16LE string literal.
+pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 {
+ comptime {
+ const len: usize = calcUtf16LeLen(utf8);
+ var utf16le: [len :0]u16 = [_ :0]u16{0} ** len;
+ const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);
+ assert(len == utf16le_len);
+ return &utf16le;
+ }
+}
+
+/// Returns length of a supplied UTF-8 string literal. Asserts that the data is valid UTF-8.
+fn calcUtf16LeLen(utf8: []const u8) usize {
+ var src_i: usize = 0;
+ var dest_len: usize = 0;
+ while (src_i < utf8.len) {
+ const n = utf8ByteSequenceLength(utf8[src_i]) catch unreachable;
+ const next_src_i = src_i + n;
+ const codepoint = utf8Decode(utf8[src_i..next_src_i]) catch unreachable;
+ if (codepoint < 0x10000) {
+ dest_len += 1;
+ } else {
+ dest_len += 2;
+ }
+ src_i = next_src_i;
+ }
+ return dest_len;
+}
+
+test "utf8ToUtf16LeStringLiteral" {
+{
+ const bytes = [_:0]u16{ 0x41 };
+ const utf16 = utf8ToUtf16LeStringLiteral("A");
+ testing.expectEqualSlices(u16, &bytes, utf16);
+ testing.expect(utf16[1] == 0);
+ }
+ {
+ const bytes = [_:0]u16{ 0xD801, 0xDC37 };
+ const utf16 = utf8ToUtf16LeStringLiteral("𐐷");
+ testing.expectEqualSlices(u16, &bytes, utf16);
+ testing.expect(utf16[2] == 0);
+ }
+ {
+ const bytes = [_:0]u16{ 0x02FF };
+ const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}");
+ testing.expectEqualSlices(u16, &bytes, utf16);
+ testing.expect(utf16[1] == 0);
+ }
+ {
+ const bytes = [_:0]u16{ 0x7FF };
+ const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}");
+ testing.expectEqualSlices(u16, &bytes, utf16);
+ testing.expect(utf16[1] == 0);
+ }
+ {
+ const bytes = [_:0]u16{ 0x801 };
+ const utf16 = utf8ToUtf16LeStringLiteral("\u{801}");
+ testing.expectEqualSlices(u16, &bytes, utf16);
+ testing.expect(utf16[1] == 0);
+ }
+ {
+ const bytes = [_:0]u16{ 0xDBFF, 0xDFFF };
+ const utf16 = utf8ToUtf16LeStringLiteral("\u{10FFFF}");
+ testing.expectEqualSlices(u16, &bytes, utf16);
+ testing.expect(utf16[2] == 0);
+ }
+}
From 8b80cb3072536069d745d6f0bee03ed3ea0e523a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 8 Mar 2020 03:52:52 -0400
Subject: [PATCH 006/111] Revert "translate-c remove redundant grouping, fix
nested loops without blocks."
This reverts commit abe7305e169be2047d65f96e6525d3828684f058.
---
src-self-hosted/translate_c.zig | 39 +++++++++++++++++++++++----------
test/translate_c.zig | 23 ++++---------------
2 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index 41e4665ff..b13a0d4bf 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -2237,7 +2237,6 @@ fn transWhileLoop(
.id = .Loop,
};
while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
- _ = try appendToken(rp.c, .Semicolon, ";");
return &while_node.base;
}
@@ -2347,10 +2346,8 @@ fn transForLoop(
try block_scope.?.block_node.statements.push(&while_node.base);
block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
return &block_scope.?.block_node.base;
- } else {
- _ = try appendToken(rp.c, .Semicolon, ";");
+ } else
return &while_node.base;
- }
}
fn transSwitch(
@@ -5579,7 +5576,14 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
);
return error.ParseError;
}
- const deref = try transCreateNodePtrDeref(c, node);
+ // deref is often used together with casts so we group the lhs expression
+ const group = try c.a().create(ast.Node.GroupedExpression);
+ group.* = .{
+ .lparen = try appendToken(c, .LParen, "("),
+ .expr = node,
+ .rparen = try appendToken(c, .RParen, ")"),
+ };
+ const deref = try transCreateNodePtrDeref(c, &group.base);
node = try transCreateNodeFieldAccess(c, deref, source[name_tok.start..name_tok.end]);
continue;
},
@@ -5623,7 +5627,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
},
.Ampersand => {
op_token = try appendToken(c, .Ampersand, "&");
- op_id = .BitAnd;
+ op_id .BitAnd;
},
.Plus => {
op_token = try appendToken(c, .Plus, "+");
@@ -5631,7 +5635,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
},
.Minus => {
op_token = try appendToken(c, .Minus, "-");
- op_id = .Sub;
+ op_id .Sub;
},
.AmpersandAmpersand => {
op_token = try appendToken(c, .Keyword_and, "and");
@@ -5703,7 +5707,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
},
.BangEqual => {
op_token = try appendToken(c, .BangEqual, "!=");
- op_id = .BangEqual;
+ op_id = .BangEqual;
},
.EqualEqual => {
op_token = try appendToken(c, .EqualEqual, "==");
@@ -5756,12 +5760,25 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
return &node.base;
},
.Asterisk => {
- const node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
- return try transCreateNodePtrDeref(c, node);
+ // deref is often used together with casts so we group the lhs expression
+ const group = try c.a().create(ast.Node.GroupedExpression);
+ group.* = .{
+ .lparen = try appendToken(c, .LParen, "("),
+ .expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
+ .rparen = try appendToken(c, .RParen, ")"),
+ };
+ return try transCreateNodePtrDeref(c, &group.base);
},
.Ampersand => {
+ // address of is often used together with casts so we group the rhs expression
const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&");
- node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
+ const group = try c.a().create(ast.Node.GroupedExpression);
+ group.* = .{
+ .lparen = try appendToken(c, .LParen, "("),
+ .expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
+ .rparen = try appendToken(c, .RParen, ")"),
+ };
+ node.rhs = &group.base;
return &node.base;
},
else => {
diff --git a/test/translate_c.zig b/test/translate_c.zig
index d4ee87179..01614ae9c 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -3,22 +3,6 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void {
- cases.add("nested loops without blocks",
- \\void foo() {
- \\ while (0) while (0) {}
- \\ for (;;) while (0);
- \\ for (;;) do {} while (0);
- \\}
- , &[_][]const u8{
- \\pub export fn foo() void {
- \\ while (@as(c_int, 0) != 0) while (@as(c_int, 0) != 0) {};
- \\ while (true) while (@as(c_int, 0) != 0) {};
- \\ while (true) while (true) {
- \\ if (!(@as(c_int, 0) != 0)) break;
- \\ };
- \\}
- });
-
cases.add("macro comma operator",
\\#define foo (foo, bar)
\\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))
@@ -30,7 +14,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub inline fn bar(x: var) @TypeOf(baz(1, 2)) {
\\ return blk: {
- \\ _ = &x;
+ \\ _ = &(x);
\\ _ = 3;
\\ _ = 4 == 4;
\\ _ = 5 * 6;
@@ -2009,7 +1993,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub const DOT = a.b;
,
- \\pub const ARROW = a.*.b;
+ \\pub const ARROW = (a).*.b;
});
cases.add("array access",
@@ -2778,11 +2762,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
\\*_XPrivDisplay;
\\typedef struct _XDisplay Display;
- \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
+ \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
\\
, &[_][]const u8{
\\pub inline fn DefaultScreen(dpy: var) @TypeOf((if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen) {
\\ return (if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen;
\\}
});
+
}
From 9e60c89601ab205cd3e63215b318beb89ad1b471 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 8 Mar 2020 03:53:06 -0400
Subject: [PATCH 007/111] Revert "Translate C: Group generated casts"
This reverts commit 895672b3f96aab1f5bad3446f5186a047f29412c.
---
src-self-hosted/translate_c.zig | 41 ++++-----------------------------
test/run_translated_c.zig | 18 ---------------
test/translate_c.zig | 24 ++++---------------
3 files changed, 9 insertions(+), 74 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index b13a0d4bf..d24001cf9 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -5424,15 +5424,12 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
return error.ParseError;
}
- // TODO: It might be nice if we only did the alignCasting for opaque types
- //( if (@typeInfo(@TypeOf(x)) == .Pointer)
- // @ptrCast(dest, @alignCast(@alignOf(dest.Child), x))
+ //if (@typeInfo(@TypeOf(x)) == .Pointer)
+ // @ptrCast(dest, x)
//else if (@typeInfo(@TypeOf(x)) == .Integer)
// @intToPtr(dest, x)
//else
- // @as(dest, x) )
-
- const group_lparen = try appendToken(c, .LParen, "(");
+ // @as(dest, x)
const if_1 = try transCreateNodeIf(c);
const type_id_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
@@ -5452,30 +5449,9 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
if_1.condition = &cmp_1.base;
_ = try appendToken(c, .RParen, ")");
- const period_tok = try appendToken(c, .Period, ".");
- const child_ident = try transCreateNodeIdentifier(c, "Child");
- const inner_node_child = try c.a().create(ast.Node.InfixOp);
- inner_node_child.* = .{
- .op_token = period_tok,
- .lhs = inner_node,
- .op = .Period,
- .rhs = child_ident,
- };
-
- const align_of = try transCreateNodeBuiltinFnCall(c, "@alignOf");
- try align_of.params.push(&inner_node_child.base);
- align_of.rparen_token = try appendToken(c, .RParen, ")");
- // hack to get zig fmt to render a comma in builtin calls
- _ = try appendToken(c, .Comma, ",");
-
- const align_cast = try transCreateNodeBuiltinFnCall(c, "@alignCast");
- try align_cast.params.push(&align_of.base);
- try align_cast.params.push(node_to_cast);
- align_cast.rparen_token = try appendToken(c, .RParen, ")");
-
const ptr_cast = try transCreateNodeBuiltinFnCall(c, "@ptrCast");
try ptr_cast.params.push(inner_node);
- try ptr_cast.params.push(&align_cast.base);
+ try ptr_cast.params.push(node_to_cast);
ptr_cast.rparen_token = try appendToken(c, .RParen, ")");
if_1.body = &ptr_cast.base;
@@ -5516,14 +5492,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
as.rparen_token = try appendToken(c, .RParen, ")");
else_2.body = &as.base;
- const group_rparen = try appendToken(c, .RParen, ")");
- const grouped_expr = try c.a().create(ast.Node.GroupedExpression);
- grouped_expr.* = .{
- .lparen = group_lparen,
- .expr = &if_1.base,
- .rparen = group_rparen,
- };
- return &grouped_expr.base;
+ return &if_1.base;
},
else => {
const first_tok = it.list.at(0);
diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig
index 313a83705..629a85083 100644
--- a/test/run_translated_c.zig
+++ b/test/run_translated_c.zig
@@ -195,22 +195,4 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");
-
- cases.add("cast from pointer to opaque type to struct",
- \\#include
- \\typedef struct
- \\{
- \\ int i;
- \\}
- \\StructType,*StructPtrType;
- \\
- \\typedef struct OpaqueStruct OpaqueStructTypedef;
- \\#define Macro(opaquePtr) (((StructPtrType)(opaquePtr))->i)
- \\int main(int argc, char **argv) {
- \\ StructType localStruct = {88};
- \\ OpaqueStructTypedef *opaquePtrToLocal = &localStruct;
- \\ printf("%d!\n", Macro(opaquePtrToLocal));
- \\ return 0;
- \\}
- , "88!\n");
}
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 01614ae9c..3d0843d27 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1404,7 +1404,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("macro pointer cast",
\\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
, &[_][]const u8{
- \\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, @alignCast(@alignOf([*c]NRF_GPIO_Type.Child), NRF_GPIO_BASE)) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
+ \\pub const NRF_GPIO = if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
});
cases.add("basic macro function",
@@ -2588,11 +2588,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define FOO(bar) baz((void *)(baz))
\\#define BAR (void*) a
, &[_][]const u8{
- \\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, @alignCast(@alignOf(*c_void.Child), baz)) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)))) {
- \\ return baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, @alignCast(@alignOf(*c_void.Child), baz)) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)));
+ \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz))) {
+ \\ return baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz));
\\}
,
- \\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, @alignCast(@alignOf(*c_void.Child), a)) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a));
+ \\pub const BAR = if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a);
});
cases.add("macro conditional operator",
@@ -2754,20 +2754,4 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return if (x > y) x else y;
\\}
});
-
- cases.add("Make sure casts are grouped",
- \\typedef struct
- \\{
- \\ int i;
- \\}
- \\*_XPrivDisplay;
- \\typedef struct _XDisplay Display;
- \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
- \\
- , &[_][]const u8{
- \\pub inline fn DefaultScreen(dpy: var) @TypeOf((if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen) {
- \\ return (if (@typeInfo(@TypeOf(dpy)) == .Pointer) @ptrCast(_XPrivDisplay, @alignCast(@alignOf(_XPrivDisplay.Child), dpy)) else if (@typeInfo(@TypeOf(dpy)) == .Int) @intToPtr(_XPrivDisplay, dpy) else @as(_XPrivDisplay, dpy)).*.default_screen;
- \\}
- });
-
}
From b85bb152bf4c84a298200703d9a005ffcd1b24a0 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Sun, 8 Mar 2020 19:18:06 +1100
Subject: [PATCH 008/111] Fix grammar in error message
---
src/ir.cpp | 2 +-
test/compile_errors.zig | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 86d85303c..86a5cf061 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -30246,7 +30246,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
return ErrorSemanticAnalyzeFail;
} else if (elem_type->id == ZigTypeIdOpaque) {
ir_add_error(ira, &lazy_ptr_type->elem_type->base,
- buf_sprintf("C pointers cannot point opaque types"));
+ buf_sprintf("C pointers cannot point to opaque types"));
return ErrorSemanticAnalyzeFail;
} else if (lazy_ptr_type->is_allowzero) {
ir_add_error(ira, &lazy_ptr_type->elem_type->base,
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index f55931154..e402197a8 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1592,7 +1592,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var y: [*c]c_void = x;
\\}
, &[_][]const u8{
- "tmp.zig:3:16: error: C pointers cannot point opaque types",
+ "tmp.zig:3:16: error: C pointers cannot point to opaque types",
});
cases.add("directly embedding opaque type in struct and union",
From c8050a931c11e34bc6f4723eaed30f0a1bde5b14 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Sun, 8 Mar 2020 19:18:25 +1100
Subject: [PATCH 009/111] Strip trailing whitespace from src/ir.cpp
---
src/ir.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 86a5cf061..34f3ef26a 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -9014,7 +9014,7 @@ static IrInstSrc *ir_gen_switch_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n
return irb->codegen->invalid_inst_src;
}
else_prong = prong_node;
- } else if (prong_item_count == 1 &&
+ } else if (prong_item_count == 1 &&
prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol &&
buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) {
if (underscore_prong) {
@@ -26068,7 +26068,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
if (array_type->data.pointer.ptr_len == PtrLenC) {
array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown);
- // C pointers are allowzero by default.
+ // C pointers are allowzero by default.
// However, we want to be able to slice them without generating an allowzero slice (see issue #4401).
// To achieve this, we generate a runtime safety check and make the slice type non-allowzero.
if (array_type->data.pointer.allow_zero) {
@@ -26363,7 +26363,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
if (type_is_invalid(ptr_val->value->type))
return ira->codegen->invalid_inst_gen;
-
+
ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);
}
From 5aa993cd617e0ae3cabc9c626e45a748857e2f2a Mon Sep 17 00:00:00 2001
From: Vexu
Date: Sun, 8 Mar 2020 11:26:53 +0200
Subject: [PATCH 010/111] translate-c fix nested loops without blocks.
---
src-self-hosted/translate_c.zig | 51 +++++++++++++--------------------
test/translate_c.zig | 28 ++++++++++++++----
2 files changed, 42 insertions(+), 37 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index d24001cf9..b2eb96f2a 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -2237,6 +2237,7 @@ fn transWhileLoop(
.id = .Loop,
};
while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
+ _ = try appendToken(rp.c, .Semicolon, ";");
return &while_node.base;
}
@@ -2346,8 +2347,10 @@ fn transForLoop(
try block_scope.?.block_node.statements.push(&while_node.base);
block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
return &block_scope.?.block_node.base;
- } else
+ } else {
+ _ = try appendToken(rp.c, .Semicolon, ";");
return &while_node.base;
+ }
}
fn transSwitch(
@@ -5431,6 +5434,8 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
//else
// @as(dest, x)
+ const lparen = try appendToken(c, .LParen, "(");
+
const if_1 = try transCreateNodeIf(c);
const type_id_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf");
@@ -5492,7 +5497,13 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
as.rparen_token = try appendToken(c, .RParen, ")");
else_2.body = &as.base;
- return &if_1.base;
+ const group_node = try c.a().create(ast.Node.GroupedExpression);
+ group_node.* = .{
+ .lparen = lparen,
+ .expr = &if_1.base,
+ .rparen = try appendToken(c, .RParen, ")"),
+ };
+ return &group_node.base;
},
else => {
const first_tok = it.list.at(0);
@@ -5545,14 +5556,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
);
return error.ParseError;
}
- // deref is often used together with casts so we group the lhs expression
- const group = try c.a().create(ast.Node.GroupedExpression);
- group.* = .{
- .lparen = try appendToken(c, .LParen, "("),
- .expr = node,
- .rparen = try appendToken(c, .RParen, ")"),
- };
- const deref = try transCreateNodePtrDeref(c, &group.base);
+ const deref = try transCreateNodePtrDeref(c, node);
node = try transCreateNodeFieldAccess(c, deref, source[name_tok.start..name_tok.end]);
continue;
},
@@ -5596,7 +5600,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
},
.Ampersand => {
op_token = try appendToken(c, .Ampersand, "&");
- op_id .BitAnd;
+ op_id= .BitAnd;
},
.Plus => {
op_token = try appendToken(c, .Plus, "+");
@@ -5604,7 +5608,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
},
.Minus => {
op_token = try appendToken(c, .Minus, "-");
- op_id .Sub;
+ op_id= .Sub;
},
.AmpersandAmpersand => {
op_token = try appendToken(c, .Keyword_and, "and");
@@ -5676,19 +5680,17 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
},
.BangEqual => {
op_token = try appendToken(c, .BangEqual, "!=");
- op_id = .BangEqual;
+ op_id = .BangEqual;
},
.EqualEqual => {
op_token = try appendToken(c, .EqualEqual, "==");
op_id = .EqualEqual;
},
.Slash => {
- // unsigned/float division uses the operator
op_id = .Div;
op_token = try appendToken(c, .Slash, "/");
},
.Percent => {
- // unsigned/float division uses the operator
op_id = .Mod;
op_token = try appendToken(c, .Percent, "%");
},
@@ -5729,25 +5731,12 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
return &node.base;
},
.Asterisk => {
- // deref is often used together with casts so we group the lhs expression
- const group = try c.a().create(ast.Node.GroupedExpression);
- group.* = .{
- .lparen = try appendToken(c, .LParen, "("),
- .expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
- .rparen = try appendToken(c, .RParen, ")"),
- };
- return try transCreateNodePtrDeref(c, &group.base);
+ const node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
+ return try transCreateNodePtrDeref(c, node);
},
.Ampersand => {
- // address of is often used together with casts so we group the rhs expression
const node = try transCreateNodePrefixOp(c, .AddressOf, .Ampersand, "&");
- const group = try c.a().create(ast.Node.GroupedExpression);
- group.* = .{
- .lparen = try appendToken(c, .LParen, "("),
- .expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
- .rparen = try appendToken(c, .RParen, ")"),
- };
- node.rhs = &group.base;
+ node.rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
return &node.base;
},
else => {
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 3d0843d27..a791d0cca 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -3,6 +3,22 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void {
+ cases.add("nested loops without blocks",
+ \\void foo() {
+ \\ while (0) while (0) {}
+ \\ for (;;) while (0);
+ \\ for (;;) do {} while (0);
+ \\}
+ , &[_][]const u8{
+ \\pub export fn foo() void {
+ \\ while (@as(c_int, 0) != 0) while (@as(c_int, 0) != 0) {};
+ \\ while (true) while (@as(c_int, 0) != 0) {};
+ \\ while (true) while (true) {
+ \\ if (!(@as(c_int, 0) != 0)) break;
+ \\ };
+ \\}
+ });
+
cases.add("macro comma operator",
\\#define foo (foo, bar)
\\#define bar(x) (&x, +3, 4 == 4, 5 * 6, baz(1, 2), 2 % 2, baz(1,2))
@@ -14,7 +30,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub inline fn bar(x: var) @TypeOf(baz(1, 2)) {
\\ return blk: {
- \\ _ = &(x);
+ \\ _ = &x;
\\ _ = 3;
\\ _ = 4 == 4;
\\ _ = 5 * 6;
@@ -1404,7 +1420,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("macro pointer cast",
\\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
, &[_][]const u8{
- \\pub const NRF_GPIO = if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
+ \\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
});
cases.add("basic macro function",
@@ -1993,7 +2009,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub const DOT = a.b;
,
- \\pub const ARROW = (a).*.b;
+ \\pub const ARROW = a.*.b;
});
cases.add("array access",
@@ -2588,11 +2604,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define FOO(bar) baz((void *)(baz))
\\#define BAR (void*) a
, &[_][]const u8{
- \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz))) {
- \\ return baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz));
+ \\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)))) {
+ \\ return baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)));
\\}
,
- \\pub const BAR = if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a);
+ \\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a));
});
cases.add("macro conditional operator",
From 692a974c3edd05944d33cd579bcb355cdd7199fc Mon Sep 17 00:00:00 2001
From: Vexu
Date: Sun, 8 Mar 2020 12:07:26 +0200
Subject: [PATCH 011/111] translate-c reject structs with VLAs
---
src-self-hosted/clang.zig | 1 +
src-self-hosted/translate_c.zig | 14 +++++++++++---
src/zig_clang.cpp | 20 ++++++++++++++++++++
src/zig_clang.h | 1 +
test/translate_c.zig | 9 +++++++++
5 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig
index bdaa8b86d..3a3b4ac19 100644
--- a/src-self-hosted/clang.zig
+++ b/src-self-hosted/clang.zig
@@ -812,6 +812,7 @@ pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) str
pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool;
pub extern fn ZigClangType_isConstantArrayType(self: ?*const struct_ZigClangType) bool;
pub extern fn ZigClangType_isRecordType(self: ?*const struct_ZigClangType) bool;
+pub extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(self: ?*const struct_ZigClangType, *const ZigClangASTContext) bool;
pub extern fn ZigClangType_isArrayType(self: ?*const struct_ZigClangType) bool;
pub extern fn ZigClangType_isBooleanType(self: ?*const struct_ZigClangType) bool;
pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8;
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index b2eb96f2a..be3e43f3d 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -793,6 +793,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) {
const field_decl = ZigClangRecordDecl_field_iterator_deref(it);
const field_loc = ZigClangFieldDecl_getLocation(field_decl);
+ const field_qt = ZigClangFieldDecl_getType(field_decl);
if (ZigClangFieldDecl_isBitField(field_decl)) {
const opaque = try transCreateNodeOpaqueType(c);
@@ -801,6 +802,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
break :blk opaque;
}
+ if (ZigClangType_isIncompleteOrZeroLengthArrayType(qualTypeCanon(field_qt), c.clang_context)) {
+ const opaque = try transCreateNodeOpaqueType(c);
+ semicolon = try appendToken(c, .Semicolon, ";");
+ try emitWarning(c, field_loc, "{} demoted to opaque type - has variable length array", .{container_kind_name});
+ break :blk opaque;
+ }
+
var is_anon = false;
var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
@@ -809,7 +817,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
}
const field_name = try appendIdentifier(c, raw_name);
_ = try appendToken(c, .Colon, ":");
- const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) {
+ const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
error.UnsupportedType => {
const opaque = try transCreateNodeOpaqueType(c);
semicolon = try appendToken(c, .Semicolon, ";");
@@ -5600,7 +5608,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
},
.Ampersand => {
op_token = try appendToken(c, .Ampersand, "&");
- op_id= .BitAnd;
+ op_id = .BitAnd;
},
.Plus => {
op_token = try appendToken(c, .Plus, "+");
@@ -5608,7 +5616,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
},
.Minus => {
op_token = try appendToken(c, .Minus, "-");
- op_id= .Sub;
+ op_id = .Sub;
},
.AmpersandAmpersand => {
op_token = try appendToken(c, .Keyword_and, "and");
diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp
index 8a1baa2d4..c5ea182e8 100644
--- a/src/zig_clang.cpp
+++ b/src/zig_clang.cpp
@@ -1881,6 +1881,26 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {
return casted->isRecordType();
}
+bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self,
+ const struct ZigClangASTContext *ctx)
+{
+ auto casted_ctx = reinterpret_cast(ctx);
+ auto casted = reinterpret_cast(self);
+ auto casted_type = reinterpret_cast(self);
+ if (casted_type->isIncompleteArrayType())
+ return true;
+
+ clang::QualType elem_type = *casted;
+ while (const clang::ConstantArrayType *ArrayT = casted_ctx->getAsConstantArrayType(elem_type)) {
+ if (ArrayT->getSize() == 0)
+ return true;
+
+ elem_type = ArrayT->getElementType();
+ }
+
+ return false;
+}
+
bool ZigClangType_isConstantArrayType(const ZigClangType *self) {
auto casted = reinterpret_cast(self);
return casted->isConstantArrayType();
diff --git a/src/zig_clang.h b/src/zig_clang.h
index 2d9485ae9..579812a84 100644
--- a/src/zig_clang.h
+++ b/src/zig_clang.h
@@ -947,6 +947,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);
ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);
ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);
+ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx);
ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);
ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
ZIG_EXTERN_C const struct ZigClangArrayType *ZigClangType_getAsArrayTypeUnsafe(const struct ZigClangType *self);
diff --git a/test/translate_c.zig b/test/translate_c.zig
index a791d0cca..209a301f8 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -3,6 +3,15 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void {
+ cases.add("structs with VLAs are rejected",
+ \\struct foo { int x; int y[]; };
+ \\struct bar { int x; int y[0]; };
+ , &[_][]const u8{
+ \\pub const struct_foo = @OpaqueType();
+ ,
+ \\pub const struct_bar = @OpaqueType();
+ });
+
cases.add("nested loops without blocks",
\\void foo() {
\\ while (0) while (0) {}
From 2b1316954f169a88cfb694f4c1defc0d965455ea Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sun, 8 Mar 2020 10:55:00 +0100
Subject: [PATCH 012/111] std: One more cpuid fix
Don't read from stale eax value, rework the logic a bit so that's clear
what's going on.
---
lib/std/zig/system/x86.zig | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/lib/std/zig/system/x86.zig b/lib/std/zig/system/x86.zig
index c85b646f8..b4964596d 100644
--- a/lib/std/zig/system/x86.zig
+++ b/lib/std/zig/system/x86.zig
@@ -2,6 +2,12 @@ const std = @import("std");
const Target = std.Target;
const CrossTarget = std.zig.CrossTarget;
+const XCR0_XMM = 0x02;
+const XCR0_YMM = 0x04;
+const XCR0_MASKREG = 0x20;
+const XCR0_ZMM0_15 = 0x40;
+const XCR0_ZMM16_31 = 0x80;
+
fn setFeature(cpu: *Target.Cpu, feature: Target.x86.Feature, enabled: bool) void {
const idx = @as(Target.Cpu.Feature.Set.Index, @enumToInt(feature));
@@ -12,6 +18,10 @@ inline fn bit(input: u32, offset: u5) bool {
return (input >> offset) & 1 != 0;
}
+inline fn hasMask(input: u32, mask: u32) bool {
+ return (input & mask) == mask;
+}
+
pub fn detectNativeCpuAndFeatures(arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) Target.Cpu {
var cpu = Target.Cpu{
.arch = arch,
@@ -309,7 +319,6 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
leaf = cpuid(1, 0);
- setFeature(cpu, .cx8, bit(leaf.edx, 8));
setFeature(cpu, .cx8, bit(leaf.edx, 8));
setFeature(cpu, .cmov, bit(leaf.edx, 15));
setFeature(cpu, .mmx, bit(leaf.edx, 23));
@@ -327,11 +336,13 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
setFeature(cpu, .aes, bit(leaf.ecx, 25));
setFeature(cpu, .rdrnd, bit(leaf.ecx, 30));
- // If the CPU supports XSAVE/XRESTORE (bit 27) and AVX (bit 28) also check
- // if the AVX registers are saved & restored on context switch
- const has_avx_save = bit(leaf.ecx, 27) and
- bit(leaf.ecx, 28) and
- ((getXCR0() & 0x6) == 0x6);
+ const has_xsave = bit(leaf.ecx, 27);
+ const has_avx = bit(leaf.ecx, 28);
+
+ // Make sure not to call xgetbv if xsave is not supported
+ const xcr0_eax = if (has_xsave and has_avx) getXCR0() else 0;
+
+ const has_avx_save = hasMask(xcr0_eax, XCR0_XMM | XCR0_YMM);
// LLVM approaches avx512_save by hardcoding it to true on Darwin,
// because the kernel saves the context even if the bit is not set.
@@ -355,7 +366,7 @@ fn detectNativeFeatures(cpu: *Target.Cpu, os_tag: Target.Os.Tag) void {
// set right now.
const has_avx512_save = switch (os_tag.isDarwin()) {
true => true,
- false => has_avx_save and ((leaf.eax & 0xE0) == 0xE0),
+ false => hasMask(xcr0_eax, XCR0_MASKREG | XCR0_ZMM0_15 | XCR0_ZMM16_31),
};
setFeature(cpu, .avx, has_avx_save);
@@ -530,6 +541,7 @@ fn cpuid(leaf_id: u32, subid: u32) CpuidLeaf {
[leaf_ptr] "r" (&cpuid_leaf)
: "eax", "ebx", "ecx", "edx"
);
+
return cpuid_leaf;
}
From 7782c76bee0201227be730ae131171939f728538 Mon Sep 17 00:00:00 2001
From: xackus <14938807+xackus@users.noreply.github.com>
Date: Thu, 5 Mar 2020 08:32:09 +0100
Subject: [PATCH 013/111] fix failed assert on generic fn opaque return type
---
src/analyze.cpp | 42 ++++++++++++++++++++---------------------
src/analyze.hpp | 1 +
src/ir.cpp | 13 +++++++++++++
test/compile_errors.zig | 18 ++++++++++++++++--
4 files changed, 50 insertions(+), 24 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 7712f0f70..638a31ab5 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1955,29 +1955,14 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
return g->builtin_types.entry_invalid;
}
- switch (specified_return_type->id) {
- case ZigTypeIdInvalid:
- zig_unreachable();
-
- case ZigTypeIdUndefined:
- case ZigTypeIdNull:
- add_node_error(g, fn_proto->return_type,
- buf_sprintf("return type '%s' not allowed", buf_ptr(&specified_return_type->name)));
- return g->builtin_types.entry_invalid;
-
- case ZigTypeIdOpaque:
- {
- ErrorMsg* msg = add_node_error(g, fn_proto->return_type,
- buf_sprintf("opaque return type '%s' not allowed", buf_ptr(&specified_return_type->name)));
- Tld *tld = find_decl(g, &fn_entry->fndef_scope->base, &specified_return_type->name);
- if (tld != nullptr) {
- add_error_note(g, msg, tld->source_node, buf_sprintf("declared here"));
- }
- return g->builtin_types.entry_invalid;
+ if(!is_valid_return_type(specified_return_type)){
+ ErrorMsg* msg = add_node_error(g, fn_proto->return_type,
+ buf_sprintf("return type '%s' not allowed", buf_ptr(&specified_return_type->name)));
+ Tld *tld = find_decl(g, &fn_entry->fndef_scope->base, &specified_return_type->name);
+ if (tld != nullptr) {
+ add_error_note(g, msg, tld->source_node, buf_sprintf("type declared here"));
}
-
- default:
- break;
+ return g->builtin_types.entry_invalid;
}
if (fn_proto->auto_err_set) {
@@ -2049,6 +2034,19 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
return get_fn_type(g, &fn_type_id);
}
+bool is_valid_return_type(ZigType* type) {
+ switch (type->id) {
+ case ZigTypeIdInvalid:
+ case ZigTypeIdUndefined:
+ case ZigTypeIdNull:
+ case ZigTypeIdOpaque:
+ return false;
+ default:
+ return true;
+ }
+ zig_unreachable();
+}
+
bool type_is_invalid(ZigType *type_entry) {
switch (type_entry->id) {
case ZigTypeIdInvalid:
diff --git a/src/analyze.hpp b/src/analyze.hpp
index fded1e405..84d319bf5 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -265,6 +265,7 @@ ZigValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *
void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn);
bool fn_is_async(ZigFn *fn);
CallingConvention cc_from_fn_proto(AstNodeFnProto *fn_proto);
+bool is_valid_return_type(ZigType* type);
Error type_val_resolve_abi_align(CodeGen *g, AstNode *source_node, ZigValue *type_val, uint32_t *abi_align);
Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ZigValue *type_val,
diff --git a/src/ir.cpp b/src/ir.cpp
index 34f3ef26a..67eabf504 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -19339,6 +19339,19 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node);
if (type_is_invalid(specified_return_type))
return ira->codegen->invalid_inst_gen;
+
+ if(!is_valid_return_type(specified_return_type)){
+ ErrorMsg *msg = ir_add_error(ira, source_instr,
+ buf_sprintf("call to generic function with return type '%s' not allowed", buf_ptr(&specified_return_type->name)));
+ add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here"));
+
+ Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name);
+ if (tld != nullptr) {
+ add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("type declared here"));
+ }
+ return ira->codegen->invalid_inst_gen;
+ }
+
if (fn_proto_node->data.fn_proto.auto_err_set) {
ZigType *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn);
if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown)))
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index e402197a8..006bd3ef7 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -6539,8 +6539,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.InvalidValue;
\\}
, &[_][]const u8{
- "tmp.zig:2:18: error: opaque return type 'FooType' not allowed",
- "tmp.zig:1:1: note: declared here",
+ "tmp.zig:2:18: error: return type 'FooType' not allowed",
+ "tmp.zig:1:1: note: type declared here",
+ });
+
+ cases.add("generic function returning opaque type",
+ \\const FooType = @OpaqueType();
+ \\fn generic(comptime T: type) !T {
+ \\ return undefined;
+ \\}
+ \\export fn bar() void {
+ \\ _ = generic(FooType);
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:6:16: error: call to generic function with return type 'FooType' not allowed",
+ "tmp.zig:2:1: note: function declared here",
+ "tmp.zig:1:1: note: type declared here",
});
cases.add( // fixed bug #2032
From 55077435bf53bb8273e1b23c1690798312d6abc6 Mon Sep 17 00:00:00 2001
From: LeRoyce Pearson
Date: Sun, 8 Mar 2020 14:27:49 -0600
Subject: [PATCH 014/111] Expose file inode (linux) and file index (windows)
---
lib/std/fs/file.zig | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 5b51f19f4..47f13080f 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -28,6 +28,10 @@ pub const File = struct {
pub const async_block_allowed_no = if (io.is_async) false else {};
pub const Mode = os.mode_t;
+ pub const INode = switch (builtin.os.tag) {
+ .windows => os.windows.LARGE_INTEGER,
+ else => u64,
+ };
pub const default_mode = switch (builtin.os.tag) {
.windows => 0,
@@ -145,6 +149,7 @@ pub const File = struct {
}
pub const Stat = struct {
+ inode: INode,
size: u64,
mode: Mode,
@@ -174,6 +179,7 @@ pub const File = struct {
else => return windows.unexpectedStatus(rc),
}
return Stat{
+ .inode = info.InternalInformation.IndexNumber,
.size = @bitCast(u64, info.StandardInformation.EndOfFile),
.mode = 0,
.atime = windows.fromSysTime(info.BasicInformation.LastAccessTime),
@@ -187,6 +193,7 @@ pub const File = struct {
const mtime = st.mtime();
const ctime = st.ctime();
return Stat{
+ .inode = st.ino,
.size = @bitCast(u64, st.size),
.mode = st.mode,
.atime = @as(i64, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
From e1c1ca99031a76b44ba1bdce0d10acb4513af8d6 Mon Sep 17 00:00:00 2001
From: LeRoyce Pearson
Date: Sun, 8 Mar 2020 15:47:50 -0600
Subject: [PATCH 015/111] Add documentation about Stat.inode
---
lib/std/fs/file.zig | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 47f13080f..a4ce89868 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -28,8 +28,13 @@ pub const File = struct {
pub const async_block_allowed_no = if (io.is_async) false else {};
pub const Mode = os.mode_t;
+
+ /// The type that is used to represent the inode/file index number. On windows this is a
+ /// LARGE_INTEGER (i64), and on linux this is a u64.
pub const INode = switch (builtin.os.tag) {
.windows => os.windows.LARGE_INTEGER,
+ // TODO: Handle possibility of 128 bit numbers? ReFS on windows server 2012 uses a 128 bit file
+ // index. See https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
else => u64,
};
@@ -149,7 +154,16 @@ pub const File = struct {
}
pub const Stat = struct {
+ /// A number that the system uses to point to the file metadata. This number is not guaranteed to be
+ /// unique across time, as some file systems may reuse an inode after it's file has been deleted.
+ /// Some systems may change the inode of a file over time.
+ ///
+ /// On Linux, the inode _is_ structure that stores the metadata, and the inode _number_ is what
+ /// you see here: the index number of the inode.
+ ///
+ /// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem.
inode: INode,
+
size: u64,
mode: Mode,
From 06d0dac0fb58c2d20036e34f5c1a1bc9c386c189 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sun, 8 Mar 2020 19:48:35 +0100
Subject: [PATCH 016/111] ir: Prevent crash in compiler error
Anonymous containers have no struct_field->type AstNode set, let's
always use the field node itself to make the error messages consistent.
Closes #4691
---
src/analyze.cpp | 4 ++--
test/compile_errors.zig | 9 +++++++--
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 7712f0f70..c7bd7094d 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2893,7 +2893,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
return ErrorSemanticAnalyzeFail;
}
if (field_is_opaque_type) {
- add_node_error(g, field_node->data.struct_field.type,
+ add_node_error(g, field_node,
buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs"));
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
@@ -3185,7 +3185,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
return ErrorSemanticAnalyzeFail;
}
if (field_is_opaque_type) {
- add_node_error(g, field_node->data.struct_field.type,
+ add_node_error(g, field_node,
buf_create_from_str(
"opaque types have unknown size and therefore cannot be directly embedded in unions"));
union_type->data.unionation.resolve_status = ResolveStatusInvalid;
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index e402197a8..2b74d8fc7 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -1610,9 +1610,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn b() void {
\\ var bar: Bar = undefined;
\\}
+ \\export fn c() void {
+ \\ var baz: *@OpaqueType() = undefined;
+ \\ const qux = .{baz.*};
+ \\}
, &[_][]const u8{
- "tmp.zig:3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
- "tmp.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
+ "tmp.zig:3:5: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
+ "tmp.zig:7:5: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
+ "tmp.zig:17:22: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
});
cases.add("implicit cast between C pointer and Zig pointer - bad const/align/child",
From e2fd289a33bb35cf4b86daa4d80adb7cc0c2c2b0 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Tue, 3 Mar 2020 12:13:13 +0100
Subject: [PATCH 017/111] ir: Create usize result_loc for array subscript expr
Allow the subscript expression to infer the resulting type.
Closes #4169
---
src/ir.cpp | 14 +++++++++++---
test/compile_errors.zig | 4 ++--
test/stage1/behavior/array.zig | 18 +++++++++++++++++-
3 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 34f3ef26a..110778fb9 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -5910,10 +5910,18 @@ static IrInstSrc *ir_gen_array_access(IrBuilderSrc *irb, Scope *scope, AstNode *
if (array_ref_instruction == irb->codegen->invalid_inst_src)
return array_ref_instruction;
+ // Create an usize-typed result location to hold the subscript value, this
+ // makes it possible for the compiler to infer the subscript expression type
+ // if needed
+ IrInstSrc *usize_type_inst = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
+ ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, usize_type_inst, no_result_loc());
+
AstNode *subscript_node = node->data.array_access_expr.subscript;
- IrInstSrc *subscript_instruction = ir_gen_node(irb, subscript_node, scope);
- if (subscript_instruction == irb->codegen->invalid_inst_src)
- return subscript_instruction;
+ IrInstSrc *subscript_value = ir_gen_node_extra(irb, subscript_node, scope, LValNone, &result_loc_cast->base);
+ if (subscript_value == irb->codegen->invalid_inst_src)
+ return irb->codegen->invalid_inst_src;
+
+ IrInstSrc *subscript_instruction = ir_build_implicit_cast(irb, scope, subscript_node, subscript_value, result_loc_cast);
IrInstSrc *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction,
subscript_instruction, true, PtrLenSingle, nullptr);
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 2b74d8fc7..717793baa 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -3610,11 +3610,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add("array access of non array",
\\export fn f() void {
\\ var bad : bool = undefined;
- \\ bad[bad] = bad[bad];
+ \\ bad[0] = bad[0];
\\}
\\export fn g() void {
\\ var bad : bool = undefined;
- \\ _ = bad[bad];
+ \\ _ = bad[0];
\\}
, &[_][]const u8{
"tmp.zig:3:8: error: array access of non-array type 'bool'",
diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig
index 7ac1e8197..da56864cc 100644
--- a/test/stage1/behavior/array.zig
+++ b/test/stage1/behavior/array.zig
@@ -1,6 +1,8 @@
const std = @import("std");
-const expect = std.testing.expect;
+const testing = std.testing;
const mem = std.mem;
+const expect = testing.expect;
+const expectEqual = testing.expectEqual;
test "arrays" {
var array: [5]u32 = undefined;
@@ -360,3 +362,17 @@ test "access the null element of a null terminated array" {
S.doTheTest();
comptime S.doTheTest();
}
+
+test "type deduction for array subscript expression" {
+ const S = struct {
+ fn doTheTest() void {
+ var array = [_]u8{ 0x55, 0xAA };
+ var v0 = true;
+ expectEqual(@as(u8, 0xAA), array[if (v0) 1 else 0]);
+ var v1 = false;
+ expectEqual(@as(u8, 0x55), array[if (v1) 1 else 0]);
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
From cb84875eed42b4721de5b2cc356c4a6719eb0516 Mon Sep 17 00:00:00 2001
From: LeRoyce Pearson
Date: Sun, 8 Mar 2020 18:31:18 -0600
Subject: [PATCH 018/111] Define ino_t for systems not yet defining it
Also, use ino_t instead of u64 in fs.File.INode
---
lib/std/fs/file.zig | 2 +-
lib/std/os/bits/darwin.zig | 3 ++-
lib/std/os/bits/dragonfly.zig | 4 +++-
lib/std/os/bits/freebsd.zig | 3 ++-
lib/std/os/bits/linux/x86_64.zig | 3 ++-
lib/std/os/bits/netbsd.zig | 3 ++-
lib/std/os/bits/wasi.zig | 1 +
7 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index a4ce89868..33307a9dd 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -35,7 +35,7 @@ pub const File = struct {
.windows => os.windows.LARGE_INTEGER,
// TODO: Handle possibility of 128 bit numbers? ReFS on windows server 2012 uses a 128 bit file
// index. See https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
- else => u64,
+ else => os.ino_t,
};
pub const default_mode = switch (builtin.os.tag) {
diff --git a/lib/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig
index fb933c669..6808af031 100644
--- a/lib/std/os/bits/darwin.zig
+++ b/lib/std/os/bits/darwin.zig
@@ -53,6 +53,7 @@ pub const mach_timebase_info_data = extern struct {
};
pub const off_t = i64;
+pub const ino_t = u64;
/// Renamed to Stat to not conflict with the stat function.
/// atime, mtime, and ctime have functions to return `timespec`,
@@ -64,7 +65,7 @@ pub const Stat = extern struct {
dev: i32,
mode: u16,
nlink: u16,
- ino: u64,
+ ino: ino_t,
uid: u32,
gid: u32,
rdev: i32,
diff --git a/lib/std/os/bits/dragonfly.zig b/lib/std/os/bits/dragonfly.zig
index c6c23affa..27b2733b7 100644
--- a/lib/std/os/bits/dragonfly.zig
+++ b/lib/std/os/bits/dragonfly.zig
@@ -138,8 +138,10 @@ pub const MAP_SIZEALIGN = 262144;
pub const PATH_MAX = 1024;
+pub const ino_t = c_ulong;
+
pub const Stat = extern struct {
- ino: c_ulong,
+ ino: ino_t,
nlink: c_uint,
dev: c_uint,
mode: c_ushort,
diff --git a/lib/std/os/bits/freebsd.zig b/lib/std/os/bits/freebsd.zig
index b7d14934f..02fe7e75b 100644
--- a/lib/std/os/bits/freebsd.zig
+++ b/lib/std/os/bits/freebsd.zig
@@ -98,6 +98,7 @@ pub const msghdr_const = extern struct {
};
pub const off_t = i64;
+pub const ino_t = u64;
/// Renamed to Stat to not conflict with the stat function.
/// atime, mtime, and ctime have functions to return `timespec`,
@@ -107,7 +108,7 @@ pub const off_t = i64;
/// methods to accomplish this.
pub const Stat = extern struct {
dev: u64,
- ino: u64,
+ ino: ino_t,
nlink: usize,
mode: u16,
diff --git a/lib/std/os/bits/linux/x86_64.zig b/lib/std/os/bits/linux/x86_64.zig
index 608f74e2d..e92591d94 100644
--- a/lib/std/os/bits/linux/x86_64.zig
+++ b/lib/std/os/bits/linux/x86_64.zig
@@ -481,6 +481,7 @@ pub const msghdr_const = extern struct {
};
pub const off_t = i64;
+pub const ino_t = u64;
/// Renamed to Stat to not conflict with the stat function.
/// atime, mtime, and ctime have functions to return `timespec`,
@@ -490,7 +491,7 @@ pub const off_t = i64;
/// methods to accomplish this.
pub const Stat = extern struct {
dev: u64,
- ino: u64,
+ ino: ino_t,
nlink: usize,
mode: u32,
diff --git a/lib/std/os/bits/netbsd.zig b/lib/std/os/bits/netbsd.zig
index 89e0998d6..735485695 100644
--- a/lib/std/os/bits/netbsd.zig
+++ b/lib/std/os/bits/netbsd.zig
@@ -69,6 +69,7 @@ pub const msghdr_const = extern struct {
};
pub const off_t = i64;
+pub const ino_t = u64;
/// Renamed to Stat to not conflict with the stat function.
/// atime, mtime, and ctime have functions to return `timespec`,
@@ -79,7 +80,7 @@ pub const off_t = i64;
pub const Stat = extern struct {
dev: u64,
mode: u32,
- ino: u64,
+ ino: ino_t,
nlink: usize,
uid: u32,
diff --git a/lib/std/os/bits/wasi.zig b/lib/std/os/bits/wasi.zig
index f56e53504..8fb85e1fc 100644
--- a/lib/std/os/bits/wasi.zig
+++ b/lib/std/os/bits/wasi.zig
@@ -178,6 +178,7 @@ pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
pub const inode_t = u64;
+pub const ino_t = inode_t;
pub const linkcount_t = u32;
From 25d9ab95dd8a691963453c4507d519051eaebb0c Mon Sep 17 00:00:00 2001
From: LeRoyce Pearson
Date: Sun, 8 Mar 2020 21:52:36 -0600
Subject: [PATCH 019/111] Use os.ino_t for everything
Also, define ino_t for windows
---
lib/std/fs/file.zig | 11 +----------
lib/std/os/bits/windows.zig | 1 +
2 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 33307a9dd..8f7a46ad3 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -29,15 +29,6 @@ pub const File = struct {
pub const Mode = os.mode_t;
- /// The type that is used to represent the inode/file index number. On windows this is a
- /// LARGE_INTEGER (i64), and on linux this is a u64.
- pub const INode = switch (builtin.os.tag) {
- .windows => os.windows.LARGE_INTEGER,
- // TODO: Handle possibility of 128 bit numbers? ReFS on windows server 2012 uses a 128 bit file
- // index. See https://docs.microsoft.com/en-us/windows/win32/api/fileapi/ns-fileapi-by_handle_file_information
- else => os.ino_t,
- };
-
pub const default_mode = switch (builtin.os.tag) {
.windows => 0,
else => 0o666,
@@ -162,7 +153,7 @@ pub const File = struct {
/// you see here: the index number of the inode.
///
/// The FileIndex on Windows is similar. It is a number for a file that is unique to each filesystem.
- inode: INode,
+ inode: os.ino_t,
size: u64,
mode: Mode,
diff --git a/lib/std/os/bits/windows.zig b/lib/std/os/bits/windows.zig
index ba2725e0a..05486c8f7 100644
--- a/lib/std/os/bits/windows.zig
+++ b/lib/std/os/bits/windows.zig
@@ -4,6 +4,7 @@ usingnamespace @import("../windows/bits.zig");
const ws2_32 = @import("../windows/ws2_32.zig");
pub const fd_t = HANDLE;
+pub const ino_t = LARGE_INTEGER;
pub const pid_t = HANDLE;
pub const mode_t = u0;
From 6f8d732599461aa816f545b658a068eceb6ac9bc Mon Sep 17 00:00:00 2001
From: Vexu
Date: Mon, 9 Mar 2020 11:02:16 +0200
Subject: [PATCH 020/111] update parsers to new noasync syntax
---
lib/std/zig/ast.zig | 29 ++++++++++++++++++--
lib/std/zig/parse.zig | 62 +++++++++++++++++++++++++-----------------
lib/std/zig/render.zig | 9 ++++--
src/all_types.hpp | 7 ++++-
src/ast_render.cpp | 8 ++++++
src/parser.cpp | 36 ++++++++++++++++--------
6 files changed, 108 insertions(+), 43 deletions(-)
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index bc4f6350d..711806b81 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -431,6 +431,7 @@ pub const Node = struct {
ContainerDecl,
Asm,
Comptime,
+ Noasync,
Block,
// Misc
@@ -1078,6 +1079,30 @@ pub const Node = struct {
}
};
+ pub const Noasync = struct {
+ base: Node = Node{ .id = .Noasync },
+ doc_comments: ?*DocComment,
+ noasync_token: TokenIndex,
+ expr: *Node,
+
+ pub fn iterate(self: *Noasync, index: usize) ?*Node {
+ var i = index;
+
+ if (i < 1) return self.expr;
+ i -= 1;
+
+ return null;
+ }
+
+ pub fn firstToken(self: *const Noasync) TokenIndex {
+ return self.noasync_token;
+ }
+
+ pub fn lastToken(self: *const Noasync) TokenIndex {
+ return self.expr.lastToken();
+ }
+ };
+
pub const Payload = struct {
base: Node = Node{ .id = .Payload },
lpipe: TokenIndex,
@@ -1560,9 +1585,7 @@ pub const Node = struct {
pub const Op = union(enum) {
AddressOf,
ArrayType: ArrayInfo,
- Await: struct {
- noasync_token: ?TokenIndex = null,
- },
+ Await,
BitNot,
BoolNot,
Cancel,
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
index cadf25eef..5392c18df 100644
--- a/lib/std/zig/parse.zig
+++ b/lib/std/zig/parse.zig
@@ -856,6 +856,7 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
/// / IfExpr
/// / KEYWORD_break BreakLabel? Expr?
/// / KEYWORD_comptime Expr
+/// / KEYWORD_noasync Expr
/// / KEYWORD_continue BreakLabel?
/// / KEYWORD_resume Expr
/// / KEYWORD_return Expr?
@@ -870,7 +871,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
const label = try parseBreakLabel(arena, it, tree);
const expr_node = try parseExpr(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
- node.* = Node.ControlFlowExpression{
+ node.* = .{
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind{ .Break = label },
.rhs = expr_node,
@@ -883,7 +884,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
.ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
});
const node = try arena.create(Node.Comptime);
- node.* = Node.Comptime{
+ node.* = .{
.doc_comments = null,
.comptime_token = token,
.expr = expr_node,
@@ -891,10 +892,23 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
return &node.base;
}
+ if (eatToken(it, .Keyword_noasync)) |token| {
+ const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{
+ .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
+ });
+ const node = try arena.create(Node.Noasync);
+ node.* = .{
+ .doc_comments = null,
+ .noasync_token = token,
+ .expr = expr_node,
+ };
+ return &node.base;
+ }
+
if (eatToken(it, .Keyword_continue)) |token| {
const label = try parseBreakLabel(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
- node.* = Node.ControlFlowExpression{
+ node.* = .{
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind{ .Continue = label },
.rhs = null,
@@ -907,7 +921,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
.ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
});
const node = try arena.create(Node.PrefixOp);
- node.* = Node.PrefixOp{
+ node.* = .{
.op_token = token,
.op = Node.PrefixOp.Op.Resume,
.rhs = expr_node,
@@ -918,7 +932,7 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
if (eatToken(it, .Keyword_return)) |token| {
const expr_node = try parseExpr(arena, it, tree);
const node = try arena.create(Node.ControlFlowExpression);
- node.* = Node.ControlFlowExpression{
+ node.* = .{
.ltoken = token,
.kind = Node.ControlFlowExpression.Kind.Return,
.rhs = expr_node,
@@ -1126,19 +1140,18 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
/// SuffixExpr
/// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
-/// / KEYWORD_noasync PrimaryTypeExpr SuffixOp* FnCallArguments
/// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
- const maybe_async = eatAnnotatedToken(it, .Keyword_async) orelse eatAnnotatedToken(it, .Keyword_noasync);
+ const maybe_async = eatToken(it, .Keyword_async);
if (maybe_async) |async_token| {
const token_fn = eatToken(it, .Keyword_fn);
- if (async_token.ptr.id == .Keyword_async and token_fn != null) {
+ if (token_fn != null) {
// HACK: If we see the keyword `fn`, then we assume that
// we are parsing an async fn proto, and not a call.
// We therefore put back all tokens consumed by the async
// prefix...
putBackToken(it, token_fn.?);
- putBackToken(it, async_token.index);
+ putBackToken(it, async_token);
return parsePrimaryTypeExpr(arena, it, tree);
}
// TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr
@@ -1167,7 +1180,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
.op = Node.SuffixOp.Op{
.Call = Node.SuffixOp.Op.Call{
.params = params.list,
- .async_token = async_token.index,
+ .async_token = async_token,
},
},
.rtoken = params.rparen,
@@ -1224,6 +1237,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
/// / IfTypeExpr
/// / INTEGER
/// / KEYWORD_comptime TypeExpr
+/// / KEYWORD_noasync TypeExpr
/// / KEYWORD_error DOT IDENTIFIER
/// / KEYWORD_false
/// / KEYWORD_null
@@ -1255,13 +1269,23 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
if (eatToken(it, .Keyword_comptime)) |token| {
const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
const node = try arena.create(Node.Comptime);
- node.* = Node.Comptime{
+ node.* = .{
.doc_comments = null,
.comptime_token = token,
.expr = expr,
};
return &node.base;
}
+ if (eatToken(it, .Keyword_noasync)) |token| {
+ const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
+ const node = try arena.create(Node.Noasync);
+ node.* = .{
+ .doc_comments = null,
+ .noasync_token = token,
+ .expr = expr,
+ };
+ return &node.base;
+ }
if (eatToken(it, .Keyword_error)) |token| {
const period = try expectToken(it, tree, .Period);
const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{
@@ -1269,7 +1293,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
});
const global_error_set = try createLiteral(arena, Node.ErrorType, token);
const node = try arena.create(Node.InfixOp);
- node.* = Node.InfixOp{
+ node.* = .{
.op_token = period,
.lhs = global_error_set,
.op = Node.InfixOp.Op.Period,
@@ -1281,7 +1305,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
if (eatToken(it, .Keyword_anyframe)) |token| {
const node = try arena.create(Node.AnyFrameType);
- node.* = Node.AnyFrameType{
+ node.* = .{
.anyframe_token = token,
.result = null,
};
@@ -2180,18 +2204,6 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
.Ampersand => ops{ .AddressOf = {} },
.Keyword_try => ops{ .Try = {} },
.Keyword_await => ops{ .Await = .{} },
- .Keyword_noasync => if (eatToken(it, .Keyword_await)) |await_tok| {
- const node = try arena.create(Node.PrefixOp);
- node.* = Node.PrefixOp{
- .op_token = await_tok,
- .op = .{ .Await = .{ .noasync_token = token.index } },
- .rhs = undefined, // set by caller
- };
- return &node.base;
- } else {
- putBackToken(it, token.index);
- return null;
- },
else => {
putBackToken(it, token.index);
return null;
diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig
index 625aef313..ce9049e35 100644
--- a/lib/std/zig/render.zig
+++ b/lib/std/zig/render.zig
@@ -390,6 +390,12 @@ fn renderExpression(
try renderToken(tree, stream, comptime_node.comptime_token, indent, start_col, Space.Space);
return renderExpression(allocator, stream, tree, indent, start_col, comptime_node.expr, space);
},
+ .Noasync => {
+ const noasync_node = @fieldParentPtr(ast.Node.Noasync, "base", base);
+
+ try renderToken(tree, stream, noasync_node.noasync_token, indent, start_col, Space.Space);
+ return renderExpression(allocator, stream, tree, indent, start_col, noasync_node.expr, space);
+ },
.Suspend => {
const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
@@ -590,9 +596,6 @@ fn renderExpression(
},
.Await => |await_info| {
- if (await_info.noasync_token) |tok| {
- try renderToken(tree, stream, tok, indent, start_col, Space.Space);
- }
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);
},
}
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 2a3ab2041..ec839ffb4 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -651,6 +651,7 @@ enum NodeType {
NodeTypeSwitchProng,
NodeTypeSwitchRange,
NodeTypeCompTime,
+ NodeTypeNoAsync,
NodeTypeBreak,
NodeTypeContinue,
NodeTypeAsmExpr,
@@ -991,6 +992,10 @@ struct AstNodeCompTime {
AstNode *expr;
};
+struct AstNodeNoAsync {
+ AstNode *expr;
+};
+
struct AsmOutput {
Buf *asm_symbolic_name;
Buf *constraint;
@@ -1148,7 +1153,6 @@ struct AstNodeErrorType {
};
struct AstNodeAwaitExpr {
- Token *noasync_token;
AstNode *expr;
};
@@ -1199,6 +1203,7 @@ struct AstNode {
AstNodeSwitchProng switch_prong;
AstNodeSwitchRange switch_range;
AstNodeCompTime comptime_expr;
+ AstNodeNoAsync noasync_expr;
AstNodeAsmExpr asm_expr;
AstNodeFieldAccessExpr field_access_expr;
AstNodePtrDerefExpr ptr_deref_expr;
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index d8d0d6c0e..6bc21ce97 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -220,6 +220,8 @@ static const char *node_type_str(NodeType node_type) {
return "SwitchRange";
case NodeTypeCompTime:
return "CompTime";
+ case NodeTypeNoAsync:
+ return "NoAsync";
case NodeTypeBreak:
return "Break";
case NodeTypeContinue:
@@ -1091,6 +1093,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
render_node_grouped(ar, node->data.comptime_expr.expr);
break;
}
+ case NodeTypeNoAsync:
+ {
+ fprintf(ar->f, "noasync ");
+ render_node_grouped(ar, node->data.noasync_expr.expr);
+ break;
+ }
case NodeTypeForExpr:
{
if (node->data.for_expr.name != nullptr) {
diff --git a/src/parser.cpp b/src/parser.cpp
index 3a3e13f1d..7ff24db18 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1237,6 +1237,7 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) {
// / IfExpr
// / KEYWORD_break BreakLabel? Expr?
// / KEYWORD_comptime Expr
+// / KEYWORD_noasync Expr
// / KEYWORD_continue BreakLabel?
// / KEYWORD_resume Expr
// / KEYWORD_return Expr?
@@ -1271,6 +1272,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) {
return res;
}
+ Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
+ if (noasync != nullptr) {
+ AstNode *expr = ast_expect(pc, ast_parse_expr);
+ AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
+ res->data.noasync_expr.expr = expr;
+ return res;
+ }
+
Token *continue_token = eat_token_if(pc, TokenIdKeywordContinue);
if (continue_token != nullptr) {
Token *label = ast_parse_break_label(pc);
@@ -1459,13 +1468,11 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) {
// SuffixExpr
// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
-// / KEYWORD_noasync PrimaryTypeExpr SuffixOp* FnCallArguments
// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
- Token *async_token = eat_token(pc);
- bool is_async = async_token->id == TokenIdKeywordAsync;
- if (is_async || async_token->id == TokenIdKeywordNoAsync) {
- if (is_async && eat_token_if(pc, TokenIdKeywordFn) != nullptr) {
+ Token *async_token = eat_token_if(pc, TokenIdKeywordAsync);
+ if (async_token) {
+ if (eat_token_if(pc, TokenIdKeywordFn) != nullptr) {
// HACK: If we see the keyword `fn`, then we assume that
// we are parsing an async fn proto, and not a call.
// We therefore put back all tokens consumed by the async
@@ -1515,13 +1522,12 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
assert(args->type == NodeTypeFnCallExpr);
AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async_token);
- res->data.fn_call_expr.modifier = is_async ? CallModifierAsync : CallModifierNoAsync;
+ res->data.fn_call_expr.modifier = CallModifierAsync;
res->data.fn_call_expr.seen = false;
res->data.fn_call_expr.fn_ref_expr = child;
res->data.fn_call_expr.params = args->data.fn_call_expr.params;
return res;
}
- put_back_token(pc);
AstNode *res = ast_parse_primary_type_expr(pc);
if (res == nullptr)
@@ -1582,6 +1588,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
// / IfTypeExpr
// / INTEGER
// / KEYWORD_comptime TypeExpr
+// / KEYWORD_noasync TypeExpr
// / KEYWORD_error DOT IDENTIFIER
// / KEYWORD_false
// / KEYWORD_null
@@ -1683,6 +1690,14 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
return res;
}
+ Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
+ if (noasync != nullptr) {
+ AstNode *expr = ast_expect(pc, ast_parse_type_expr);
+ AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
+ res->data.noasync_expr.expr = expr;
+ return res;
+ }
+
Token *error = eat_token_if(pc, TokenIdKeywordError);
if (error != nullptr) {
Token *dot = expect_token(pc, TokenIdDot);
@@ -2599,14 +2614,10 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {
return res;
}
- Token *noasync_token = eat_token_if(pc, TokenIdKeywordNoAsync);
Token *await = eat_token_if(pc, TokenIdKeywordAwait);
if (await != nullptr) {
AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await);
- res->data.await_expr.noasync_token = noasync_token;
return res;
- } else if (noasync_token != nullptr) {
- put_back_token(pc);
}
return nullptr;
@@ -3125,6 +3136,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeCompTime:
visit_field(&node->data.comptime_expr.expr, visit, context);
break;
+ case NodeTypeNoAsync:
+ visit_field(&node->data.comptime_expr.expr, visit, context);
+ break;
case NodeTypeBreak:
// none
break;
From 3618256c97a9988f7d623eeabb667010ca30656f Mon Sep 17 00:00:00 2001
From: Vexu
Date: Mon, 9 Mar 2020 12:31:36 +0200
Subject: [PATCH 021/111] implement noasync scopes
---
src/all_types.hpp | 6 +++++
src/analyze.cpp | 9 +++++++
src/analyze.hpp | 1 +
src/codegen.cpp | 2 ++
src/ir.cpp | 52 +++++++++++++++++++++++++++++++++++++++--
test/compile_errors.zig | 9 +++++++
6 files changed, 77 insertions(+), 2 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index ec839ffb4..14b99228c 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -2330,6 +2330,7 @@ enum ScopeId {
ScopeIdRuntime,
ScopeIdTypeOf,
ScopeIdExpr,
+ ScopeIdNoAsync,
};
struct Scope {
@@ -2462,6 +2463,11 @@ struct ScopeCompTime {
Scope base;
};
+// This scope is created for a noasync expression.
+// NodeTypeNoAsync
+struct ScopeNoAsync {
+ Scope base;
+};
// This scope is created for a function definition.
// NodeTypeFnDef
diff --git a/src/analyze.cpp b/src/analyze.cpp
index c7bd7094d..d92400242 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -106,6 +106,7 @@ static ScopeExpr *find_expr_scope(Scope *scope) {
case ScopeIdDecls:
case ScopeIdFnDef:
case ScopeIdCompTime:
+ case ScopeIdNoAsync:
case ScopeIdVarDecl:
case ScopeIdCImport:
case ScopeIdSuspend:
@@ -226,6 +227,12 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) {
return &scope->base;
}
+Scope *create_noasync_scope(CodeGen *g, AstNode *node, Scope *parent) {
+ ScopeNoAsync *scope = heap::c_allocator.create();
+ init_scope(g, &scope->base, ScopeIdNoAsync, node, parent);
+ return &scope->base;
+}
+
Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) {
ScopeTypeOf *scope = heap::c_allocator.create();
init_scope(g, &scope->base, ScopeIdTypeOf, node, parent);
@@ -3755,6 +3762,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeCompTime:
preview_comptime_decl(g, node, decls_scope);
break;
+ case NodeTypeNoAsync:
case NodeTypeParamDecl:
case NodeTypeReturnExpr:
case NodeTypeDefer:
@@ -6176,6 +6184,7 @@ static void mark_suspension_point(Scope *scope) {
case ScopeIdDecls:
case ScopeIdFnDef:
case ScopeIdCompTime:
+ case ScopeIdNoAsync:
case ScopeIdCImport:
case ScopeIdSuspend:
case ScopeIdTypeOf:
diff --git a/src/analyze.hpp b/src/analyze.hpp
index fded1e405..98d09d452 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -125,6 +125,7 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
+Scope *create_noasync_scope(CodeGen *g, AstNode *node, Scope *parent);
Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstSrc *is_comptime);
Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent);
ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent);
diff --git a/src/codegen.cpp b/src/codegen.cpp
index ef567c27a..52ac2e793 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -687,6 +687,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
case ScopeIdLoop:
case ScopeIdSuspend:
case ScopeIdCompTime:
+ case ScopeIdNoAsync:
case ScopeIdRuntime:
case ScopeIdTypeOf:
case ScopeIdExpr:
@@ -3934,6 +3935,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) {
case ScopeIdLoop:
case ScopeIdSuspend:
case ScopeIdCompTime:
+ case ScopeIdNoAsync:
case ScopeIdRuntime:
case ScopeIdTypeOf:
case ScopeIdExpr:
diff --git a/src/ir.cpp b/src/ir.cpp
index 110778fb9..6a387e12e 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -4978,6 +4978,7 @@ static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_
case ScopeIdLoop:
case ScopeIdSuspend:
case ScopeIdCompTime:
+ case ScopeIdNoAsync:
case ScopeIdRuntime:
case ScopeIdTypeOf:
case ScopeIdExpr:
@@ -5033,6 +5034,7 @@ static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope
case ScopeIdLoop:
case ScopeIdSuspend:
case ScopeIdCompTime:
+ case ScopeIdNoAsync:
case ScopeIdRuntime:
case ScopeIdTypeOf:
case ScopeIdExpr:
@@ -7307,6 +7309,31 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
zig_unreachable();
}
+static bool is_noasync_scope(Scope *scope) {
+ for (;;) {
+ switch (scope->id) {
+ case ScopeIdNoAsync:
+ return true;
+ case ScopeIdDefer:
+ case ScopeIdDeferExpr:
+ case ScopeIdDecls:
+ case ScopeIdFnDef:
+ case ScopeIdCompTime:
+ case ScopeIdVarDecl:
+ case ScopeIdCImport:
+ case ScopeIdSuspend:
+ return false;
+ case ScopeIdExpr:
+ case ScopeIdTypeOf:
+ case ScopeIdBlock:
+ case ScopeIdLoop:
+ case ScopeIdRuntime:
+ scope = scope->parent;
+ continue;
+ }
+ }
+}
+
static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval,
ResultLoc *result_loc)
{
@@ -7315,8 +7342,19 @@ static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node,
if (node->data.fn_call_expr.modifier == CallModifierBuiltin)
return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc);
+ bool is_noasync = is_noasync_scope(scope);
+ CallModifier modifier = node->data.fn_call_expr.modifier;
+ if (is_noasync) {
+ if (modifier == CallModifierAsync) {
+ add_node_error(irb->codegen, node,
+ buf_sprintf("async call in noasync scope"));
+ return irb->codegen->invalid_inst_src;
+ }
+ modifier = CallModifierNoAsync;
+ }
+
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
- return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, node->data.fn_call_expr.modifier,
+ return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, modifier,
nullptr, node->data.fn_call_expr.params.items, node->data.fn_call_expr.params.length, lval, result_loc);
}
@@ -9170,6 +9208,14 @@ static IrInstSrc *ir_gen_comptime(IrBuilderSrc *irb, Scope *parent_scope, AstNod
return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr);
}
+static IrInstSrc *ir_gen_noasync(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) {
+ assert(node->type == NodeTypeNoAsync);
+
+ Scope *child_scope = create_noasync_scope(irb->codegen, node, parent_scope);
+ // purposefully pass null for result_loc and let EndExpr handle it
+ return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr);
+}
+
static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) {
IrInstSrc *is_comptime;
if (ir_should_inline(irb->exec, break_scope)) {
@@ -9763,7 +9809,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
{
assert(node->type == NodeTypeAwaitExpr);
- bool is_noasync = node->data.await_expr.noasync_token != nullptr;
+ bool is_noasync = is_noasync_scope(scope);
AstNode *expr_node = node->data.await_expr.expr;
if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) {
@@ -9938,6 +9984,8 @@ static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope
return ir_gen_switch_expr(irb, scope, node, lval, result_loc);
case NodeTypeCompTime:
return ir_expr_wrap(irb, scope, ir_gen_comptime(irb, scope, node, lval), result_loc);
+ case NodeTypeNoAsync:
+ return ir_expr_wrap(irb, scope, ir_gen_noasync(irb, scope, node, lval), result_loc);
case NodeTypeErrorType:
return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval, result_loc);
case NodeTypeBreak:
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 717793baa..7021f8155 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2,6 +2,15 @@ const tests = @import("tests.zig");
const std = @import("std");
pub fn addCases(cases: *tests.CompileErrorContext) void {
+ cases.addTest("combination of noasync and async",
+ \\export fn entry() void {
+ \\ noasync async foo();
+ \\}
+ \\fn foo() void {}
+ , &[_][]const u8{
+ "tmp.zig:2:13: error: async call in noasync scope",
+ });
+
cases.addTest("@TypeOf with no arguments",
\\export fn entry() void {
\\ _ = @TypeOf();
From 03c1431f9c0b651f3f1853f11112edc07555883d Mon Sep 17 00:00:00 2001
From: Vexu
Date: Mon, 9 Mar 2020 15:51:51 +0200
Subject: [PATCH 022/111] disallow resume and suspend in noasync scopes
---
lib/std/zig/ast.zig | 1 -
lib/std/zig/parse.zig | 16 ++++++++++++++--
src/ir.cpp | 44 ++++++++++++++++++++-----------------------
src/parser.cpp | 9 +++++++++
4 files changed, 43 insertions(+), 27 deletions(-)
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index 711806b81..541151966 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -1081,7 +1081,6 @@ pub const Node = struct {
pub const Noasync = struct {
base: Node = Node{ .id = .Noasync },
- doc_comments: ?*DocComment,
noasync_token: TokenIndex,
expr: *Node,
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
index 5392c18df..9a574c623 100644
--- a/lib/std/zig/parse.zig
+++ b/lib/std/zig/parse.zig
@@ -462,6 +462,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
/// Statement
/// <- KEYWORD_comptime? VarDecl
/// / KEYWORD_comptime BlockExprStatement
+/// / KEYWORD_noasync BlockExprStatement
/// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
/// / KEYWORD_defer BlockExprStatement
/// / KEYWORD_errdefer BlockExprStatement
@@ -493,6 +494,19 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
return &node.base;
}
+ if (eatToken(it, .Keyword_noasync)) |noasync_token| {
+ const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{
+ .ExpectedBlockOrAssignment = .{ .token = it.index },
+ });
+
+ const node = try arena.create(Node.Noasync);
+ node.* = .{
+ .noasync_token = noasync_token,
+ .expr = block_expr,
+ };
+ return &node.base;
+ }
+
if (eatToken(it, .Keyword_suspend)) |suspend_token| {
const semicolon = eatToken(it, .Semicolon);
@@ -898,7 +912,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
});
const node = try arena.create(Node.Noasync);
node.* = .{
- .doc_comments = null,
.noasync_token = token,
.expr = expr_node,
};
@@ -1280,7 +1293,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
const node = try arena.create(Node.Noasync);
node.* = .{
- .doc_comments = null,
.noasync_token = token,
.expr = expr,
};
diff --git a/src/ir.cpp b/src/ir.cpp
index 6a387e12e..50ace888c 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -7309,29 +7309,16 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
zig_unreachable();
}
-static bool is_noasync_scope(Scope *scope) {
- for (;;) {
- switch (scope->id) {
- case ScopeIdNoAsync:
- return true;
- case ScopeIdDefer:
- case ScopeIdDeferExpr:
- case ScopeIdDecls:
- case ScopeIdFnDef:
- case ScopeIdCompTime:
- case ScopeIdVarDecl:
- case ScopeIdCImport:
- case ScopeIdSuspend:
- return false;
- case ScopeIdExpr:
- case ScopeIdTypeOf:
- case ScopeIdBlock:
- case ScopeIdLoop:
- case ScopeIdRuntime:
- scope = scope->parent;
- continue;
- }
+static ScopeNoAsync *get_scope_noasync(Scope *scope) {
+ while (scope) {
+ if (scope->id == ScopeIdNoAsync)
+ return (ScopeNoAsync *)scope;
+ if (scope->id == ScopeIdFnDef)
+ return nullptr;
+
+ scope = scope->parent;
}
+ return nullptr;
}
static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval,
@@ -7342,7 +7329,7 @@ static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node,
if (node->data.fn_call_expr.modifier == CallModifierBuiltin)
return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc);
- bool is_noasync = is_noasync_scope(scope);
+ bool is_noasync = get_scope_noasync(scope) != nullptr;
CallModifier modifier = node->data.fn_call_expr.modifier;
if (is_noasync) {
if (modifier == CallModifierAsync) {
@@ -9796,6 +9783,10 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod
static IrInstSrc *ir_gen_resume(IrBuilderSrc *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeResume);
+ if (get_scope_noasync(scope) != nullptr) {
+ add_node_error(irb->codegen, node, buf_sprintf("resume in noasync scope"));
+ return irb->codegen->invalid_inst_src;
+ }
IrInstSrc *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr);
if (target_inst == irb->codegen->invalid_inst_src)
@@ -9809,7 +9800,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
{
assert(node->type == NodeTypeAwaitExpr);
- bool is_noasync = is_noasync_scope(scope);
+ bool is_noasync = get_scope_noasync(scope) != nullptr;
AstNode *expr_node = node->data.await_expr.expr;
if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) {
@@ -9855,6 +9846,11 @@ static IrInstSrc *ir_gen_suspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode
add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
return irb->codegen->invalid_inst_src;
}
+ if (get_scope_noasync(parent_scope) != nullptr) {
+ add_node_error(irb->codegen, node, buf_sprintf("suspend in noasync scope"));
+ return irb->codegen->invalid_inst_src;
+ }
+
ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
if (existing_suspend_scope) {
if (!existing_suspend_scope->reported_err) {
diff --git a/src/parser.cpp b/src/parser.cpp
index 7ff24db18..cdd254962 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -876,6 +876,7 @@ static AstNode *ast_parse_container_field(ParseContext *pc) {
// Statement
// <- KEYWORD_comptime? VarDecl
// / KEYWORD_comptime BlockExprStatement
+// / KEYWORD_noasync BlockExprStatement
// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
// / KEYWORD_defer BlockExprStatement
// / KEYWORD_errdefer BlockExprStatement
@@ -899,6 +900,14 @@ static AstNode *ast_parse_statement(ParseContext *pc) {
return res;
}
+ Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
+ if (noasync != nullptr) {
+ AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement);
+ AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
+ res->data.noasync_expr.expr = statement;
+ return res;
+ }
+
Token *suspend = eat_token_if(pc, TokenIdKeywordSuspend);
if (suspend != nullptr) {
AstNode *statement = nullptr;
From 3fd2cd43678d52ca2f737d991edaddfd8b73c2a4 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Mon, 9 Mar 2020 18:38:54 +0200
Subject: [PATCH 023/111] add LemonBoy's test
---
src/codegen.cpp | 2 +-
test/compile_errors.zig | 10 ++++++++--
test/stage1/behavior/async_fn.zig | 16 ++++++++++++++++
3 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 52ac2e793..a67b8dc00 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -969,7 +969,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
case PanicMsgIdResumedFnPendingAwait:
return buf_create_from_str("resumed an async function which can only be awaited");
case PanicMsgIdBadNoAsyncCall:
- return buf_create_from_str("async function called with noasync suspended");
+ return buf_create_from_str("async function called in noasync scope suspended");
case PanicMsgIdResumeNotSuspendedFn:
return buf_create_from_str("resumed a non-suspended function");
case PanicMsgIdBadSentinel:
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 7021f8155..443492022 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -4,11 +4,17 @@ const std = @import("std");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.addTest("combination of noasync and async",
\\export fn entry() void {
- \\ noasync async foo();
+ \\ noasync {
+ \\ const bar = async foo();
+ \\ suspend;
+ \\ resume bar;
+ \\ }
\\}
\\fn foo() void {}
, &[_][]const u8{
- "tmp.zig:2:13: error: async call in noasync scope",
+ "tmp.zig:3:21: error: async call in noasync scope",
+ "tmp.zig:4:9: error: suspend in noasync scope",
+ "tmp.zig:5:9: error: resume in noasync scope",
});
cases.addTest("@TypeOf with no arguments",
diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig
index 6583adec6..6b9918756 100644
--- a/test/stage1/behavior/async_fn.zig
+++ b/test/stage1/behavior/async_fn.zig
@@ -1531,3 +1531,19 @@ test "noasync await" {
S.doTheTest();
expect(S.finished);
}
+
+test "noasync on function calls" {
+ const S0 = struct {
+ b: i32 = 42,
+ };
+ const S1 = struct {
+ fn c() S0 {
+ return S0{};
+ }
+ fn d() !S0 {
+ return S0{};
+ }
+ };
+ expectEqual(@as(i32, 42), noasync S1.c().b);
+ expectEqual(@as(i32, 42), (try noasync S1.d()).b);
+}
From 9b1b44b41c2b1efe272985af44eaae84b9c4af1c Mon Sep 17 00:00:00 2001
From: Ryan Liptak
Date: Mon, 9 Mar 2020 00:52:28 -0700
Subject: [PATCH 024/111] Windows: Fix std.fs.realpath/os.realpathW for
directories
---
lib/std/os.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/std/os.zig b/lib/std/os.zig
index a6c8b32ba..460f0bee0 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -3077,7 +3077,7 @@ pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) Real
windows.FILE_SHARE_READ,
null,
windows.OPEN_EXISTING,
- windows.FILE_ATTRIBUTE_NORMAL,
+ windows.FILE_FLAG_BACKUP_SEMANTICS,
null,
);
defer windows.CloseHandle(h_file);
From 648f94c0275a85fece347ced013f89ee5eb5d800 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Mon, 9 Mar 2020 04:20:37 +1100
Subject: [PATCH 025/111] std: add some definitions for netlink sockets
---
lib/std/os/bits/linux.zig | 6 +
lib/std/os/bits/linux/netlink.zig | 498 ++++++++++++++++++++++++++++++
2 files changed, 504 insertions(+)
create mode 100644 lib/std/os/bits/linux/netlink.zig
diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig
index c5a9a7d77..e20e96181 100644
--- a/lib/std/os/bits/linux.zig
+++ b/lib/std/os/bits/linux.zig
@@ -18,6 +18,8 @@ pub usingnamespace switch (builtin.arch) {
else => struct {},
};
+pub usingnamespace @import("linux/netlink.zig");
+
const is_mips = builtin.arch.isMIPS();
pub const pid_t = i32;
@@ -30,6 +32,10 @@ pub const NAME_MAX = 255;
pub const PATH_MAX = 4096;
pub const IOV_MAX = 1024;
+/// Largest hardware address length
+/// e.g. a mac address is a type of hardware address
+pub const MAX_ADDR_LEN = 32;
+
pub const STDIN_FILENO = 0;
pub const STDOUT_FILENO = 1;
pub const STDERR_FILENO = 2;
diff --git a/lib/std/os/bits/linux/netlink.zig b/lib/std/os/bits/linux/netlink.zig
new file mode 100644
index 000000000..b40308d6f
--- /dev/null
+++ b/lib/std/os/bits/linux/netlink.zig
@@ -0,0 +1,498 @@
+usingnamespace @import("../linux.zig");
+
+/// Routing/device hook
+pub const NETLINK_ROUTE = 0;
+
+/// Unused number
+pub const NETLINK_UNUSED = 1;
+
+/// Reserved for user mode socket protocols
+pub const NETLINK_USERSOCK = 2;
+
+/// Unused number, formerly ip_queue
+pub const NETLINK_FIREWALL = 3;
+
+/// socket monitoring
+pub const NETLINK_SOCK_DIAG = 4;
+
+/// netfilter/iptables ULOG
+pub const NETLINK_NFLOG = 5;
+
+/// ipsec
+pub const NETLINK_XFRM = 6;
+
+/// SELinux event notifications
+pub const NETLINK_SELINUX = 7;
+
+/// Open-iSCSI
+pub const NETLINK_ISCSI = 8;
+
+/// auditing
+pub const NETLINK_AUDIT = 9;
+
+pub const NETLINK_FIB_LOOKUP = 10;
+
+pub const NETLINK_CONNECTOR = 11;
+
+/// netfilter subsystem
+pub const NETLINK_NETFILTER = 12;
+
+pub const NETLINK_IP6_FW = 13;
+
+/// DECnet routing messages
+pub const NETLINK_DNRTMSG = 14;
+
+/// Kernel messages to userspace
+pub const NETLINK_KOBJECT_UEVENT = 15;
+
+pub const NETLINK_GENERIC = 16;
+
+// leave room for NETLINK_DM (DM Events)
+
+/// SCSI Transports
+pub const NETLINK_SCSITRANSPORT = 18;
+
+pub const NETLINK_ECRYPTFS = 19;
+
+pub const NETLINK_RDMA = 20;
+
+/// Crypto layer
+pub const NETLINK_CRYPTO = 21;
+
+/// SMC monitoring
+pub const NETLINK_SMC = 22;
+
+// Flags values
+
+/// It is request message.
+pub const NLM_F_REQUEST = 0x01;
+
+/// Multipart message, terminated by NLMSG_DONE
+pub const NLM_F_MULTI = 0x02;
+
+/// Reply with ack, with zero or error code
+pub const NLM_F_ACK = 0x04;
+
+/// Echo this request
+pub const NLM_F_ECHO = 0x08;
+
+/// Dump was inconsistent due to sequence change
+pub const NLM_F_DUMP_INTR = 0x10;
+
+/// Dump was filtered as requested
+pub const NLM_F_DUMP_FILTERED = 0x20;
+
+// Modifiers to GET request
+
+/// specify tree root
+pub const NLM_F_ROOT = 0x100;
+
+/// return all matching
+pub const NLM_F_MATCH = 0x200;
+
+/// atomic GET
+pub const NLM_F_ATOMIC = 0x400;
+pub const NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH;
+
+// Modifiers to NEW request
+
+/// Override existing
+pub const NLM_F_REPLACE = 0x100;
+
+/// Do not touch, if it exists
+pub const NLM_F_EXCL = 0x200;
+
+/// Create, if it does not exist
+pub const NLM_F_CREATE = 0x400;
+
+/// Add to end of list
+pub const NLM_F_APPEND = 0x800;
+
+// Modifiers to DELETE request
+
+/// Do not delete recursively
+pub const NLM_F_NONREC = 0x100;
+
+// Flags for ACK message
+
+/// request was capped
+pub const NLM_F_CAPPED = 0x100;
+
+/// extended ACK TVLs were included
+pub const NLM_F_ACK_TLVS = 0x200;
+
+pub const NetlinkMessageType = extern enum(u16) {
+ /// Nothing.
+ NOOP = 0x1,
+
+ /// Error
+ ERROR = 0x2,
+
+ /// End of a dump
+ DONE = 0x3,
+
+ /// Data lost
+ OVERRUN = 0x4,
+
+ /// < 0x10: reserved control messages
+ pub const MIN_TYPE = 0x10;
+
+ // rtlink types
+
+ RTM_NEWLINK = 16,
+ RTM_DELLINK,
+ RTM_GETLINK,
+ RTM_SETLINK,
+
+ RTM_NEWADDR = 20,
+ RTM_DELADDR,
+ RTM_GETADDR,
+
+ RTM_NEWROUTE = 24,
+ RTM_DELROUTE,
+ RTM_GETROUTE,
+
+ RTM_NEWNEIGH = 28,
+ RTM_DELNEIGH,
+ RTM_GETNEIGH,
+
+ RTM_NEWRULE = 32,
+ RTM_DELRULE,
+ RTM_GETRULE,
+
+ RTM_NEWQDISC = 36,
+ RTM_DELQDISC,
+ RTM_GETQDISC,
+
+ RTM_NEWTCLASS = 40,
+ RTM_DELTCLASS,
+ RTM_GETTCLASS,
+
+ RTM_NEWTFILTER = 44,
+ RTM_DELTFILTER,
+ RTM_GETTFILTER,
+
+ RTM_NEWACTION = 48,
+ RTM_DELACTION,
+ RTM_GETACTION,
+
+ RTM_NEWPREFIX = 52,
+
+ RTM_GETMULTICAST = 58,
+
+ RTM_GETANYCAST = 62,
+
+ RTM_NEWNEIGHTBL = 64,
+ RTM_GETNEIGHTBL = 66,
+ RTM_SETNEIGHTBL,
+
+ RTM_NEWNDUSEROPT = 68,
+
+ RTM_NEWADDRLABEL = 72,
+ RTM_DELADDRLABEL,
+ RTM_GETADDRLABEL,
+
+ RTM_GETDCB = 78,
+ RTM_SETDCB,
+
+ RTM_NEWNETCONF = 80,
+ RTM_DELNETCONF,
+ RTM_GETNETCONF = 82,
+
+ RTM_NEWMDB = 84,
+ RTM_DELMDB = 85,
+ RTM_GETMDB = 86,
+
+ RTM_NEWNSID = 88,
+ RTM_DELNSID = 89,
+ RTM_GETNSID = 90,
+
+ RTM_NEWSTATS = 92,
+ RTM_GETSTATS = 94,
+
+ RTM_NEWCACHEREPORT = 96,
+
+ RTM_NEWCHAIN = 100,
+ RTM_DELCHAIN,
+ RTM_GETCHAIN,
+
+ RTM_NEWNEXTHOP = 104,
+ RTM_DELNEXTHOP,
+ RTM_GETNEXTHOP,
+
+ _,
+};
+
+/// Netlink socket address
+pub const sockaddr_nl = extern struct {
+ family: sa_family_t = AF_NETLINK,
+ __pad1: c_ushort = 0,
+
+ /// port ID
+ pid: u32,
+
+ /// multicast groups mask
+ groups: u32,
+};
+
+/// Netlink message header
+/// Specified in RFC 3549 Section 2.3.2
+pub const nlmsghdr = extern struct {
+ /// Length of message including header
+ len: u32,
+
+ /// Message content
+ @"type": NetlinkMessageType,
+
+ /// Additional flags
+ flags: u16,
+
+ /// Sequence number
+ seq: u32,
+
+ /// Sending process port ID
+ pid: u32,
+};
+
+pub const ifinfomsg = extern struct {
+ family: u8,
+ __pad1: u8 = 0,
+
+ /// ARPHRD_*
+ @"type": c_ushort,
+
+ /// Link index
+ index: c_int,
+
+ /// IFF_* flags
+ flags: c_uint,
+
+ /// IFF_* change mask
+ /// is reserved for future use and should be always set to 0xFFFFFFFF.
+ change: c_uint = 0xFFFFFFFF,
+};
+
+pub const rtattr = extern struct {
+ /// Length of option
+ len: c_ushort,
+
+ /// Type of option
+ @"type": IFLA,
+
+ pub const ALIGNTO = 4;
+};
+
+pub const IFLA = extern enum(c_ushort) {
+ UNSPEC,
+ ADDRESS,
+ BROADCAST,
+ IFNAME,
+ MTU,
+ LINK,
+ QDISC,
+ STATS,
+ COST,
+ PRIORITY,
+ MASTER,
+
+ /// Wireless Extension event
+ WIRELESS,
+
+ /// Protocol specific information for a link
+ PROTINFO,
+
+ TXQLEN,
+ MAP,
+ WEIGHT,
+ OPERSTATE,
+ LINKMODE,
+ LINKINFO,
+ NET_NS_PID,
+ IFALIAS,
+
+ /// Number of VFs if device is SR-IOV PF
+ NUM_VF,
+
+ VFINFO_LIST,
+ STATS64,
+ VF_PORTS,
+ PORT_SELF,
+ AF_SPEC,
+
+ /// Group the device belongs to
+ GROUP,
+
+ NET_NS_FD,
+
+ /// Extended info mask, VFs, etc
+ EXT_MASK,
+
+ /// Promiscuity count: > 0 means acts PROMISC
+ PROMISCUITY,
+
+ NUM_TX_QUEUES,
+ NUM_RX_QUEUES,
+ CARRIER,
+ PHYS_PORT_ID,
+ CARRIER_CHANGES,
+ PHYS_SWITCH_ID,
+ LINK_NETNSID,
+ PHYS_PORT_NAME,
+ PROTO_DOWN,
+ GSO_MAX_SEGS,
+ GSO_MAX_SIZE,
+ PAD,
+ XDP,
+ EVENT,
+
+ NEW_NETNSID,
+ IF_NETNSID = 46,
+ TARGET_NETNSID = 46, // new alias
+
+ CARRIER_UP_COUNT,
+ CARRIER_DOWN_COUNT,
+ NEW_IFINDEX,
+ MIN_MTU,
+ MAX_MTU,
+
+ _,
+};
+
+pub const rtnl_link_ifmap = extern struct {
+ mem_start: u64,
+ mem_end: u64,
+ base_addr: u64,
+ irq: u16,
+ dma: u8,
+ port: u8,
+};
+
+pub const rtnl_link_stats = extern struct {
+ /// total packets received
+ rx_packets: u32,
+
+ /// total packets transmitted
+ tx_packets: u32,
+
+ /// total bytes received
+ rx_bytes: u32,
+
+ /// total bytes transmitted
+ tx_bytes: u32,
+
+ /// bad packets received
+ rx_errors: u32,
+
+ /// packet transmit problems
+ tx_errors: u32,
+
+ /// no space in linux buffers
+ rx_dropped: u32,
+
+ /// no space available in linux
+ tx_dropped: u32,
+
+ /// multicast packets received
+ multicast: u32,
+
+ collisions: u32,
+
+ // detailed rx_errors
+
+ rx_length_errors: u32,
+
+ /// receiver ring buff overflow
+ rx_over_errors: u32,
+
+ /// recved pkt with crc error
+ rx_crc_errors: u32,
+
+ /// recv'd frame alignment error
+ rx_frame_errors: u32,
+
+ /// recv'r fifo overrun
+ rx_fifo_errors: u32,
+
+ /// receiver missed packet
+ rx_missed_errors: u32,
+
+ // detailed tx_errors
+ tx_aborted_errors: u32,
+ tx_carrier_errors: u32,
+ tx_fifo_errors: u32,
+ tx_heartbeat_errors: u32,
+ tx_window_errors: u32,
+
+ // for cslip etc
+
+ rx_compressed: u32,
+ tx_compressed: u32,
+
+ /// dropped, no handler found
+ rx_nohandler: u32,
+};
+
+pub const rtnl_link_stats64 = extern struct {
+ /// total packets received
+ rx_packets: u64,
+
+ /// total packets transmitted
+ tx_packets: u64,
+
+ /// total bytes received
+ rx_bytes: u64,
+
+ /// total bytes transmitted
+ tx_bytes: u64,
+
+ /// bad packets received
+ rx_errors: u64,
+
+ /// packet transmit problems
+ tx_errors: u64,
+
+ /// no space in linux buffers
+ rx_dropped: u64,
+
+ /// no space available in linux
+ tx_dropped: u64,
+
+ /// multicast packets received
+ multicast: u64,
+
+ collisions: u64,
+
+ // detailed rx_errors
+
+ rx_length_errors: u64,
+
+ /// receiver ring buff overflow
+ rx_over_errors: u64,
+
+ /// recved pkt with crc error
+ rx_crc_errors: u64,
+
+ /// recv'd frame alignment error
+ rx_frame_errors: u64,
+
+ /// recv'r fifo overrun
+ rx_fifo_errors: u64,
+
+ /// receiver missed packet
+ rx_missed_errors: u64,
+
+ // detailed tx_errors
+ tx_aborted_errors: u64,
+ tx_carrier_errors: u64,
+ tx_fifo_errors: u64,
+ tx_heartbeat_errors: u64,
+ tx_window_errors: u64,
+
+ // for cslip etc
+
+ rx_compressed: u64,
+ tx_compressed: u64,
+
+ /// dropped, no handler found
+ rx_nohandler: u64,
+};
From 14bbb828326a8b08cf6680a44d992e64a5de34f5 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sun, 23 Feb 2020 09:44:19 +0100
Subject: [PATCH 026/111] ir: Fix lazy comparison between @alignOf and zero
Closes #4527
---
src/ir.cpp | 15 +++++++++++++--
test/stage1/behavior/alignof.zig | 21 +++++++++++++++++++++
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 110778fb9..3adf6d1e0 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -15565,9 +15565,20 @@ static Error lazy_cmp_zero(CodeGen *codegen, AstNode *source_node, ZigValue *val
switch (val->data.x_lazy->id) {
case LazyValueIdInvalid:
zig_unreachable();
- case LazyValueIdAlignOf:
- *result = CmpGT;
+ case LazyValueIdAlignOf: {
+ LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy);
+ IrAnalyze *ira = lazy_align_of->ira;
+
+ uint32_t abi_align;
+ if ((err = type_val_resolve_abi_align(ira->codegen, source_node, lazy_align_of->target_type->value,
+ &abi_align)))
+ {
+ return err;
+ }
+
+ *result = (abi_align == 0) ? CmpEQ : CmpGT;
return ErrorNone;
+ }
case LazyValueIdSizeOf: {
LazyValueSizeOf *lazy_size_of = reinterpret_cast(val->data.x_lazy);
IrAnalyze *ira = lazy_size_of->ira;
diff --git a/test/stage1/behavior/alignof.zig b/test/stage1/behavior/alignof.zig
index f923fd935..96114ed56 100644
--- a/test/stage1/behavior/alignof.zig
+++ b/test/stage1/behavior/alignof.zig
@@ -15,3 +15,24 @@ test "@alignOf(T) before referencing T" {
comptime expect(@alignOf(Foo) == 4);
}
}
+
+test "comparison of @alignOf(T) against zero" {
+ {
+ const T = struct { x: u32 };
+ expect(!(@alignOf(T) == 0));
+ expect(@alignOf(T) != 0);
+ expect(!(@alignOf(T) < 0));
+ expect(!(@alignOf(T) <= 0));
+ expect(@alignOf(T) > 0);
+ expect(@alignOf(T) >= 0);
+ }
+ {
+ const T = struct {};
+ expect(@alignOf(T) == 0);
+ expect(!(@alignOf(T) != 0));
+ expect(!(@alignOf(T) < 0));
+ expect(@alignOf(T) <= 0);
+ expect(!(@alignOf(T) > 0));
+ expect(@alignOf(T) >= 0);
+ }
+}
From 7db6da7cb81c6b83804171e3791198a687881f43 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 9 Mar 2020 14:24:04 -0400
Subject: [PATCH 027/111] lazy_cmp_zero only resolves type is zero bits for
alignof
---
src/ir.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 3adf6d1e0..7346492c9 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -15569,14 +15569,14 @@ static Error lazy_cmp_zero(CodeGen *codegen, AstNode *source_node, ZigValue *val
LazyValueAlignOf *lazy_align_of = reinterpret_cast(val->data.x_lazy);
IrAnalyze *ira = lazy_align_of->ira;
- uint32_t abi_align;
- if ((err = type_val_resolve_abi_align(ira->codegen, source_node, lazy_align_of->target_type->value,
- &abi_align)))
+ bool is_zero_bits;
+ if ((err = type_val_resolve_zero_bits(ira->codegen, lazy_align_of->target_type->value,
+ nullptr, nullptr, &is_zero_bits)))
{
return err;
}
- *result = (abi_align == 0) ? CmpEQ : CmpGT;
+ *result = is_zero_bits ? CmpEQ : CmpGT;
return ErrorNone;
}
case LazyValueIdSizeOf: {
From e7cc45642138472c29e09cd10e31962426c1aba5 Mon Sep 17 00:00:00 2001
From: xackus <14938807+xackus@users.noreply.github.com>
Date: Mon, 9 Mar 2020 19:36:15 +0100
Subject: [PATCH 028/111] better error messages and more tests
---
src/analyze.cpp | 2 +-
src/ir.cpp | 2 +-
test/compile_errors.zig | 22 ++++++++++++++++++++--
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 638a31ab5..89e64ec54 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1957,7 +1957,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
if(!is_valid_return_type(specified_return_type)){
ErrorMsg* msg = add_node_error(g, fn_proto->return_type,
- buf_sprintf("return type '%s' not allowed", buf_ptr(&specified_return_type->name)));
+ buf_sprintf("%s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name)));
Tld *tld = find_decl(g, &fn_entry->fndef_scope->base, &specified_return_type->name);
if (tld != nullptr) {
add_error_note(g, msg, tld->source_node, buf_sprintf("type declared here"));
diff --git a/src/ir.cpp b/src/ir.cpp
index 67eabf504..d4db5455f 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -19342,7 +19342,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
if(!is_valid_return_type(specified_return_type)){
ErrorMsg *msg = ir_add_error(ira, source_instr,
- buf_sprintf("call to generic function with return type '%s' not allowed", buf_ptr(&specified_return_type->name)));
+ buf_sprintf("call to generic function with %s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name)));
add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here"));
Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name);
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 006bd3ef7..63a8a48be 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -6538,9 +6538,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn bar() !FooType {
\\ return error.InvalidValue;
\\}
+ \\export fn bav() !@TypeOf(null) {
+ \\ return error.InvalidValue;
+ \\}
+ \\export fn baz() !@TypeOf(undefined) {
+ \\ return error.InvalidValue;
+ \\}
, &[_][]const u8{
- "tmp.zig:2:18: error: return type 'FooType' not allowed",
+ "tmp.zig:2:18: error: Opaque return type 'FooType' not allowed",
"tmp.zig:1:1: note: type declared here",
+ "tmp.zig:5:18: error: Null return type '(null)' not allowed",
+ "tmp.zig:8:18: error: Undefined return type '(undefined)' not allowed",
});
cases.add("generic function returning opaque type",
@@ -6551,10 +6559,20 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn bar() void {
\\ _ = generic(FooType);
\\}
+ \\export fn bav() void {
+ \\ _ = generic(@TypeOf(null));
+ \\}
+ \\export fn baz() void {
+ \\ _ = generic(@TypeOf(undefined));
+ \\}
, &[_][]const u8{
- "tmp.zig:6:16: error: call to generic function with return type 'FooType' not allowed",
+ "tmp.zig:6:16: error: call to generic function with Opaque return type 'FooType' not allowed",
"tmp.zig:2:1: note: function declared here",
"tmp.zig:1:1: note: type declared here",
+ "tmp.zig:9:16: error: call to generic function with Null return type '(null)' not allowed",
+ "tmp.zig:2:1: note: function declared here",
+ "tmp.zig:12:16: error: call to generic function with Undefined return type '(undefined)' not allowed",
+ "tmp.zig:2:1: note: function declared here",
});
cases.add( // fixed bug #2032
From 1f44b29724b52433d84b43345a52da59f9220e62 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Mon, 9 Mar 2020 20:58:25 +0100
Subject: [PATCH 029/111] ir: Fix codegen of ?*T types where T is zero-sized
* Fix codegen for optional types that decay to a pointer, the type
behaves as a boolean
* Fix comptime evaluation of zero-sized arrays, always initialize the
internal array elements
Closes #4673
---
src/analyze.cpp | 34 +++++++++++++++++++++++++++++++
src/analyze.hpp | 1 +
src/codegen.cpp | 12 ++++++++++-
src/ir.cpp | 26 ++++++++---------------
test/stage1/behavior/optional.zig | 23 +++++++++++++++++++++
5 files changed, 77 insertions(+), 19 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index d92400242..905a6a6f9 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -5797,6 +5797,7 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
ZigValue *result = g->pass1_arena->create();
result->type = type_entry;
result->special = ConstValSpecialStatic;
+
if (result->type->id == ZigTypeIdStruct) {
// The fields array cannot be left unpopulated
const ZigType *struct_type = result->type;
@@ -5808,6 +5809,22 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
assert(field_type != nullptr);
result->data.x_struct.fields[i] = get_the_one_possible_value(g, field_type);
}
+ } else if (result->type->id == ZigTypeIdArray) {
+ // The elements array cannot be left unpopulated
+ ZigType *array_type = result->type;
+ ZigType *elem_type = array_type->data.array.child_type;
+ ZigValue *sentinel_value = array_type->data.array.sentinel;
+ const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr);
+
+ result->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count);
+ for (size_t i = 0; i < elem_count; i += 1) {
+ ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i];
+ copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type));
+ }
+ if (sentinel_value != nullptr) {
+ ZigValue *last_elem_val = &result->data.x_array.data.s_none.elements[elem_count - 1];
+ copy_const_val(g, last_elem_val, sentinel_value);
+ }
} else if (result->type->id == ZigTypeIdPointer) {
result->data.x_ptr.special = ConstPtrSpecialRef;
result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type);
@@ -9537,6 +9554,23 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) {
}
}
+bool optional_value_is_null(ZigValue *val) {
+ assert(val->special == ConstValSpecialStatic);
+ if (get_src_ptr_type(val->type) != nullptr) {
+ if (val->data.x_ptr.special == ConstPtrSpecialNull) {
+ return true;
+ } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
+ return val->data.x_ptr.data.hard_coded_addr.addr == 0;
+ } else {
+ return false;
+ }
+ } else if (is_opt_err_set(val->type)) {
+ return val->data.x_err_set == nullptr;
+ } else {
+ return val->data.x_optional == nullptr;
+ }
+}
+
bool type_is_numeric(ZigType *ty) {
switch (ty->id) {
case ZigTypeIdInvalid:
diff --git a/src/analyze.hpp b/src/analyze.hpp
index 98d09d452..0b48d357f 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -198,6 +198,7 @@ size_t type_id_index(ZigType *entry);
ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
LinkLib *create_link_lib(Buf *name);
LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
+bool optional_value_is_null(ZigValue *val);
uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry);
ZigType *get_align_amt_type(CodeGen *g);
diff --git a/src/codegen.cpp b/src/codegen.cpp
index a67b8dc00..22cb97520 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -6902,8 +6902,18 @@ check: switch (const_val->special) {
case ZigTypeIdOptional:
{
ZigType *child_type = type_entry->data.maybe.child_type;
+
if (get_src_ptr_type(type_entry) != nullptr) {
- return gen_const_val_ptr(g, const_val, name);
+ bool has_bits;
+ if ((err = type_has_bits2(g, child_type, &has_bits)))
+ codegen_report_errors_and_exit(g);
+
+ if (has_bits)
+ return gen_const_val_ptr(g, const_val, name);
+
+ // No bits, treat this value as a boolean
+ const unsigned bool_val = optional_value_is_null(const_val) ? 0 : 1;
+ return LLVMConstInt(LLVMInt1Type(), bool_val, false);
} else if (child_type->id == ZigTypeIdErrorSet) {
return gen_const_val_err_set(g, const_val, name);
} else if (!type_has_bits(g, child_type)) {
diff --git a/src/ir.cpp b/src/ir.cpp
index aab2bff81..e2cf13b77 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -15478,23 +15478,6 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
}
}
-static bool optional_value_is_null(ZigValue *val) {
- assert(val->special == ConstValSpecialStatic);
- if (get_src_ptr_type(val->type) != nullptr) {
- if (val->data.x_ptr.special == ConstPtrSpecialNull) {
- return true;
- } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
- return val->data.x_ptr.data.hard_coded_addr.addr == 0;
- } else {
- return false;
- }
- } else if (is_opt_err_set(val->type)) {
- return val->data.x_err_set == nullptr;
- } else {
- return val->data.x_optional == nullptr;
- }
-}
-
static void set_optional_value_to_null(ZigValue *val) {
assert(val->special == ConstValSpecialStatic);
if (val->type->id == ZigTypeIdNull) return; // nothing to do
@@ -17594,7 +17577,14 @@ static IrInstGen *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstSrcDeclV
ZigValue *init_val = nullptr;
if (instr_is_comptime(var_ptr) && var_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) {
- init_val = const_ptr_pointee(ira, ira->codegen, var_ptr->value, decl_var_instruction->base.base.source_node);
+ ZigValue *ptr_val = ir_resolve_const(ira, var_ptr, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ init_val = const_ptr_pointee(ira, ira->codegen, ptr_val, decl_var_instruction->base.base.source_node);
+ if (init_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
if (is_comptime_var) {
if (var->gen_is_const) {
var->const_value = init_val;
diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig
index fa002b707..7dd48769d 100644
--- a/test/stage1/behavior/optional.zig
+++ b/test/stage1/behavior/optional.zig
@@ -175,3 +175,26 @@ test "0-bit child type coerced to optional return ptr result location" {
S.doTheTest();
comptime S.doTheTest();
}
+
+test "0-bit child type coerced to optional" {
+ const S = struct {
+ fn doTheTest() void {
+ var it: Foo = .{
+ .list = undefined,
+ };
+ expect(it.foo() != null);
+ }
+
+ const Empty = struct {};
+ const Foo = struct {
+ list: [10]Empty,
+
+ fn foo(self: *Foo) ?*Empty {
+ const data = &self.list[0];
+ return data;
+ }
+ };
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
From baec74645d8757f51f1ac14483daf4438e2d77bd Mon Sep 17 00:00:00 2001
From: Vexu
Date: Tue, 10 Mar 2020 15:52:03 +0200
Subject: [PATCH 030/111] translate-c add daurnimator's pointer check to macro
cast
---
src-self-hosted/translate_c.zig | 21 ++++++++++++++++++++-
test/translate_c.zig | 8 ++++----
2 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index be3e43f3d..949178b37 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -5437,7 +5437,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
//if (@typeInfo(@TypeOf(x)) == .Pointer)
// @ptrCast(dest, x)
- //else if (@typeInfo(@TypeOf(x)) == .Integer)
+ //else if (@typeInfo(@TypeOf(x)) == .Int and @typeInfo(dest) == .Pointer)
// @intToPtr(dest, x)
//else
// @as(dest, x)
@@ -5487,6 +5487,25 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
.rhs = try transCreateNodeEnumLiteral(c, "Int"),
};
if_2.condition = &cmp_2.base;
+ const cmp_4 = try c.a().create(ast.Node.InfixOp);
+ cmp_4.* = .{
+ .op_token = try appendToken(c, .Keyword_and, "and"),
+ .lhs = &cmp_2.base,
+ .op = .BoolAnd,
+ .rhs = undefined,
+ };
+ const type_id_3 = try transCreateNodeBuiltinFnCall(c, "@typeInfo");
+ try type_id_3.params.push(inner_node);
+ type_id_3.rparen_token = try appendToken(c, .LParen, ")");
+ const cmp_3 = try c.a().create(ast.Node.InfixOp);
+ cmp_3.* = .{
+ .op_token = try appendToken(c, .EqualEqual, "=="),
+ .lhs = &type_id_3.base,
+ .op = .EqualEqual,
+ .rhs = try transCreateNodeEnumLiteral(c, "Pointer"),
+ };
+ cmp_4.rhs = &cmp_3.base;
+ if_2.condition = &cmp_4.base;
else_1.body = &if_2.base;
_ = try appendToken(c, .RParen, ")");
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 209a301f8..7e70e698d 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1429,7 +1429,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("macro pointer cast",
\\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
, &[_][]const u8{
- \\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
+ \\pub const NRF_GPIO = (if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int and @typeInfo([*c]NRF_GPIO_Type) == .Pointer) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
});
cases.add("basic macro function",
@@ -2613,11 +2613,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\#define FOO(bar) baz((void *)(baz))
\\#define BAR (void*) a
, &[_][]const u8{
- \\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)))) {
- \\ return baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)));
+ \\pub inline fn FOO(bar: var) @TypeOf(baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int and @typeInfo(*c_void) == .Pointer) @intToPtr(*c_void, baz) else @as(*c_void, baz)))) {
+ \\ return baz((if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int and @typeInfo(*c_void) == .Pointer) @intToPtr(*c_void, baz) else @as(*c_void, baz)));
\\}
,
- \\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a));
+ \\pub const BAR = (if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int and @typeInfo(*c_void) == .Pointer) @intToPtr(*c_void, a) else @as(*c_void, a));
});
cases.add("macro conditional operator",
From 4cace8f7c342b7d1b1f415cc28f48d5c98bada72 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Tue, 10 Mar 2020 15:52:54 +0200
Subject: [PATCH 031/111] properly mangle shadowed primitive types
---
src-self-hosted/translate_c.zig | 6 +++---
test/translate_c.zig | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index 949178b37..8af98a3bf 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -560,7 +560,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "_{}", .{var_name}) else var_name;
+ const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{var_name, c.getMangle()}) else var_name;
const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
@@ -677,7 +677,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "_{}", .{typedef_name}) else typedef_name;
+ const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{typedef_name, c.getMangle()}) else typedef_name;
if (mem.eql(u8, checked_name, "uint8_t"))
return transTypeDefAsBuiltin(c, typedef_decl, "u8")
@@ -4857,7 +4857,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
const name = try c.str(raw_name);
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "_{}", .{name}) else name;
+ const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{name, c.getMangle()}) else name;
if (scope.containsNow(mangled_name)) {
continue;
}
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 7e70e698d..471e1eca5 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1601,7 +1601,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("shadowing primitive types",
\\unsigned anyerror = 2;
, &[_][]const u8{
- \\pub export var _anyerror: c_uint = @bitCast(c_uint, @as(c_int, 2));
+ \\pub export var anyerror_1: c_uint = @bitCast(c_uint, @as(c_int, 2));
});
cases.add("floats",
From cb4c488cbd1e02b88ca8e7466a0945691f06d4fd Mon Sep 17 00:00:00 2001
From: Vexu
Date: Tue, 10 Mar 2020 15:57:57 +0200
Subject: [PATCH 032/111] translate-c support struct field alignment
---
src-self-hosted/clang.zig | 1 +
src-self-hosted/translate_c.zig | 20 +++++++++++++++++---
src/zig_clang.cpp | 10 ++++++++++
src/zig_clang.h | 1 +
test/translate_c.zig | 10 ++++++++++
5 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig
index 3a3b4ac19..ce2c7aea2 100644
--- a/src-self-hosted/clang.zig
+++ b/src-self-hosted/clang.zig
@@ -765,6 +765,7 @@ pub extern fn ZigClangTagDecl_isThisDeclarationADefinition(self: *const ZigClang
pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl;
pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;
pub extern fn ZigClangFieldDecl_getCanonicalDecl(field_decl: ?*const struct_ZigClangFieldDecl) ?*const struct_ZigClangFieldDecl;
+pub extern fn ZigClangFieldDecl_getAlignedAttribute(field_decl: ?*const struct_ZigClangFieldDecl, *const ZigClangASTContext) c_uint;
pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl;
pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl;
pub extern fn ZigClangFunctionDecl_getCanonicalDecl(self: ?*const struct_ZigClangFunctionDecl) ?*const struct_ZigClangFunctionDecl;
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index 8af98a3bf..f14ebe330 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -632,7 +632,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
const align_expr = blk: {
const alignment = ZigClangVarDecl_getAlignedAttribute(var_decl, rp.c.clang_context);
if (alignment != 0) {
- _ = try appendToken(rp.c, .Keyword_linksection, "align");
+ _ = try appendToken(rp.c, .Keyword_align, "align");
_ = try appendToken(rp.c, .LParen, "(");
// Clang reports the alignment in bits
const expr = try transCreateNodeInt(rp.c, alignment / 8);
@@ -827,6 +827,20 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
else => |e| return e,
};
+ const align_expr = blk: {
+ const alignment = ZigClangFieldDecl_getAlignedAttribute(field_decl, rp.c.clang_context);
+ if (alignment != 0) {
+ _ = try appendToken(rp.c, .Keyword_align, "align");
+ _ = try appendToken(rp.c, .LParen, "(");
+ // Clang reports the alignment in bits
+ const expr = try transCreateNodeInt(rp.c, alignment / 8);
+ _ = try appendToken(rp.c, .RParen, ")");
+
+ break :blk expr;
+ }
+ break :blk null;
+ };
+
const field_node = try c.a().create(ast.Node.ContainerField);
field_node.* = .{
.doc_comments = null,
@@ -834,7 +848,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
.name_token = field_name,
.type_expr = field_type,
.value_expr = null,
- .align_expr = null,
+ .align_expr = align_expr,
};
if (is_anon) {
@@ -4607,7 +4621,7 @@ fn finishTransFnProto(
if (fn_decl) |decl| {
const alignment = ZigClangFunctionDecl_getAlignedAttribute(decl, rp.c.clang_context);
if (alignment != 0) {
- _ = try appendToken(rp.c, .Keyword_linksection, "align");
+ _ = try appendToken(rp.c, .Keyword_align, "align");
_ = try appendToken(rp.c, .LParen, "(");
// Clang reports the alignment in bits
const expr = try transCreateNodeInt(rp.c, alignment / 8);
diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp
index c5ea182e8..ca93634aa 100644
--- a/src/zig_clang.cpp
+++ b/src/zig_clang.cpp
@@ -1615,6 +1615,16 @@ unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self,
return 0;
}
+unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx) {
+ auto casted_self = reinterpret_cast(self);
+ auto casted_ctx = const_cast(reinterpret_cast(ctx));
+ if (const clang::AlignedAttr *AA = casted_self->getAttr()) {
+ return AA->getAlignment(*casted_ctx);
+ }
+ // Zero means no explicit alignment factor was specified
+ return 0;
+}
+
unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx) {
auto casted_self = reinterpret_cast(self);
auto casted_ctx = const_cast(reinterpret_cast(ctx));
diff --git a/src/zig_clang.h b/src/zig_clang.h
index 579812a84..af4b04c77 100644
--- a/src/zig_clang.h
+++ b/src/zig_clang.h
@@ -865,6 +865,7 @@ ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(cons
ZIG_EXTERN_C const char* ZigClangVarDecl_getSectionAttribute(const struct ZigClangVarDecl *self, size_t *len);
ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx);
ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx);
+ZIG_EXTERN_C unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx);
ZIG_EXTERN_C struct ZigClangQualType ZigClangParmVarDecl_getOriginalType(const struct ZigClangParmVarDecl *self);
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 471e1eca5..e21c3c49a 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -3,6 +3,16 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void {
+ cases.add("struct with aligned fields",
+ \\struct foo {
+ \\ __attribute__((aligned(1))) short bar;
+ \\};
+ , &[_][]const u8{
+ \\pub const struct_foo = extern struct {
+ \\ bar: c_short align(1),
+ \\};
+ });
+
cases.add("structs with VLAs are rejected",
\\struct foo { int x; int y[]; };
\\struct bar { int x; int y[0]; };
From 3e93dce0a12e8b09f2de30276364d9ee18c6ada0 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Tue, 10 Mar 2020 12:16:56 +0100
Subject: [PATCH 033/111] std: Fix detection of Linux kernel version
---
lib/std/os/bits/linux.zig | 12 ++++++------
lib/std/zig/system.zig | 11 +++++++++--
2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig
index e20e96181..2a58c1449 100644
--- a/lib/std/os/bits/linux.zig
+++ b/lib/std/os/bits/linux.zig
@@ -1296,12 +1296,12 @@ pub const io_uring_files_update = struct {
};
pub const utsname = extern struct {
- sysname: [65]u8,
- nodename: [65]u8,
- release: [65]u8,
- version: [65]u8,
- machine: [65]u8,
- domainname: [65]u8,
+ sysname: [64:0]u8,
+ nodename: [64:0]u8,
+ release: [64:0]u8,
+ version: [64:0]u8,
+ machine: [64:0]u8,
+ domainname: [64:0]u8,
};
pub const HOST_NAME_MAX = 64;
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index a4e065e18..336dd0d31 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -201,8 +201,15 @@ pub const NativeTargetInfo = struct {
switch (Target.current.os.tag) {
.linux => {
const uts = std.os.uname();
- const release = mem.toSliceConst(u8, @ptrCast([*:0]const u8, &uts.release));
- if (std.builtin.Version.parse(release)) |ver| {
+ const release = mem.toSliceConst(u8, &uts.release);
+ // The release field may have several other fields after the
+ // kernel version
+ const kernel_version = if (mem.indexOfScalar(u8, release, '-')) |pos|
+ release[0..pos]
+ else
+ release;
+
+ if (std.builtin.Version.parse(kernel_version)) |ver| {
os.version_range.linux.range.min = ver;
os.version_range.linux.range.max = ver;
} else |err| switch (err) {
From 90c232bbe8e53c09df14536def54b33d92ddd3c5 Mon Sep 17 00:00:00 2001
From: Jonathan Marler
Date: Tue, 10 Mar 2020 12:06:10 -0600
Subject: [PATCH 034/111] add allocSentinel function
---
lib/std/mem.zig | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 4da782957..3b4382c93 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -105,6 +105,20 @@ pub const Allocator = struct {
return self.alignedAlloc(T, null, n);
}
+ /// Allocates an array of `n + 1` items of type `T` and sets the first `n`
+ /// items to `undefined` and the last item to `sentinel`. Depending on the
+ /// Allocator implementation, it may be required to call `free` once the
+ /// memory is no longer needed, to avoid a resource leak. If the
+ /// `Allocator` implementation is unknown, then correct code will
+ /// call `free` when done.
+ ///
+ /// For allocating a single item, see `create`.
+ pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem {
+ var ptr = try self.alloc(Elem, n + 1);
+ ptr[n] = sentinel;
+ return ptr[0 .. n :sentinel];
+ }
+
pub fn alignedAlloc(
self: *Allocator,
comptime T: type,
From 1ad831a0ef22f354d4e1dd5073456a0683249846 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Tue, 10 Mar 2020 20:02:22 +0200
Subject: [PATCH 035/111] fix zig fmt on noasync block
---
lib/std/zig/ast.zig | 56 ++++++++++++++++++++-----------------
lib/std/zig/parser_test.zig | 11 ++++++++
2 files changed, 41 insertions(+), 26 deletions(-)
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index 541151966..95a772376 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -500,68 +500,72 @@ pub const Node = struct {
var n = base;
while (true) {
switch (n.id) {
- Id.Root,
- Id.ContainerField,
- Id.ParamDecl,
- Id.Block,
- Id.Payload,
- Id.PointerPayload,
- Id.PointerIndexPayload,
- Id.Switch,
- Id.SwitchCase,
- Id.SwitchElse,
- Id.FieldInitializer,
- Id.DocComment,
- Id.TestDecl,
+ .Root,
+ .ContainerField,
+ .ParamDecl,
+ .Block,
+ .Payload,
+ .PointerPayload,
+ .PointerIndexPayload,
+ .Switch,
+ .SwitchCase,
+ .SwitchElse,
+ .FieldInitializer,
+ .DocComment,
+ .TestDecl,
=> return false,
- Id.While => {
+ .While => {
const while_node = @fieldParentPtr(While, "base", n);
if (while_node.@"else") |@"else"| {
n = &@"else".base;
continue;
}
- return while_node.body.id != Id.Block;
+ return while_node.body.id != .Block;
},
- Id.For => {
+ .For => {
const for_node = @fieldParentPtr(For, "base", n);
if (for_node.@"else") |@"else"| {
n = &@"else".base;
continue;
}
- return for_node.body.id != Id.Block;
+ return for_node.body.id != .Block;
},
- Id.If => {
+ .If => {
const if_node = @fieldParentPtr(If, "base", n);
if (if_node.@"else") |@"else"| {
n = &@"else".base;
continue;
}
- return if_node.body.id != Id.Block;
+ return if_node.body.id != .Block;
},
- Id.Else => {
+ .Else => {
const else_node = @fieldParentPtr(Else, "base", n);
n = else_node.body;
continue;
},
- Id.Defer => {
+ .Defer => {
const defer_node = @fieldParentPtr(Defer, "base", n);
- return defer_node.expr.id != Id.Block;
+ return defer_node.expr.id != .Block;
},
- Id.Comptime => {
+ .Comptime => {
const comptime_node = @fieldParentPtr(Comptime, "base", n);
- return comptime_node.expr.id != Id.Block;
+ return comptime_node.expr.id != .Block;
},
- Id.Suspend => {
+ .Suspend => {
const suspend_node = @fieldParentPtr(Suspend, "base", n);
if (suspend_node.body) |body| {
- return body.id != Id.Block;
+ return body.id != .Block;
}
return true;
},
+ .Noasync => {
+ const noasync_node = @fieldParentPtr(Noasync, "base", n);
+ return noasync_node.expr.id != .Block;
+ },
else => return true,
}
}
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index 9a023bb52..ddea0fc57 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -1,3 +1,14 @@
+test "zig fmt: noasync block" {
+ try testCanonical(
+ \\pub fn main() anyerror!void {
+ \\ noasync {
+ \\ var foo: Foo = .{ .bar = 42 };
+ \\ }
+ \\}
+ \\
+ );
+}
+
test "zig fmt: noasync await" {
try testCanonical(
\\fn foo() void {
From ba0e3be5cfa2f60f2f9d2a4eb319408f972796c2 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 15:27:45 -0400
Subject: [PATCH 036/111] (breaking) rework stream abstractions
The main goal here is to make the function pointers comptime, so that we
don't have to do the crazy stuff with async function frames.
Since InStream, OutStream, and SeekableStream are already generic
across error sets, it's not really worse to make them generic across the
vtable as well.
See #764 for the open issue acknowledging that using generics for these
abstractions is a design flaw.
See #130 for the efforts to make these abstractions non-generic.
This commit also changes the OutStream API so that `write` returns
number of bytes written, and `writeAll` is the one that loops until the
whole buffer is written.
---
lib/std/buffer.zig | 11 ++
lib/std/child_process.zig | 10 +-
lib/std/debug.zig | 223 ++++++++++++++------------
lib/std/dwarf.zig | 161 ++++++++++---------
lib/std/elf.zig | 48 ++++++
lib/std/fs.zig | 2 +-
lib/std/fs/file.zig | 94 +++--------
lib/std/io.zig | 219 ++++++-------------------
lib/std/io/buffered_atomic_file.zig | 50 ++++++
lib/std/io/buffered_out_stream.zig | 56 +++++++
lib/std/io/c_out_stream.zig | 43 -----
lib/std/io/counting_out_stream.zig | 42 +++++
lib/std/io/fixed_buffer_stream.zig | 66 ++++++++
lib/std/io/in_stream.zig | 83 ++++------
lib/std/io/out_stream.zig | 75 ++++-----
lib/std/io/seekable_stream.zig | 105 +++---------
lib/std/json/write_stream.zig | 32 ++--
lib/std/os.zig | 2 +-
lib/std/pdb.zig | 10 +-
lib/std/zig/ast.zig | 2 +-
lib/std/zig/render.zig | 139 ++++++++--------
src-self-hosted/libc_installation.zig | 4 +-
src-self-hosted/print_targets.zig | 13 +-
src-self-hosted/stage2.zig | 30 ++--
24 files changed, 748 insertions(+), 772 deletions(-)
create mode 100644 lib/std/io/buffered_atomic_file.zig
create mode 100644 lib/std/io/buffered_out_stream.zig
delete mode 100644 lib/std/io/c_out_stream.zig
create mode 100644 lib/std/io/counting_out_stream.zig
create mode 100644 lib/std/io/fixed_buffer_stream.zig
diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig
index 9bf024191..a33670b6d 100644
--- a/lib/std/buffer.zig
+++ b/lib/std/buffer.zig
@@ -157,6 +157,17 @@ pub const Buffer = struct {
pub fn print(self: *Buffer, comptime fmt: []const u8, args: var) !void {
return std.fmt.format(self, error{OutOfMemory}, Buffer.append, fmt, args);
}
+
+ pub fn outStream(self: *Buffer) std.io.OutStream(*Buffer, 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.
+ pub fn appendWrite(self: *Buffer, m: []const u8) !usize {
+ try self.append(m);
+ return m.len;
+ }
};
test "simple Buffer" {
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index 4f5fc2b49..95619384b 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -221,9 +221,9 @@ pub const ChildProcess = struct {
var stderr_file_in_stream = child.stderr.?.inStream();
// TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
- const stdout = try stdout_file_in_stream.stream.readAllAlloc(args.allocator, args.max_output_bytes);
+ const stdout = try stdout_file_in_stream.readAllAlloc(args.allocator, args.max_output_bytes);
errdefer args.allocator.free(stdout);
- const stderr = try stderr_file_in_stream.stream.readAllAlloc(args.allocator, args.max_output_bytes);
+ const stderr = try stderr_file_in_stream.readAllAlloc(args.allocator, args.max_output_bytes);
errdefer args.allocator.free(stderr);
return ExecResult{
@@ -857,8 +857,7 @@ fn writeIntFd(fd: i32, value: ErrInt) !void {
.io_mode = .blocking,
.async_block_allowed = File.async_block_allowed_yes,
};
- const stream = &file.outStream().stream;
- stream.writeIntNative(u64, @intCast(u64, value)) catch return error.SystemResources;
+ file.outStream().writeIntNative(u64, @intCast(u64, value)) catch return error.SystemResources;
}
fn readIntFd(fd: i32) !ErrInt {
@@ -867,8 +866,7 @@ fn readIntFd(fd: i32) !ErrInt {
.io_mode = .blocking,
.async_block_allowed = File.async_block_allowed_yes,
};
- const stream = &file.inStream().stream;
- return @intCast(ErrInt, stream.readIntNative(u64) catch return error.SystemResources);
+ return @intCast(ErrInt, file.inStream().readIntNative(u64) catch return error.SystemResources);
}
/// Caller must free result.
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 558b7e051..5c5649051 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -55,7 +55,7 @@ pub const LineInfo = struct {
var stderr_file: File = undefined;
var stderr_file_out_stream: File.OutStream = undefined;
-var stderr_stream: ?*io.OutStream(File.WriteError) = null;
+var stderr_stream: ?*File.OutStream = null;
var stderr_mutex = std.Mutex.init();
pub fn warn(comptime fmt: []const u8, args: var) void {
@@ -65,13 +65,13 @@ pub fn warn(comptime fmt: []const u8, args: var) void {
noasync stderr.print(fmt, args) catch return;
}
-pub fn getStderrStream() *io.OutStream(File.WriteError) {
+pub fn getStderrStream() *File.OutStream {
if (stderr_stream) |st| {
return st;
} else {
stderr_file = io.getStdErr();
stderr_file_out_stream = stderr_file.outStream();
- const st = &stderr_file_out_stream.stream;
+ const st = &stderr_file_out_stream;
stderr_stream = st;
return st;
}
@@ -408,15 +408,15 @@ pub const TTY = struct {
windows_api,
fn setColor(conf: Config, out_stream: var, color: Color) void {
- switch (conf) {
+ noasync switch (conf) {
.no_color => return,
.escape_codes => switch (color) {
- .Red => noasync out_stream.write(RED) catch return,
- .Green => noasync out_stream.write(GREEN) catch return,
- .Cyan => noasync out_stream.write(CYAN) catch return,
- .White, .Bold => noasync out_stream.write(WHITE) catch return,
- .Dim => noasync out_stream.write(DIM) catch return,
- .Reset => noasync out_stream.write(RESET) catch return,
+ .Red => out_stream.writeAll(RED) catch return,
+ .Green => out_stream.writeAll(GREEN) catch return,
+ .Cyan => out_stream.writeAll(CYAN) catch return,
+ .White, .Bold => out_stream.writeAll(WHITE) catch return,
+ .Dim => out_stream.writeAll(DIM) catch return,
+ .Reset => out_stream.writeAll(RESET) catch return,
},
.windows_api => if (builtin.os.tag == .windows) {
const S = struct {
@@ -455,7 +455,7 @@ pub const TTY = struct {
} else {
unreachable;
},
- }
+ };
}
};
};
@@ -565,38 +565,40 @@ fn printLineInfo(
tty_config: TTY.Config,
comptime printLineFromFile: var,
) !void {
- tty_config.setColor(out_stream, .White);
+ noasync {
+ tty_config.setColor(out_stream, .White);
- if (line_info) |*li| {
- try noasync out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });
- } else {
- try noasync out_stream.write("???:?:?");
- }
+ if (line_info) |*li| {
+ try out_stream.print("{}:{}:{}", .{ li.file_name, li.line, li.column });
+ } else {
+ try out_stream.writeAll("???:?:?");
+ }
- tty_config.setColor(out_stream, .Reset);
- try noasync out_stream.write(": ");
- tty_config.setColor(out_stream, .Dim);
- try noasync out_stream.print("0x{x} in {} ({})", .{ address, symbol_name, compile_unit_name });
- tty_config.setColor(out_stream, .Reset);
- try noasync out_stream.write("\n");
+ 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 });
+ tty_config.setColor(out_stream, .Reset);
+ try out_stream.writeAll("\n");
- // Show the matching source code line if possible
- if (line_info) |li| {
- if (noasync printLineFromFile(out_stream, li)) {
- if (li.column > 0) {
- // The caret already takes one char
- const space_needed = @intCast(usize, li.column - 1);
+ // Show the matching source code line if possible
+ if (line_info) |li| {
+ if (printLineFromFile(out_stream, li)) {
+ if (li.column > 0) {
+ // The caret already takes one char
+ const space_needed = @intCast(usize, li.column - 1);
- try noasync out_stream.writeByteNTimes(' ', space_needed);
- tty_config.setColor(out_stream, .Green);
- try noasync out_stream.write("^");
- tty_config.setColor(out_stream, .Reset);
+ try out_stream.writeByteNTimes(' ', space_needed);
+ tty_config.setColor(out_stream, .Green);
+ try out_stream.writeAll("^");
+ tty_config.setColor(out_stream, .Reset);
+ }
+ try out_stream.writeAll("\n");
+ } else |err| switch (err) {
+ error.EndOfFile, error.FileNotFound => {},
+ error.BadPathName => {},
+ else => return err,
}
- try noasync out_stream.write("\n");
- } else |err| switch (err) {
- error.EndOfFile, error.FileNotFound => {},
- error.BadPathName => {},
- else => return err,
}
}
}
@@ -609,21 +611,21 @@ pub const OpenSelfDebugInfoError = error{
};
/// TODO resources https://github.com/ziglang/zig/issues/4353
-/// TODO once https://github.com/ziglang/zig/issues/3157 is fully implemented,
-/// make this `noasync fn` and remove the individual noasync calls.
pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
- if (builtin.strip_debug_info)
- return error.MissingDebugInfo;
- if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
- return noasync root.os.debug.openSelfDebugInfo(allocator);
- }
- switch (builtin.os.tag) {
- .linux,
- .freebsd,
- .macosx,
- .windows,
- => return DebugInfo.init(allocator),
- else => @compileError("openSelfDebugInfo unsupported for this platform"),
+ noasync {
+ if (builtin.strip_debug_info)
+ return error.MissingDebugInfo;
+ if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
+ return root.os.debug.openSelfDebugInfo(allocator);
+ }
+ switch (builtin.os.tag) {
+ .linux,
+ .freebsd,
+ .macosx,
+ .windows,
+ => return DebugInfo.init(allocator),
+ else => @compileError("openSelfDebugInfo unsupported for this platform"),
+ }
}
}
@@ -808,45 +810,64 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 {
/// TODO resources https://github.com/ziglang/zig/issues/4353
pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo {
- const mapped_mem = try mapWholeFile(elf_file_path);
+ noasync {
+ const mapped_mem = try mapWholeFile(elf_file_path);
+ const hdr = @ptrCast(*const elf.Ehdr, &mapped_mem[0]);
+ if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
+ if (hdr.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion;
- var seekable_stream = io.SliceSeekableInStream.init(mapped_mem);
- var efile = try noasync elf.Elf.openStream(
- allocator,
- @ptrCast(*DW.DwarfSeekableStream, &seekable_stream.seekable_stream),
- @ptrCast(*DW.DwarfInStream, &seekable_stream.stream),
- );
- defer noasync efile.close();
+ const endian: builtin.Endian = switch (hdr.e_ident[elf.EI_DATA]) {
+ elf.ELFDATA2LSB => .Little,
+ elf.ELFDATA2MSB => .Big,
+ else => return error.InvalidElfEndian,
+ };
+ assert(endian == std.builtin.endian); // this is our own debug info
- const debug_info = (try noasync efile.findSection(".debug_info")) orelse
- return error.MissingDebugInfo;
- const debug_abbrev = (try noasync efile.findSection(".debug_abbrev")) orelse
- return error.MissingDebugInfo;
- const debug_str = (try noasync efile.findSection(".debug_str")) orelse
- return error.MissingDebugInfo;
- const debug_line = (try noasync efile.findSection(".debug_line")) orelse
- return error.MissingDebugInfo;
- const opt_debug_ranges = try noasync efile.findSection(".debug_ranges");
+ const shoff = hdr.e_shoff;
+ const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx);
+ const header_strings = mapped_mem[str_section_off..str_section_off + hdr.e_shentsize];
+ const shdrs = @ptrCast([*]const elf.Shdr, @alignCast(@alignOf(elf.Shdr), &mapped_mem[shoff]))[0..hdr.e_shnum];
- var di = DW.DwarfInfo{
- .endian = efile.endian,
- .debug_info = try chopSlice(mapped_mem, debug_info.sh_offset, debug_info.sh_size),
- .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.sh_offset, debug_abbrev.sh_size),
- .debug_str = try chopSlice(mapped_mem, debug_str.sh_offset, debug_str.sh_size),
- .debug_line = try chopSlice(mapped_mem, debug_line.sh_offset, debug_line.sh_size),
- .debug_ranges = if (opt_debug_ranges) |debug_ranges|
- try chopSlice(mapped_mem, debug_ranges.sh_offset, debug_ranges.sh_size)
- else
- null,
- };
+ var opt_debug_info: ?[]const u8 = null;
+ var opt_debug_abbrev: ?[]const u8 = null;
+ var opt_debug_str: ?[]const u8 = null;
+ var opt_debug_line: ?[]const u8 = null;
+ var opt_debug_ranges: ?[]const u8 = null;
- try noasync DW.openDwarfDebugInfo(&di, allocator);
+ for (shdrs) |*shdr| {
+ if (shdr.sh_type == elf.SHT_NULL) continue;
- return ModuleDebugInfo{
- .base_address = undefined,
- .dwarf = di,
- .mapped_memory = mapped_mem,
- };
+ const name = std.mem.span(@ptrCast([*:0]const u8, header_strings[shdr.sh_name..].ptr));
+ if (mem.eql(u8, name, ".debug_info")) {
+ opt_debug_info = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
+ } else if (mem.eql(u8, name, ".debug_abbrev")) {
+ opt_debug_abbrev = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
+ } else if (mem.eql(u8, name, ".debug_str")) {
+ opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
+ } else if (mem.eql(u8, name, ".debug_line")) {
+ opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
+ } else if (mem.eql(u8, name, ".debug_ranges")) {
+ opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
+ }
+ }
+
+ var di = DW.DwarfInfo{
+ .endian = endian,
+ .debug_info = opt_debug_info orelse return error.MissingDebugInfo,
+ .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo,
+ .debug_str = opt_debug_str orelse return error.MissingDebugInfo,
+ .debug_line = opt_debug_line orelse return error.MissingDebugInfo,
+ .debug_ranges = opt_debug_ranges,
+ };
+
+ try DW.openDwarfDebugInfo(&di, allocator);
+
+ return ModuleDebugInfo{
+ .base_address = undefined,
+ .dwarf = di,
+ .mapped_memory = mapped_mem,
+ };
+ }
}
/// TODO resources https://github.com/ziglang/zig/issues/4353
@@ -982,22 +1003,24 @@ const MachoSymbol = struct {
}
};
-fn mapWholeFile(path: []const u8) ![]const u8 {
- const file = try noasync fs.openFileAbsolute(path, .{ .always_blocking = true });
- defer noasync file.close();
+fn mapWholeFile(path: []const u8) ![]align(mem.page_size) const u8 {
+ noasync {
+ const file = try fs.openFileAbsolute(path, .{ .always_blocking = true });
+ defer file.close();
- const file_len = try math.cast(usize, try file.getEndPos());
- const mapped_mem = try os.mmap(
- null,
- file_len,
- os.PROT_READ,
- os.MAP_SHARED,
- file.handle,
- 0,
- );
- errdefer os.munmap(mapped_mem);
+ const file_len = try math.cast(usize, try file.getEndPos());
+ const mapped_mem = try os.mmap(
+ null,
+ file_len,
+ os.PROT_READ,
+ os.MAP_SHARED,
+ file.handle,
+ 0,
+ );
+ errdefer os.munmap(mapped_mem);
- return mapped_mem;
+ return mapped_mem;
+ }
}
pub const DebugInfo = struct {
diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig
index 32a49b68e..769f349e3 100644
--- a/lib/std/dwarf.zig
+++ b/lib/std/dwarf.zig
@@ -11,9 +11,6 @@ const ArrayList = std.ArrayList;
usingnamespace @import("dwarf_bits.zig");
-pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
-pub const DwarfInStream = io.InStream(anyerror);
-
const PcRange = struct {
start: u64,
end: u64,
@@ -239,7 +236,7 @@ const LineNumberProgram = struct {
}
};
-fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
+fn readInitialLength(in_stream: var, is_64: *bool) !u64 {
const first_32_bits = try in_stream.readIntLittle(u32);
is_64.* = (first_32_bits == 0xffffffff);
if (is_64.*) {
@@ -414,40 +411,42 @@ pub const DwarfInfo = struct {
}
fn scanAllFunctions(di: *DwarfInfo) !void {
- var s = io.SliceSeekableInStream.init(di.debug_info);
+ var stream = io.fixedBufferStream(di.debug_info);
+ const in = &stream.inStream();
+ const seekable = &stream.seekableStream();
var this_unit_offset: u64 = 0;
- while (this_unit_offset < try s.seekable_stream.getEndPos()) {
- s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
+ while (this_unit_offset < try seekable.getEndPos()) {
+ seekable.seekTo(this_unit_offset) catch |err| switch (err) {
error.EndOfStream => unreachable,
else => return err,
};
var is_64: bool = undefined;
- const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
+ const unit_length = try readInitialLength(in, &is_64);
if (unit_length == 0) return;
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
- const version = try s.stream.readInt(u16, di.endian);
+ const version = try in.readInt(u16, di.endian);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
- const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
+ const debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
- const address_size = try s.stream.readByte();
+ const address_size = try in.readByte();
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
- const compile_unit_pos = try s.seekable_stream.getPos();
+ const compile_unit_pos = try seekable.getPos();
const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
- try s.seekable_stream.seekTo(compile_unit_pos);
+ try seekable.seekTo(compile_unit_pos);
const next_unit_pos = this_unit_offset + next_offset;
- while ((try s.seekable_stream.getPos()) < next_unit_pos) {
- const die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse continue;
+ while ((try seekable.getPos()) < next_unit_pos) {
+ const die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse continue;
defer die_obj.attrs.deinit();
- const after_die_offset = try s.seekable_stream.getPos();
+ const after_die_offset = try seekable.getPos();
switch (die_obj.tag_id) {
TAG_subprogram, TAG_inlined_subroutine, TAG_subroutine, TAG_entry_point => {
@@ -463,14 +462,14 @@ pub const DwarfInfo = struct {
// Follow the DIE it points to and repeat
const ref_offset = try this_die_obj.getAttrRef(AT_abstract_origin);
if (ref_offset > next_offset) return error.InvalidDebugInfo;
- try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
- this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
+ try seekable.seekTo(this_unit_offset + ref_offset);
+ this_die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
} else if (this_die_obj.getAttr(AT_specification)) |ref| {
// Follow the DIE it points to and repeat
const ref_offset = try this_die_obj.getAttrRef(AT_specification);
if (ref_offset > next_offset) return error.InvalidDebugInfo;
- try s.seekable_stream.seekTo(this_unit_offset + ref_offset);
- this_die_obj = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
+ try seekable.seekTo(this_unit_offset + ref_offset);
+ this_die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
} else {
break :x null;
}
@@ -511,7 +510,7 @@ pub const DwarfInfo = struct {
else => {},
}
- try s.seekable_stream.seekTo(after_die_offset);
+ try seekable.seekTo(after_die_offset);
}
this_unit_offset += next_offset;
@@ -519,35 +518,37 @@ pub const DwarfInfo = struct {
}
fn scanAllCompileUnits(di: *DwarfInfo) !void {
- var s = io.SliceSeekableInStream.init(di.debug_info);
+ var stream = io.fixedBufferStream(di.debug_info);
+ const in = &stream.inStream();
+ const seekable = &stream.seekableStream();
var this_unit_offset: u64 = 0;
- while (this_unit_offset < try s.seekable_stream.getEndPos()) {
- s.seekable_stream.seekTo(this_unit_offset) catch |err| switch (err) {
+ while (this_unit_offset < try seekable.getEndPos()) {
+ seekable.seekTo(this_unit_offset) catch |err| switch (err) {
error.EndOfStream => unreachable,
else => return err,
};
var is_64: bool = undefined;
- const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
+ const unit_length = try readInitialLength(in, &is_64);
if (unit_length == 0) return;
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
- const version = try s.stream.readInt(u16, di.endian);
+ const version = try in.readInt(u16, di.endian);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
- const debug_abbrev_offset = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
+ const debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
- const address_size = try s.stream.readByte();
+ const address_size = try in.readByte();
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
- const compile_unit_pos = try s.seekable_stream.getPos();
+ const compile_unit_pos = try seekable.getPos();
const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset);
- try s.seekable_stream.seekTo(compile_unit_pos);
+ try seekable.seekTo(compile_unit_pos);
const compile_unit_die = try di.allocator().create(Die);
- compile_unit_die.* = (try di.parseDie(&s.stream, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
+ compile_unit_die.* = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo;
if (compile_unit_die.tag_id != TAG_compile_unit) return error.InvalidDebugInfo;
@@ -593,7 +594,9 @@ pub const DwarfInfo = struct {
}
if (di.debug_ranges) |debug_ranges| {
if (compile_unit.die.getAttrSecOffset(AT_ranges)) |ranges_offset| {
- var s = io.SliceSeekableInStream.init(debug_ranges);
+ var stream = io.fixedBufferStream(debug_ranges);
+ const in = &stream.inStream();
+ const seekable = &stream.seekableStream();
// All the addresses in the list are relative to the value
// specified by DW_AT_low_pc or to some other value encoded
@@ -604,11 +607,11 @@ pub const DwarfInfo = struct {
else => return err,
};
- try s.seekable_stream.seekTo(ranges_offset);
+ try seekable.seekTo(ranges_offset);
while (true) {
- const begin_addr = try s.stream.readIntLittle(usize);
- const end_addr = try s.stream.readIntLittle(usize);
+ const begin_addr = try in.readIntLittle(usize);
+ const end_addr = try in.readIntLittle(usize);
if (begin_addr == 0 and end_addr == 0) {
break;
}
@@ -646,25 +649,27 @@ pub const DwarfInfo = struct {
}
fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable {
- var s = io.SliceSeekableInStream.init(di.debug_abbrev);
+ var stream = io.fixedBufferStream(di.debug_abbrev);
+ const in = &stream.inStream();
+ const seekable = &stream.seekableStream();
- try s.seekable_stream.seekTo(offset);
+ try seekable.seekTo(offset);
var result = AbbrevTable.init(di.allocator());
errdefer result.deinit();
while (true) {
- const abbrev_code = try leb.readULEB128(u64, &s.stream);
+ const abbrev_code = try leb.readULEB128(u64, in);
if (abbrev_code == 0) return result;
try result.append(AbbrevTableEntry{
.abbrev_code = abbrev_code,
- .tag_id = try leb.readULEB128(u64, &s.stream),
- .has_children = (try s.stream.readByte()) == CHILDREN_yes,
+ .tag_id = try leb.readULEB128(u64, in),
+ .has_children = (try in.readByte()) == CHILDREN_yes,
.attrs = ArrayList(AbbrevAttr).init(di.allocator()),
});
const attrs = &result.items[result.len - 1].attrs;
while (true) {
- const attr_id = try leb.readULEB128(u64, &s.stream);
- const form_id = try leb.readULEB128(u64, &s.stream);
+ const attr_id = try leb.readULEB128(u64, in);
+ const form_id = try leb.readULEB128(u64, in);
if (attr_id == 0 and form_id == 0) break;
try attrs.append(AbbrevAttr{
.attr_id = attr_id,
@@ -695,42 +700,44 @@ pub const DwarfInfo = struct {
}
fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !debug.LineInfo {
- var s = io.SliceSeekableInStream.init(di.debug_line);
+ var stream = io.fixedBufferStream(di.debug_line);
+ const in = &stream.inStream();
+ const seekable = &stream.seekableStream();
const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT_comp_dir);
const line_info_offset = try compile_unit.die.getAttrSecOffset(AT_stmt_list);
- try s.seekable_stream.seekTo(line_info_offset);
+ try seekable.seekTo(line_info_offset);
var is_64: bool = undefined;
- const unit_length = try readInitialLength(@TypeOf(s.stream.readFn).ReturnType.ErrorSet, &s.stream, &is_64);
+ const unit_length = try readInitialLength(in, &is_64);
if (unit_length == 0) {
return error.MissingDebugInfo;
}
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
- const version = try s.stream.readInt(u16, di.endian);
+ const version = try in.readInt(u16, di.endian);
// TODO support 3 and 5
if (version != 2 and version != 4) return error.InvalidDebugInfo;
- const prologue_length = if (is_64) try s.stream.readInt(u64, di.endian) else try s.stream.readInt(u32, di.endian);
- const prog_start_offset = (try s.seekable_stream.getPos()) + prologue_length;
+ const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
+ const prog_start_offset = (try seekable.getPos()) + prologue_length;
- const minimum_instruction_length = try s.stream.readByte();
+ const minimum_instruction_length = try in.readByte();
if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
if (version >= 4) {
// maximum_operations_per_instruction
- _ = try s.stream.readByte();
+ _ = try in.readByte();
}
- const default_is_stmt = (try s.stream.readByte()) != 0;
- const line_base = try s.stream.readByteSigned();
+ const default_is_stmt = (try in.readByte()) != 0;
+ const line_base = try in.readByteSigned();
- const line_range = try s.stream.readByte();
+ const line_range = try in.readByte();
if (line_range == 0) return error.InvalidDebugInfo;
- const opcode_base = try s.stream.readByte();
+ const opcode_base = try in.readByte();
const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
defer di.allocator().free(standard_opcode_lengths);
@@ -738,14 +745,14 @@ pub const DwarfInfo = struct {
{
var i: usize = 0;
while (i < opcode_base - 1) : (i += 1) {
- standard_opcode_lengths[i] = try s.stream.readByte();
+ standard_opcode_lengths[i] = try in.readByte();
}
}
var include_directories = ArrayList([]const u8).init(di.allocator());
try include_directories.append(compile_unit_cwd);
while (true) {
- const dir = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
+ const dir = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
if (dir.len == 0) break;
try include_directories.append(dir);
}
@@ -754,11 +761,11 @@ pub const DwarfInfo = struct {
var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address);
while (true) {
- const file_name = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
+ const file_name = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
if (file_name.len == 0) break;
- const dir_index = try leb.readULEB128(usize, &s.stream);
- const mtime = try leb.readULEB128(usize, &s.stream);
- const len_bytes = try leb.readULEB128(usize, &s.stream);
+ const dir_index = try leb.readULEB128(usize, in);
+ const mtime = try leb.readULEB128(usize, in);
+ const len_bytes = try leb.readULEB128(usize, in);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
@@ -767,17 +774,17 @@ pub const DwarfInfo = struct {
});
}
- try s.seekable_stream.seekTo(prog_start_offset);
+ try seekable.seekTo(prog_start_offset);
const next_unit_pos = line_info_offset + next_offset;
- while ((try s.seekable_stream.getPos()) < next_unit_pos) {
- const opcode = try s.stream.readByte();
+ while ((try seekable.getPos()) < next_unit_pos) {
+ const opcode = try in.readByte();
if (opcode == LNS_extended_op) {
- const op_size = try leb.readULEB128(u64, &s.stream);
+ const op_size = try leb.readULEB128(u64, in);
if (op_size < 1) return error.InvalidDebugInfo;
- var sub_op = try s.stream.readByte();
+ var sub_op = try in.readByte();
switch (sub_op) {
LNE_end_sequence => {
prog.end_sequence = true;
@@ -785,14 +792,14 @@ pub const DwarfInfo = struct {
prog.reset();
},
LNE_set_address => {
- const addr = try s.stream.readInt(usize, di.endian);
+ const addr = try in.readInt(usize, di.endian);
prog.address = addr;
},
LNE_define_file => {
- const file_name = try s.stream.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
- const dir_index = try leb.readULEB128(usize, &s.stream);
- const mtime = try leb.readULEB128(usize, &s.stream);
- const len_bytes = try leb.readULEB128(usize, &s.stream);
+ const file_name = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize));
+ const dir_index = try leb.readULEB128(usize, in);
+ const mtime = try leb.readULEB128(usize, in);
+ const len_bytes = try leb.readULEB128(usize, in);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
@@ -802,7 +809,7 @@ pub const DwarfInfo = struct {
},
else => {
const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
- try s.seekable_stream.seekBy(fwd_amt);
+ try seekable.seekBy(fwd_amt);
},
}
} else if (opcode >= opcode_base) {
@@ -821,19 +828,19 @@ pub const DwarfInfo = struct {
prog.basic_block = false;
},
LNS_advance_pc => {
- const arg = try leb.readULEB128(usize, &s.stream);
+ const arg = try leb.readULEB128(usize, in);
prog.address += arg * minimum_instruction_length;
},
LNS_advance_line => {
- const arg = try leb.readILEB128(i64, &s.stream);
+ const arg = try leb.readILEB128(i64, in);
prog.line += arg;
},
LNS_set_file => {
- const arg = try leb.readULEB128(usize, &s.stream);
+ const arg = try leb.readULEB128(usize, in);
prog.file = arg;
},
LNS_set_column => {
- const arg = try leb.readULEB128(u64, &s.stream);
+ const arg = try leb.readULEB128(u64, in);
prog.column = arg;
},
LNS_negate_stmt => {
@@ -847,14 +854,14 @@ pub const DwarfInfo = struct {
prog.address += inc_addr;
},
LNS_fixed_advance_pc => {
- const arg = try s.stream.readInt(u16, di.endian);
+ const arg = try in.readInt(u16, di.endian);
prog.address += arg;
},
LNS_set_prologue_end => {},
else => {
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
const len_bytes = standard_opcode_lengths[opcode - 1];
- try s.seekable_stream.seekBy(len_bytes);
+ try seekable.seekBy(len_bytes);
},
}
}
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index fc57db7c9..efaa4d6f0 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -333,6 +333,54 @@ pub const ET = extern enum(u16) {
pub const SectionHeader = Elf64_Shdr;
pub const ProgramHeader = Elf64_Phdr;
+const Header = struct {
+ endian: builtin.Endian,
+ is_64: bool,
+ entry: u64,
+ phoff: u64,
+ shoff: u64,
+ phentsize: u16,
+ phnum: u16,
+ shentsize: u16,
+ shnum: u16,
+ shstrndx: u16,
+};
+
+pub fn readHeader(in_stream: var) !Header {
+ var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
+ try in_stream.readAll(&hdr_buf);
+ const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
+ const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
+ if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
+ if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
+
+ const endian = switch (hdr32.e_ident[elf.EI_DATA]) {
+ ELFDATA2LSB => .Little,
+ ELFDATA2MSB => .Big,
+ else => return error.InvalidElfEndian,
+ };
+ const need_bswap = endian != std.builtin.endian;
+
+ const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
+ ELFCLASS32 => false,
+ ELFCLASS64 => true,
+ else => return error.InvalidElfClass,
+ };
+
+ return @as(Header, .{
+ .endian = endian,
+ .is_64 = is_64,
+ .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
+ .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
+ .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
+ .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
+ .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
+ .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
+ .shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
+ .shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
+ });
+}
+
pub const Elf = struct {
seekable_stream: *io.SeekableStream(anyerror, anyerror),
in_stream: *io.InStream(anyerror),
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 1f20a14f7..892b97729 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -1150,7 +1150,7 @@ pub const Dir = struct {
const buf = try allocator.alignedAlloc(u8, A, size);
errdefer allocator.free(buf);
- try file.inStream().stream.readNoEof(buf);
+ try file.inStream().readNoEof(buf);
return buf;
}
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 8f7a46ad3..845e4bc75 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -71,7 +71,7 @@ pub const File = struct {
if (need_async_thread and self.io_mode == .blocking and !self.async_block_allowed) {
std.event.Loop.instance.?.close(self.handle);
} else {
- return os.close(self.handle);
+ os.close(self.handle);
}
}
@@ -496,85 +496,29 @@ pub const File = struct {
}
}
- pub fn inStream(file: File) InStream {
- return InStream{
- .file = file,
- .stream = InStream.Stream{ .readFn = InStream.readFn },
- };
+ pub const InStream = io.InStream(File, ReadError, read);
+
+ pub fn inStream(file: File) io.InStream(File, ReadError, read) {
+ return .{ .context = file };
}
+ pub const OutStream = io.OutStream(File, WriteError, write);
+
pub fn outStream(file: File) OutStream {
- return OutStream{
- .file = file,
- .stream = OutStream.Stream{ .writeFn = OutStream.writeFn },
- };
+ return .{ .context = file };
}
+ pub const SeekableStream = io.SeekableStream(
+ File,
+ SeekError,
+ GetPosError,
+ seekTo,
+ seekBy,
+ getPos,
+ getEndPos,
+ );
+
pub fn seekableStream(file: File) SeekableStream {
- return SeekableStream{
- .file = file,
- .stream = SeekableStream.Stream{
- .seekToFn = SeekableStream.seekToFn,
- .seekByFn = SeekableStream.seekByFn,
- .getPosFn = SeekableStream.getPosFn,
- .getEndPosFn = SeekableStream.getEndPosFn,
- },
- };
+ return .{ .context = file };
}
-
- /// Implementation of io.InStream trait for File
- pub const InStream = struct {
- file: File,
- stream: Stream,
-
- pub const Error = ReadError;
- pub const Stream = io.InStream(Error);
-
- fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
- const self = @fieldParentPtr(InStream, "stream", in_stream);
- return self.file.read(buffer);
- }
- };
-
- /// Implementation of io.OutStream trait for File
- pub const OutStream = struct {
- file: File,
- stream: Stream,
-
- pub const Error = WriteError;
- pub const Stream = io.OutStream(Error);
-
- fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
- const self = @fieldParentPtr(OutStream, "stream", out_stream);
- return self.file.write(bytes);
- }
- };
-
- /// Implementation of io.SeekableStream trait for File
- pub const SeekableStream = struct {
- file: File,
- stream: Stream,
-
- pub const Stream = io.SeekableStream(SeekError, GetPosError);
-
- pub fn seekToFn(seekable_stream: *Stream, pos: u64) SeekError!void {
- const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
- return self.file.seekTo(pos);
- }
-
- pub fn seekByFn(seekable_stream: *Stream, amt: i64) SeekError!void {
- const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
- return self.file.seekBy(amt);
- }
-
- pub fn getEndPosFn(seekable_stream: *Stream) GetPosError!u64 {
- const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
- return self.file.getEndPos();
- }
-
- pub fn getPosFn(seekable_stream: *Stream) GetPosError!u64 {
- const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
- return self.file.getPos();
- }
- };
};
diff --git a/lib/std/io.zig b/lib/std/io.zig
index 99e9391f1..dcb0551dc 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -93,10 +93,46 @@ pub fn getStdIn() File {
}
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
-pub const SliceSeekableInStream = @import("io/seekable_stream.zig").SliceSeekableInStream;
-pub const COutStream = @import("io/c_out_stream.zig").COutStream;
pub const InStream = @import("io/in_stream.zig").InStream;
pub const OutStream = @import("io/out_stream.zig").OutStream;
+pub const FixedBufferInStream = @import("io/fixed_buffer_stream.zig").FixedBufferInStream;
+pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile;
+
+pub const BufferedOutStream = @import("io/buffered_out_stream.zig").BufferedOutStream;
+pub const BufferedOutStreamCustom = @import("io/buffered_out_stream.zig").BufferedOutStreamCustom;
+pub const bufferedOutStream = @import("io/buffered_out_stream.zig").bufferedOutStream;
+
+pub const CountingOutStream = @import("io/counting_out_stream.zig").CountingOutStream;
+
+pub fn fixedBufferStream(bytes: []const u8) FixedBufferInStream {
+ return (FixedBufferInStream{ .bytes = bytes, .pos = 0 });
+}
+
+pub fn cOutStream(c_file: *std.c.FILE) COutStream {
+ return .{ .context = c_file };
+}
+
+pub const COutStream = OutStream(*std.c.FILE, std.fs.File.WriteError, cOutStreamWrite);
+
+pub fn cOutStreamWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
+ const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
+ if (amt_written >= 0) return amt_written;
+ switch (std.c._errno().*) {
+ 0 => unreachable,
+ os.EINVAL => unreachable,
+ os.EFAULT => unreachable,
+ os.EAGAIN => unreachable, // this is a blocking API
+ os.EBADF => unreachable, // always a race condition
+ os.EDESTADDRREQ => unreachable, // connect was never called
+ os.EDQUOT => return error.DiskQuota,
+ os.EFBIG => return error.FileTooBig,
+ os.EIO => return error.InputOutput,
+ os.ENOSPC => return error.NoSpaceLeft,
+ os.EPERM => return error.AccessDenied,
+ os.EPIPE => return error.BrokenPipe,
+ else => |err| return os.unexpectedErrno(@intCast(usize, err)),
+ }
+}
/// Deprecated; use `std.fs.Dir.writeFile`.
pub fn writeFile(path: []const u8, data: []const u8) !void {
@@ -495,139 +531,18 @@ test "io.SliceOutStream" {
testing.expectEqualSlices(u8, "HelloWorld!", slice_stream.getWritten());
}
-var null_out_stream_state = NullOutStream.init();
-pub const null_out_stream = &null_out_stream_state.stream;
-
/// An OutStream that doesn't write to anything.
-pub const NullOutStream = struct {
- pub const Error = error{};
- pub const Stream = OutStream(Error);
+pub const null_out_stream = @as(NullOutStream, .{ .context = {} });
- stream: Stream,
-
- pub fn init() NullOutStream {
- return NullOutStream{
- .stream = Stream{ .writeFn = writeFn },
- };
- }
-
- fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
- return bytes.len;
- }
-};
-
-test "io.NullOutStream" {
- var null_stream = NullOutStream.init();
- const stream = &null_stream.stream;
- stream.write("yay" ** 10000) catch unreachable;
+const NullOutStream = OutStream(void, error{}, dummyWrite);
+fn dummyWrite(context: void, data: []const u8) error{}!usize {
+ return data.len;
}
-/// An OutStream that counts how many bytes has been written to it.
-pub fn CountingOutStream(comptime OutStreamError: type) type {
- return struct {
- const Self = @This();
- pub const Stream = OutStream(Error);
- pub const Error = OutStreamError;
-
- stream: Stream,
- bytes_written: u64,
- child_stream: *Stream,
-
- pub fn init(child_stream: *Stream) Self {
- return Self{
- .stream = Stream{ .writeFn = writeFn },
- .bytes_written = 0,
- .child_stream = child_stream,
- };
- }
-
- fn writeFn(out_stream: *Stream, bytes: []const u8) OutStreamError!usize {
- const self = @fieldParentPtr(Self, "stream", out_stream);
- try self.child_stream.write(bytes);
- self.bytes_written += bytes.len;
- return bytes.len;
- }
- };
+test "null_out_stream" {
+ null_out_stream.writeAll("yay" ** 1000) catch |err| switch (err) {};
}
-test "io.CountingOutStream" {
- var null_stream = NullOutStream.init();
- var counting_stream = CountingOutStream(NullOutStream.Error).init(&null_stream.stream);
- const stream = &counting_stream.stream;
-
- const bytes = "yay" ** 10000;
- stream.write(bytes) catch unreachable;
- testing.expect(counting_stream.bytes_written == bytes.len);
-}
-
-pub fn BufferedOutStream(comptime Error: type) type {
- return BufferedOutStreamCustom(mem.page_size, Error);
-}
-
-pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamError: type) type {
- return struct {
- const Self = @This();
- pub const Stream = OutStream(Error);
- pub const Error = OutStreamError;
-
- stream: Stream,
-
- unbuffered_out_stream: *Stream,
-
- const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
- fifo: FifoType,
-
- pub fn init(unbuffered_out_stream: *Stream) Self {
- return Self{
- .unbuffered_out_stream = unbuffered_out_stream,
- .fifo = FifoType.init(),
- .stream = Stream{ .writeFn = writeFn },
- };
- }
-
- pub fn flush(self: *Self) !void {
- while (true) {
- const slice = self.fifo.readableSlice(0);
- if (slice.len == 0) break;
- try self.unbuffered_out_stream.write(slice);
- self.fifo.discard(slice.len);
- }
- }
-
- fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
- const self = @fieldParentPtr(Self, "stream", out_stream);
- if (bytes.len >= self.fifo.writableLength()) {
- try self.flush();
- return self.unbuffered_out_stream.writeOnce(bytes);
- }
- self.fifo.writeAssumeCapacity(bytes);
- return bytes.len;
- }
- };
-}
-
-/// Implementation of OutStream trait for Buffer
-pub const BufferOutStream = struct {
- buffer: *Buffer,
- stream: Stream,
-
- pub const Error = error{OutOfMemory};
- pub const Stream = OutStream(Error);
-
- pub fn init(buffer: *Buffer) BufferOutStream {
- return BufferOutStream{
- .buffer = buffer,
- .stream = Stream{ .writeFn = writeFn },
- };
- }
-
- fn writeFn(out_stream: *Stream, bytes: []const u8) !usize {
- const self = @fieldParentPtr(BufferOutStream, "stream", out_stream);
- try self.buffer.append(bytes);
- return bytes.len;
- }
-};
-
/// Creates a stream which allows for writing bit fields to another stream
pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
return struct {
@@ -752,52 +667,11 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
return buffer.len;
}
- return self.out_stream.writeOnce(buffer);
+ return self.out_stream.write(buffer);
}
};
}
-pub const BufferedAtomicFile = struct {
- atomic_file: fs.AtomicFile,
- file_stream: File.OutStream,
- buffered_stream: BufferedOutStream(File.WriteError),
- allocator: *mem.Allocator,
-
- pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
- // TODO with well defined copy elision we don't need this allocation
- var self = try allocator.create(BufferedAtomicFile);
- self.* = BufferedAtomicFile{
- .atomic_file = undefined,
- .file_stream = undefined,
- .buffered_stream = undefined,
- .allocator = allocator,
- };
- errdefer allocator.destroy(self);
-
- self.atomic_file = try fs.AtomicFile.init(dest_path, File.default_mode);
- errdefer self.atomic_file.deinit();
-
- self.file_stream = self.atomic_file.file.outStream();
- self.buffered_stream = BufferedOutStream(File.WriteError).init(&self.file_stream.stream);
- return self;
- }
-
- /// always call destroy, even after successful finish()
- pub fn destroy(self: *BufferedAtomicFile) void {
- self.atomic_file.deinit();
- self.allocator.destroy(self);
- }
-
- pub fn finish(self: *BufferedAtomicFile) !void {
- try self.buffered_stream.flush();
- try self.atomic_file.finish();
- }
-
- pub fn stream(self: *BufferedAtomicFile) *OutStream(File.WriteError) {
- return &self.buffered_stream.stream;
- }
-};
-
pub const Packing = enum {
/// Pack data to byte alignment
Byte,
@@ -1129,8 +1003,9 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co
};
}
-test "import io tests" {
+test "" {
comptime {
_ = @import("io/test.zig");
}
+ std.meta.refAllDecls(@This());
}
diff --git a/lib/std/io/buffered_atomic_file.zig b/lib/std/io/buffered_atomic_file.zig
new file mode 100644
index 000000000..48c550c90
--- /dev/null
+++ b/lib/std/io/buffered_atomic_file.zig
@@ -0,0 +1,50 @@
+const std = @import("../std.zig");
+const mem = std.mem;
+const fs = std.fs;
+const File = std.fs.File;
+
+pub const BufferedAtomicFile = struct {
+ atomic_file: fs.AtomicFile,
+ file_stream: File.OutStream,
+ buffered_stream: BufferedOutStream,
+ allocator: *mem.Allocator,
+
+ pub const buffer_size = 4096;
+ pub const BufferedOutStream = std.io.BufferedOutStreamCustom(buffer_size, File.OutStream);
+ pub const OutStream = std.io.OutStream(*BufferedOutStream, BufferedOutStream.Error, BufferedOutStream.write);
+
+ /// TODO when https://github.com/ziglang/zig/issues/2761 is solved
+ /// this API will not need an allocator
+ pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
+ var self = try allocator.create(BufferedAtomicFile);
+ self.* = BufferedAtomicFile{
+ .atomic_file = undefined,
+ .file_stream = undefined,
+ .buffered_stream = undefined,
+ .allocator = allocator,
+ };
+ errdefer allocator.destroy(self);
+
+ self.atomic_file = try fs.AtomicFile.init(dest_path, File.default_mode);
+ errdefer self.atomic_file.deinit();
+
+ self.file_stream = self.atomic_file.file.outStream();
+ self.buffered_stream = std.io.bufferedOutStream(buffer_size, self.file_stream);
+ return self;
+ }
+
+ /// always call destroy, even after successful finish()
+ pub fn destroy(self: *BufferedAtomicFile) void {
+ self.atomic_file.deinit();
+ self.allocator.destroy(self);
+ }
+
+ pub fn finish(self: *BufferedAtomicFile) !void {
+ try self.buffered_stream.flush();
+ try self.atomic_file.finish();
+ }
+
+ pub fn stream(self: *BufferedAtomicFile) OutStream {
+ return .{ .context = &self.buffered_stream };
+ }
+};
diff --git a/lib/std/io/buffered_out_stream.zig b/lib/std/io/buffered_out_stream.zig
new file mode 100644
index 000000000..3650022b2
--- /dev/null
+++ b/lib/std/io/buffered_out_stream.zig
@@ -0,0 +1,56 @@
+const std = @import("../std.zig");
+const io = std.io;
+
+pub fn BufferedOutStream(comptime OutStreamType: type) type {
+ return BufferedOutStreamCustom(4096, OutStreamType);
+}
+
+pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamType: type) type {
+ return struct {
+ unbuffered_out_stream: OutStreamType,
+ fifo: FifoType,
+
+ pub const Error = OutStreamType.Error;
+ pub const OutStream = io.OutStream(*Self, Error, write);
+
+ const Self = @This();
+ const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
+
+ pub fn init(unbuffered_out_stream: OutStreamType) Self {
+ return Self{
+ .unbuffered_out_stream = unbuffered_out_stream,
+ .fifo = FifoType.init(),
+ };
+ }
+
+ pub fn flush(self: *Self) !void {
+ while (true) {
+ const slice = self.fifo.readableSlice(0);
+ if (slice.len == 0) break;
+ try self.unbuffered_out_stream.writeAll(slice);
+ self.fifo.discard(slice.len);
+ }
+ }
+
+ pub fn outStream(self: *Self) OutStream {
+ return .{ .context = self };
+ }
+
+ pub fn write(self: *Self, bytes: []const u8) Error!usize {
+ if (bytes.len >= self.fifo.writableLength()) {
+ try self.flush();
+ return self.unbuffered_out_stream.write(bytes);
+ }
+ self.fifo.writeAssumeCapacity(bytes);
+ return bytes.len;
+ }
+ };
+}
+
+pub fn bufferedOutStream(
+ comptime buffer_size: usize,
+ underlying_stream: var,
+) BufferedOutStreamCustom(buffer_size, @TypeOf(underlying_stream)) {
+ return BufferedOutStreamCustom(buffer_size, @TypeOf(underlying_stream)).init(underlying_stream);
+}
+
diff --git a/lib/std/io/c_out_stream.zig b/lib/std/io/c_out_stream.zig
deleted file mode 100644
index adaa3fcba..000000000
--- a/lib/std/io/c_out_stream.zig
+++ /dev/null
@@ -1,43 +0,0 @@
-const std = @import("../std.zig");
-const os = std.os;
-const OutStream = std.io.OutStream;
-const builtin = @import("builtin");
-
-/// TODO make a proposal to make `std.fs.File` use *FILE when linking libc and this just becomes
-/// std.io.FileOutStream because std.fs.File.write would do this when linking
-/// libc.
-pub const COutStream = struct {
- pub const Error = std.fs.File.WriteError;
- pub const Stream = OutStream(Error);
-
- stream: Stream,
- c_file: *std.c.FILE,
-
- pub fn init(c_file: *std.c.FILE) COutStream {
- return COutStream{
- .c_file = c_file,
- .stream = Stream{ .writeFn = writeFn },
- };
- }
-
- fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
- const self = @fieldParentPtr(COutStream, "stream", out_stream);
- const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, self.c_file);
- if (amt_written >= 0) return amt_written;
- switch (std.c._errno().*) {
- 0 => unreachable,
- os.EINVAL => unreachable,
- os.EFAULT => unreachable,
- os.EAGAIN => unreachable, // this is a blocking API
- os.EBADF => unreachable, // always a race condition
- os.EDESTADDRREQ => unreachable, // connect was never called
- os.EDQUOT => return error.DiskQuota,
- os.EFBIG => return error.FileTooBig,
- os.EIO => return error.InputOutput,
- os.ENOSPC => return error.NoSpaceLeft,
- os.EPERM => return error.AccessDenied,
- os.EPIPE => return error.BrokenPipe,
- else => |err| return os.unexpectedErrno(@intCast(usize, err)),
- }
- }
-};
diff --git a/lib/std/io/counting_out_stream.zig b/lib/std/io/counting_out_stream.zig
new file mode 100644
index 000000000..2b0cba29f
--- /dev/null
+++ b/lib/std/io/counting_out_stream.zig
@@ -0,0 +1,42 @@
+const std = @import("../std.zig");
+const io = std.io;
+
+/// An OutStream that counts how many bytes has been written to it.
+pub fn CountingOutStream(comptime OutStreamType: type) type {
+ return struct {
+ bytes_written: u64,
+ child_stream: OutStreamType,
+
+ pub const Error = OutStreamType.Error;
+ pub const OutStream = io.OutStream(*Self, Error, write);
+
+ const Self = @This();
+
+ pub fn init(child_stream: OutStreamType) Self {
+ return Self{
+ .bytes_written = 0,
+ .child_stream = child_stream,
+ };
+ }
+
+ pub fn write(self: *Self, bytes: []const u8) Error!usize {
+ const amt = try self.child_stream.write(bytes);
+ self.bytes_written += amt;
+ return amt;
+ }
+
+ pub fn outStream(self: *Self) OutStream {
+ return .{ .context = self };
+ }
+ };
+}
+
+test "io.CountingOutStream" {
+ var counting_stream = CountingOutStream(NullOutStream.Error).init(std.io.null_out_stream);
+ const stream = &counting_stream.stream;
+
+ const bytes = "yay" ** 10000;
+ stream.write(bytes) catch unreachable;
+ testing.expect(counting_stream.bytes_written == bytes.len);
+}
+
diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig
new file mode 100644
index 000000000..847feeae0
--- /dev/null
+++ b/lib/std/io/fixed_buffer_stream.zig
@@ -0,0 +1,66 @@
+const std = @import("../std.zig");
+const io = std.io;
+
+pub const FixedBufferInStream = struct {
+ bytes: []const u8,
+ pos: usize,
+
+ pub const SeekError = error{EndOfStream};
+ pub const GetSeekPosError = error{};
+
+ pub const InStream = io.InStream(*FixedBufferInStream, error{}, read);
+
+ pub fn inStream(self: *FixedBufferInStream) InStream {
+ return .{ .context = self };
+ }
+
+ pub const SeekableStream = io.SeekableStream(
+ *FixedBufferInStream,
+ SeekError,
+ GetSeekPosError,
+ seekTo,
+ seekBy,
+ getPos,
+ getEndPos,
+ );
+
+ pub fn seekableStream(self: *FixedBufferInStream) SeekableStream {
+ return .{ .context = self };
+ }
+
+ pub fn read(self: *FixedBufferInStream, dest: []u8) error{}!usize {
+ const size = std.math.min(dest.len, self.bytes.len - self.pos);
+ const end = self.pos + size;
+
+ std.mem.copy(u8, dest[0..size], self.bytes[self.pos..end]);
+ self.pos = end;
+
+ return size;
+ }
+
+ pub fn seekTo(self: *FixedBufferInStream, pos: u64) SeekError!void {
+ const usize_pos = std.math.cast(usize, pos) catch return error.EndOfStream;
+ if (usize_pos > self.bytes.len) return error.EndOfStream;
+ self.pos = usize_pos;
+ }
+
+ pub fn seekBy(self: *FixedBufferInStream, amt: i64) SeekError!void {
+ if (amt < 0) {
+ const abs_amt = std.math.cast(usize, -amt) catch return error.EndOfStream;
+ if (abs_amt > self.pos) return error.EndOfStream;
+ self.pos -= abs_amt;
+ } else {
+ const usize_amt = std.math.cast(usize, amt) catch return error.EndOfStream;
+ if (self.pos + usize_amt > self.bytes.len) return error.EndOfStream;
+ self.pos += usize_amt;
+ }
+ }
+
+ pub fn getEndPos(self: *FixedBufferInStream) GetSeekPosError!u64 {
+ return self.bytes.len;
+ }
+
+ pub fn getPos(self: *FixedBufferInStream) GetSeekPosError!u64 {
+ return self.pos;
+ }
+};
diff --git a/lib/std/io/in_stream.zig b/lib/std/io/in_stream.zig
index e23418277..d181f4df4 100644
--- a/lib/std/io/in_stream.zig
+++ b/lib/std/io/in_stream.zig
@@ -1,44 +1,31 @@
const std = @import("../std.zig");
-const builtin = @import("builtin");
-const root = @import("root");
+const builtin = std.builtin;
const math = std.math;
const assert = std.debug.assert;
const mem = std.mem;
const Buffer = std.Buffer;
const testing = std.testing;
-pub const default_stack_size = 1 * 1024 * 1024;
-pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_InStream"))
- root.stack_size_std_io_InStream
-else
- default_stack_size;
-
-pub fn InStream(comptime ReadError: type) type {
+pub fn InStream(
+ comptime Context: type,
+ comptime ReadError: type,
+ /// Returns the number of bytes read. It may be less than buffer.len.
+ /// If the number of bytes read is 0, it means end of stream.
+ /// End of stream is not an error condition.
+ comptime readFn: fn (context: Context, buffer: []u8) ReadError!usize,
+) type {
return struct {
- const Self = @This();
pub const Error = ReadError;
- pub const ReadFn = if (std.io.is_async)
- async fn (self: *Self, buffer: []u8) Error!usize
- else
- fn (self: *Self, buffer: []u8) Error!usize;
+
+ context: Context,
+
+ const Self = @This();
/// Returns the number of bytes read. It may be less than buffer.len.
/// If the number of bytes read is 0, it means end of stream.
/// End of stream is not an error condition.
- readFn: ReadFn,
-
- /// Returns the number of bytes read. It may be less than buffer.len.
- /// If the number of bytes read is 0, it means end of stream.
- /// End of stream is not an error condition.
- pub fn read(self: *Self, buffer: []u8) Error!usize {
- if (std.io.is_async) {
- // Let's not be writing 0xaa in safe modes for upwards of 4 MiB for every stream read.
- @setRuntimeSafety(false);
- var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;
- return await @asyncCall(&stack_frame, {}, self.readFn, self, buffer);
- } else {
- return self.readFn(self, buffer);
- }
+ pub fn read(self: Self, buffer: []u8) Error!usize {
+ return readFn(self.context, buffer);
}
/// Deprecated: use `readAll`.
@@ -47,7 +34,7 @@ pub fn InStream(comptime ReadError: type) type {
/// Returns the number of bytes read. If the number read is smaller than buf.len, it
/// means the stream reached the end. Reaching the end of a stream is not an error
/// condition.
- pub fn readAll(self: *Self, buffer: []u8) Error!usize {
+ pub fn readAll(self: Self, buffer: []u8) Error!usize {
var index: usize = 0;
while (index != buffer.len) {
const amt = try self.read(buffer[index..]);
@@ -59,13 +46,13 @@ pub fn InStream(comptime ReadError: type) type {
/// Returns the number of bytes read. If the number read would be smaller than buf.len,
/// error.EndOfStream is returned instead.
- pub fn readNoEof(self: *Self, buf: []u8) !void {
+ pub fn readNoEof(self: Self, buf: []u8) !void {
const amt_read = try self.readAll(buf);
if (amt_read < buf.len) return error.EndOfStream;
}
/// Deprecated: use `readAllArrayList`.
- pub fn readAllBuffer(self: *Self, buffer: *Buffer, max_size: usize) !void {
+ pub fn readAllBuffer(self: Self, buffer: *Buffer, max_size: usize) !void {
buffer.list.shrink(0);
try self.readAllArrayList(&buffer.list, max_size);
errdefer buffer.shrink(0);
@@ -75,7 +62,7 @@ pub fn InStream(comptime ReadError: type) type {
/// Appends to the `std.ArrayList` contents by reading from the stream until end of stream is found.
/// If the number of bytes appended would exceed `max_append_size`, `error.StreamTooLong` is returned
/// and the `std.ArrayList` has exactly `max_append_size` bytes appended.
- pub fn readAllArrayList(self: *Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void {
+ pub fn readAllArrayList(self: Self, array_list: *std.ArrayList(u8), max_append_size: usize) !void {
try array_list.ensureCapacity(math.min(max_append_size, 4096));
const original_len = array_list.len;
var start_index: usize = original_len;
@@ -104,7 +91,7 @@ pub fn InStream(comptime ReadError: type) type {
/// memory would be greater than `max_size`, returns `error.StreamTooLong`.
/// Caller owns returned memory.
/// If this function returns an error, the contents from the stream read so far are lost.
- pub fn readAllAlloc(self: *Self, allocator: *mem.Allocator, max_size: usize) ![]u8 {
+ pub fn readAllAlloc(self: Self, allocator: *mem.Allocator, max_size: usize) ![]u8 {
var array_list = std.ArrayList(u8).init(allocator);
defer array_list.deinit();
try self.readAllArrayList(&array_list, max_size);
@@ -116,7 +103,7 @@ pub fn InStream(comptime ReadError: type) type {
/// If the `std.ArrayList` length would exceed `max_size`, `error.StreamTooLong` is returned and the
/// `std.ArrayList` is populated with `max_size` bytes from the stream.
pub fn readUntilDelimiterArrayList(
- self: *Self,
+ self: Self,
array_list: *std.ArrayList(u8),
delimiter: u8,
max_size: usize,
@@ -142,7 +129,7 @@ pub fn InStream(comptime ReadError: type) type {
/// Caller owns returned memory.
/// If this function returns an error, the contents from the stream read so far are lost.
pub fn readUntilDelimiterAlloc(
- self: *Self,
+ self: Self,
allocator: *mem.Allocator,
delimiter: u8,
max_size: usize,
@@ -159,7 +146,7 @@ pub fn InStream(comptime ReadError: type) type {
/// function is called again after that, returns null.
/// Returns a slice of the stream data, with ptr equal to `buf.ptr`. The
/// delimiter byte is not included in the returned slice.
- pub fn readUntilDelimiterOrEof(self: *Self, buf: []u8, delimiter: u8) !?[]u8 {
+ pub fn readUntilDelimiterOrEof(self: Self, buf: []u8, delimiter: u8) !?[]u8 {
var index: usize = 0;
while (true) {
const byte = self.readByte() catch |err| switch (err) {
@@ -184,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {
/// Reads from the stream until specified byte is found, discarding all data,
/// including the delimiter.
/// If end-of-stream is found, this function succeeds.
- pub fn skipUntilDelimiterOrEof(self: *Self, delimiter: u8) !void {
+ pub fn skipUntilDelimiterOrEof(self: Self, delimiter: u8) !void {
while (true) {
const byte = self.readByte() catch |err| switch (err) {
error.EndOfStream => return,
@@ -195,7 +182,7 @@ pub fn InStream(comptime ReadError: type) type {
}
/// Reads 1 byte from the stream or returns `error.EndOfStream`.
- pub fn readByte(self: *Self) !u8 {
+ pub fn readByte(self: Self) !u8 {
var result: [1]u8 = undefined;
const amt_read = try self.read(result[0..]);
if (amt_read < 1) return error.EndOfStream;
@@ -203,43 +190,43 @@ pub fn InStream(comptime ReadError: type) type {
}
/// Same as `readByte` except the returned byte is signed.
- pub fn readByteSigned(self: *Self) !i8 {
+ pub fn readByteSigned(self: Self) !i8 {
return @bitCast(i8, try self.readByte());
}
/// Reads a native-endian integer
- pub fn readIntNative(self: *Self, comptime T: type) !T {
+ pub fn readIntNative(self: Self, comptime T: type) !T {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readIntNative(T, &bytes);
}
/// Reads a foreign-endian integer
- pub fn readIntForeign(self: *Self, comptime T: type) !T {
+ pub fn readIntForeign(self: Self, comptime T: type) !T {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readIntForeign(T, &bytes);
}
- pub fn readIntLittle(self: *Self, comptime T: type) !T {
+ pub fn readIntLittle(self: Self, comptime T: type) !T {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readIntLittle(T, &bytes);
}
- pub fn readIntBig(self: *Self, comptime T: type) !T {
+ pub fn readIntBig(self: Self, comptime T: type) !T {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readIntBig(T, &bytes);
}
- pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
+ pub fn readInt(self: Self, comptime T: type, endian: builtin.Endian) !T {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readInt(T, &bytes, endian);
}
- pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
+ pub fn readVarInt(self: Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
assert(size <= @sizeOf(ReturnType));
var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
const bytes = bytes_buf[0..size];
@@ -247,14 +234,14 @@ pub fn InStream(comptime ReadError: type) type {
return mem.readVarInt(ReturnType, bytes, endian);
}
- pub fn skipBytes(self: *Self, num_bytes: u64) !void {
+ pub fn skipBytes(self: Self, num_bytes: u64) !void {
var i: u64 = 0;
while (i < num_bytes) : (i += 1) {
_ = try self.readByte();
}
}
- pub fn readStruct(self: *Self, comptime T: type) !T {
+ pub fn readStruct(self: Self, comptime T: type) !T {
// Only extern and packed structs have defined in-memory layout.
comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto);
var res: [1]T = undefined;
@@ -265,7 +252,7 @@ pub fn InStream(comptime ReadError: type) type {
/// Reads an integer with the same size as the given enum's tag type. If the integer matches
/// an enum tag, casts the integer to the enum tag and returns it. Otherwise, returns an error.
/// TODO optimization taking advantage of most fields being in order
- pub fn readEnum(self: *Self, comptime Enum: type, endian: builtin.Endian) !Enum {
+ pub fn readEnum(self: Self, comptime Enum: type, endian: builtin.Endian) !Enum {
const E = error{
/// An integer was read, but it did not match any of the tags in the supplied enum.
InvalidValue,
diff --git a/lib/std/io/out_stream.zig b/lib/std/io/out_stream.zig
index cb75b27bf..03901f667 100644
--- a/lib/std/io/out_stream.zig
+++ b/lib/std/io/out_stream.zig
@@ -1,94 +1,85 @@
const std = @import("../std.zig");
-const builtin = @import("builtin");
-const root = @import("root");
+const builtin = std.builtin;
const mem = std.mem;
-pub const default_stack_size = 1 * 1024 * 1024;
-pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_OutStream"))
- root.stack_size_std_io_OutStream
-else
- default_stack_size;
-
-pub fn OutStream(comptime WriteError: type) type {
+pub fn OutStream(
+ comptime Context: type,
+ comptime WriteError: type,
+ comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
+) type {
return struct {
+ context: Context,
+
const Self = @This();
pub const Error = WriteError;
- pub const WriteFn = if (std.io.is_async)
- async fn (self: *Self, bytes: []const u8) Error!usize
- else
- fn (self: *Self, bytes: []const u8) Error!usize;
- writeFn: WriteFn,
-
- pub fn writeOnce(self: *Self, bytes: []const u8) Error!usize {
- if (std.io.is_async) {
- // Let's not be writing 0xaa in safe modes for upwards of 4 MiB for every stream write.
- @setRuntimeSafety(false);
- var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;
- return await @asyncCall(&stack_frame, {}, self.writeFn, self, bytes);
- } else {
- return self.writeFn(self, bytes);
- }
+ pub fn write(self: Self, bytes: []const u8) Error!usize {
+ return writeFn(self.context, bytes);
}
- pub fn write(self: *Self, bytes: []const u8) Error!void {
+ pub fn writeAll(self: Self, bytes: []const u8) Error!void {
var index: usize = 0;
while (index != bytes.len) {
- index += try self.writeOnce(bytes[index..]);
+ index += try self.write(bytes[index..]);
}
}
- pub fn print(self: *Self, comptime format: []const u8, args: var) Error!void {
- return std.fmt.format(self, Error, write, format, args);
+ pub fn print(self: Self, comptime format: []const u8, args: var) Error!void {
+ return std.fmt.format(self, Error, writeAll, format, args);
}
- pub fn writeByte(self: *Self, byte: u8) Error!void {
+ pub fn writeByte(self: Self, byte: u8) Error!void {
const array = [1]u8{byte};
- return self.write(&array);
+ return self.writeAll(&array);
}
- pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) Error!void {
+ pub fn writeByteNTimes(self: Self, byte: u8, n: usize) Error!void {
var bytes: [256]u8 = undefined;
mem.set(u8, bytes[0..], byte);
var remaining: usize = n;
while (remaining > 0) {
const to_write = std.math.min(remaining, bytes.len);
- try self.write(bytes[0..to_write]);
+ try self.writeAll(bytes[0..to_write]);
remaining -= to_write;
}
}
/// Write a native-endian integer.
- pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
+ /// TODO audit non-power-of-two int sizes
+ pub fn writeIntNative(self: Self, comptime T: type, value: T) Error!void {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
mem.writeIntNative(T, &bytes, value);
- return self.write(&bytes);
+ return self.writeAll(&bytes);
}
/// Write a foreign-endian integer.
- pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
+ /// TODO audit non-power-of-two int sizes
+ pub fn writeIntForeign(self: Self, comptime T: type, value: T) Error!void {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
mem.writeIntForeign(T, &bytes, value);
- return self.write(&bytes);
+ return self.writeAll(&bytes);
}
- pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
+ /// TODO audit non-power-of-two int sizes
+ pub fn writeIntLittle(self: Self, comptime T: type, value: T) Error!void {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
mem.writeIntLittle(T, &bytes, value);
- return self.write(&bytes);
+ return self.writeAll(&bytes);
}
- pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
+ /// TODO audit non-power-of-two int sizes
+ pub fn writeIntBig(self: Self, comptime T: type, value: T) Error!void {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
mem.writeIntBig(T, &bytes, value);
- return self.write(&bytes);
+ return self.writeAll(&bytes);
}
- pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
+ /// TODO audit non-power-of-two int sizes
+ pub fn writeInt(self: Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
mem.writeInt(T, &bytes, value, endian);
- return self.write(&bytes);
+ return self.writeAll(&bytes);
}
};
}
diff --git a/lib/std/io/seekable_stream.zig b/lib/std/io/seekable_stream.zig
index 052abbc85..ed410b7aa 100644
--- a/lib/std/io/seekable_stream.zig
+++ b/lib/std/io/seekable_stream.zig
@@ -1,103 +1,36 @@
const std = @import("../std.zig");
const InStream = std.io.InStream;
-pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {
+pub fn SeekableStream(
+ comptime Context: type,
+ comptime SeekErrorType: type,
+ comptime GetSeekPosErrorType: type,
+ comptime seekToFn: fn (context: Context, pos: u64) SeekErrorType!void,
+ comptime seekByFn: fn (context: Context, pos: i64) SeekErrorType!void,
+ comptime getPosFn: fn (context: Context) GetSeekPosErrorType!u64,
+ comptime getEndPosFn: fn (context: Context) GetSeekPosErrorType!u64,
+) type {
return struct {
+ context: Context,
+
const Self = @This();
pub const SeekError = SeekErrorType;
pub const GetSeekPosError = GetSeekPosErrorType;
- seekToFn: fn (self: *Self, pos: u64) SeekError!void,
- seekByFn: fn (self: *Self, pos: i64) SeekError!void,
-
- getPosFn: fn (self: *Self) GetSeekPosError!u64,
- getEndPosFn: fn (self: *Self) GetSeekPosError!u64,
-
- pub fn seekTo(self: *Self, pos: u64) SeekError!void {
- return self.seekToFn(self, pos);
+ pub fn seekTo(self: Self, pos: u64) SeekError!void {
+ return seekToFn(self.context, pos);
}
- pub fn seekBy(self: *Self, amt: i64) SeekError!void {
- return self.seekByFn(self, amt);
+ pub fn seekBy(self: Self, amt: i64) SeekError!void {
+ return seekByFn(self.context, amt);
}
- pub fn getEndPos(self: *Self) GetSeekPosError!u64 {
- return self.getEndPosFn(self);
+ pub fn getEndPos(self: Self) GetSeekPosError!u64 {
+ return getEndPosFn(self.context);
}
- pub fn getPos(self: *Self) GetSeekPosError!u64 {
- return self.getPosFn(self);
+ pub fn getPos(self: Self) GetSeekPosError!u64 {
+ return getPosFn(self.context);
}
};
}
-
-pub const SliceSeekableInStream = struct {
- const Self = @This();
- pub const Error = error{};
- pub const SeekError = error{EndOfStream};
- pub const GetSeekPosError = error{};
- pub const Stream = InStream(Error);
- pub const SeekableInStream = SeekableStream(SeekError, GetSeekPosError);
-
- stream: Stream,
- seekable_stream: SeekableInStream,
-
- pos: usize,
- slice: []const u8,
-
- pub fn init(slice: []const u8) Self {
- return Self{
- .slice = slice,
- .pos = 0,
- .stream = Stream{ .readFn = readFn },
- .seekable_stream = SeekableInStream{
- .seekToFn = seekToFn,
- .seekByFn = seekByFn,
- .getEndPosFn = getEndPosFn,
- .getPosFn = getPosFn,
- },
- };
- }
-
- fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
- const self = @fieldParentPtr(Self, "stream", in_stream);
- const size = std.math.min(dest.len, self.slice.len - self.pos);
- const end = self.pos + size;
-
- std.mem.copy(u8, dest[0..size], self.slice[self.pos..end]);
- self.pos = end;
-
- return size;
- }
-
- fn seekToFn(in_stream: *SeekableInStream, pos: u64) SeekError!void {
- const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
- const usize_pos = @intCast(usize, pos);
- if (usize_pos > self.slice.len) return error.EndOfStream;
- self.pos = usize_pos;
- }
-
- fn seekByFn(in_stream: *SeekableInStream, amt: i64) SeekError!void {
- const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
-
- if (amt < 0) {
- const abs_amt = @intCast(usize, -amt);
- if (abs_amt > self.pos) return error.EndOfStream;
- self.pos -= abs_amt;
- } else {
- const usize_amt = @intCast(usize, amt);
- if (self.pos + usize_amt > self.slice.len) return error.EndOfStream;
- self.pos += usize_amt;
- }
- }
-
- fn getEndPosFn(in_stream: *SeekableInStream) GetSeekPosError!u64 {
- const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
- return @intCast(u64, self.slice.len);
- }
-
- fn getPosFn(in_stream: *SeekableInStream) GetSeekPosError!u64 {
- const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
- return @intCast(u64, self.pos);
- }
-};
diff --git a/lib/std/json/write_stream.zig b/lib/std/json/write_stream.zig
index 213b6768d..6d88c8b6d 100644
--- a/lib/std/json/write_stream.zig
+++ b/lib/std/json/write_stream.zig
@@ -30,11 +30,11 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
/// The string used as spacing.
space: []const u8 = " ",
- stream: *OutStream,
+ stream: OutStream,
state_index: usize,
state: [max_depth]State,
- pub fn init(stream: *OutStream) Self {
+ pub fn init(stream: OutStream) Self {
var self = Self{
.stream = stream,
.state_index = 1,
@@ -90,8 +90,8 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
self.pushState(.Value);
try self.indent();
try self.writeEscapedString(name);
- try self.stream.write(":");
- try self.stream.write(self.space);
+ try self.stream.writeAll(":");
+ try self.stream.writeAll(self.space);
},
}
}
@@ -134,16 +134,16 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
pub fn emitNull(self: *Self) !void {
assert(self.state[self.state_index] == State.Value);
- try self.stream.write("null");
+ try self.stream.writeAll("null");
self.popState();
}
pub fn emitBool(self: *Self, value: bool) !void {
assert(self.state[self.state_index] == State.Value);
if (value) {
- try self.stream.write("true");
+ try self.stream.writeAll("true");
} else {
- try self.stream.write("false");
+ try self.stream.writeAll("false");
}
self.popState();
}
@@ -188,13 +188,13 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
try self.stream.writeByte('"');
for (string) |s| {
switch (s) {
- '"' => try self.stream.write("\\\""),
- '\t' => try self.stream.write("\\t"),
- '\r' => try self.stream.write("\\r"),
- '\n' => try self.stream.write("\\n"),
- 8 => try self.stream.write("\\b"),
- 12 => try self.stream.write("\\f"),
- '\\' => try self.stream.write("\\\\"),
+ '"' => try self.stream.writeAll("\\\""),
+ '\t' => try self.stream.writeAll("\\t"),
+ '\r' => try self.stream.writeAll("\\r"),
+ '\n' => try self.stream.writeAll("\\n"),
+ 8 => try self.stream.writeAll("\\b"),
+ 12 => try self.stream.writeAll("\\f"),
+ '\\' => try self.stream.writeAll("\\\\"),
else => try self.stream.writeByte(s),
}
}
@@ -231,10 +231,10 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
fn indent(self: *Self) !void {
assert(self.state_index >= 1);
- try self.stream.write(self.newline);
+ try self.stream.writeAll(self.newline);
var i: usize = 0;
while (i < self.state_index - 1) : (i += 1) {
- try self.stream.write(self.one_indent);
+ try self.stream.writeAll(self.one_indent);
}
}
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 460f0bee0..76a5dc2be 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -176,7 +176,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
.io_mode = .blocking,
.async_block_allowed = std.fs.File.async_block_allowed_yes,
};
- const stream = &file.inStream().stream;
+ const stream = file.inStream();
stream.readNoEof(buf) catch return error.Unexpected;
}
diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig
index db60e6049..7c48cf7b7 100644
--- a/lib/std/pdb.zig
+++ b/lib/std/pdb.zig
@@ -632,11 +632,7 @@ const MsfStream = struct {
blocks: []u32 = undefined,
block_size: u32 = undefined,
- /// Implementation of InStream trait for Pdb.MsfStream
- stream: Stream = undefined,
-
pub const Error = @TypeOf(read).ReturnType.ErrorSet;
- pub const Stream = io.InStream(Error);
fn init(block_size: u32, file: File, blocks: []u32) MsfStream {
const stream = MsfStream{
@@ -644,7 +640,6 @@ const MsfStream = struct {
.pos = 0,
.blocks = blocks,
.block_size = block_size,
- .stream = Stream{ .readFn = readFn },
};
return stream;
@@ -715,8 +710,7 @@ const MsfStream = struct {
return block * self.block_size + offset;
}
- fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
- const self = @fieldParentPtr(MsfStream, "stream", in_stream);
- return self.read(buffer);
+ fn inStream(self: *MsfStream) std.io.InStream(*MsfStream, Error, read) {
+ return .{ .context = self };
}
};
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index 95a772376..8ae219a99 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -375,7 +375,7 @@ pub const Error = union(enum) {
token: TokenIndex,
pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
- return stream.write(msg);
+ return stream.writeAll(msg);
}
};
}
diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig
index ce9049e35..9600de21d 100644
--- a/lib/std/zig/render.zig
+++ b/lib/std/zig/render.zig
@@ -12,64 +12,58 @@ pub const Error = error{
};
/// Returns whether anything changed
-pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(stream).Child.Error || Error)!bool {
- comptime assert(@typeInfo(@TypeOf(stream)) == .Pointer);
-
- var anything_changed: bool = false;
-
+pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(stream).Error || Error)!bool {
// make a passthrough stream that checks whether something changed
const MyStream = struct {
const MyStream = @This();
- const StreamError = @TypeOf(stream).Child.Error;
- const Stream = std.io.OutStream(StreamError);
+ const StreamError = @TypeOf(stream).Error;
- anything_changed_ptr: *bool,
child_stream: @TypeOf(stream),
- stream: Stream,
+ anything_changed: bool,
source_index: usize,
source: []const u8,
- fn write(iface_stream: *Stream, bytes: []const u8) StreamError!usize {
- const self = @fieldParentPtr(MyStream, "stream", iface_stream);
-
- if (!self.anything_changed_ptr.*) {
+ fn write(self: *MyStream, bytes: []const u8) StreamError!usize {
+ if (!self.anything_changed) {
const end = self.source_index + bytes.len;
if (end > self.source.len) {
- self.anything_changed_ptr.* = true;
+ self.anything_changed = true;
} else {
const src_slice = self.source[self.source_index..end];
self.source_index += bytes.len;
if (!mem.eql(u8, bytes, src_slice)) {
- self.anything_changed_ptr.* = true;
+ self.anything_changed = true;
}
}
}
- return self.child_stream.writeOnce(bytes);
+ return self.child_stream.write(bytes);
}
};
var my_stream = MyStream{
- .stream = MyStream.Stream{ .writeFn = MyStream.write },
.child_stream = stream,
- .anything_changed_ptr = &anything_changed,
+ .anything_changed = false,
.source_index = 0,
.source = tree.source,
};
+ const my_stream_stream: std.io.OutStream(*MyStream, MyStream.StreamError, MyStream.write) = .{
+ .context = &my_stream,
+ };
- try renderRoot(allocator, &my_stream.stream, tree);
+ try renderRoot(allocator, my_stream_stream, tree);
- if (!anything_changed and my_stream.source_index != my_stream.source.len) {
- anything_changed = true;
+ if (my_stream.source_index != my_stream.source.len) {
+ my_stream.anything_changed = true;
}
- return anything_changed;
+ return my_stream.anything_changed;
}
fn renderRoot(
allocator: *mem.Allocator,
stream: var,
tree: *ast.Tree,
-) (@TypeOf(stream).Child.Error || Error)!void {
+) (@TypeOf(stream).Error || Error)!void {
var tok_it = tree.tokens.iterator(0);
// render all the line comments at the beginning of the file
@@ -189,7 +183,7 @@ fn renderRoot(
}
}
-fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Child.Error!void {
+fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void {
const first_token = node.firstToken();
var prev_token = first_token;
if (prev_token == 0) return;
@@ -204,11 +198,11 @@ fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *as
}
}
-fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Child.Error || Error)!void {
+fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Error || Error)!void {
try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Newline);
}
-fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Child.Error || Error)!void {
+fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Error || Error)!void {
switch (decl.id) {
.FnProto => {
const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
@@ -343,7 +337,7 @@ fn renderExpression(
start_col: *usize,
base: *ast.Node,
space: Space,
-) (@TypeOf(stream).Child.Error || Error)!void {
+) (@TypeOf(stream).Error || Error)!void {
switch (base.id) {
.Identifier => {
const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
@@ -449,9 +443,9 @@ fn renderExpression(
switch (op_tok_id) {
.Asterisk, .AsteriskAsterisk => try stream.writeByte('*'),
.LBracket => if (tree.tokens.at(prefix_op_node.op_token + 2).id == .Identifier)
- try stream.write("[*c")
+ try stream.writeAll("[*c")
else
- try stream.write("[*"),
+ try stream.writeAll("[*"),
else => unreachable,
}
if (ptr_info.sentinel) |sentinel| {
@@ -757,7 +751,7 @@ fn renderExpression(
while (it.next()) |field_init| {
var find_stream = FindByteOutStream.init('\n');
var dummy_col: usize = 0;
- try renderExpression(allocator, &find_stream.stream, tree, 0, &dummy_col, field_init.*, Space.None);
+ try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init.*, Space.None);
if (find_stream.byte_found) break :blk false;
}
break :blk true;
@@ -909,8 +903,7 @@ fn renderExpression(
var column_widths = widths[widths.len - row_size ..];
// Null stream for counting the printed length of each expression
- var null_stream = std.io.NullOutStream.init();
- var counting_stream = std.io.CountingOutStream(std.io.NullOutStream.Error).init(&null_stream.stream);
+ var counting_stream = std.io.CountingOutStream(@TypeOf(std.io.null_out_stream)).init(std.io.null_out_stream);
var it = exprs.iterator(0);
var i: usize = 0;
@@ -918,7 +911,7 @@ fn renderExpression(
while (it.next()) |expr| : (i += 1) {
counting_stream.bytes_written = 0;
var dummy_col: usize = 0;
- try renderExpression(allocator, &counting_stream.stream, tree, indent, &dummy_col, expr.*, Space.None);
+ try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr.*, Space.None);
const width = @intCast(usize, counting_stream.bytes_written);
const col = i % row_size;
column_widths[col] = std.math.max(column_widths[col], width);
@@ -1336,7 +1329,7 @@ fn renderExpression(
// TODO: Remove condition after deprecating 'typeOf'. See https://github.com/ziglang/zig/issues/1348
if (mem.eql(u8, tree.tokenSlicePtr(tree.tokens.at(builtin_call.builtin_token)), "@typeOf")) {
- try stream.write("@TypeOf");
+ try stream.writeAll("@TypeOf");
} else {
try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name
}
@@ -1505,9 +1498,9 @@ fn renderExpression(
try renderExpression(allocator, stream, tree, indent, start_col, callconv_expr, Space.None);
try renderToken(tree, stream, callconv_rparen, indent, start_col, Space.Space); // )
} else if (cc_rewrite_str) |str| {
- try stream.write("callconv(");
- try stream.write(mem.toSliceConst(u8, str));
- try stream.write(") ");
+ try stream.writeAll("callconv(");
+ try stream.writeAll(mem.toSliceConst(u8, str));
+ try stream.writeAll(") ");
}
switch (fn_proto.return_type) {
@@ -1997,11 +1990,11 @@ fn renderExpression(
.AsmInput => {
const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
- try stream.write("[");
+ try stream.writeAll("[");
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None);
- try stream.write("] ");
+ try stream.writeAll("] ");
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None);
- try stream.write(" (");
+ try stream.writeAll(" (");
try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None);
return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // )
},
@@ -2009,18 +2002,18 @@ fn renderExpression(
.AsmOutput => {
const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
- try stream.write("[");
+ try stream.writeAll("[");
try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None);
- try stream.write("] ");
+ try stream.writeAll("] ");
try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None);
- try stream.write(" (");
+ try stream.writeAll(" (");
switch (asm_output.kind) {
ast.Node.AsmOutput.Kind.Variable => |variable_name| {
try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None);
},
ast.Node.AsmOutput.Kind.Return => |return_type| {
- try stream.write("-> ");
+ try stream.writeAll("-> ");
try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None);
},
}
@@ -2052,7 +2045,7 @@ fn renderVarDecl(
indent: usize,
start_col: *usize,
var_decl: *ast.Node.VarDecl,
-) (@TypeOf(stream).Child.Error || Error)!void {
+) (@TypeOf(stream).Error || Error)!void {
if (var_decl.visib_token) |visib_token| {
try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub
}
@@ -2125,7 +2118,7 @@ fn renderParamDecl(
start_col: *usize,
base: *ast.Node,
space: Space,
-) (@TypeOf(stream).Child.Error || Error)!void {
+) (@TypeOf(stream).Error || Error)!void {
const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
try renderDocComments(tree, stream, param_decl, indent, start_col);
@@ -2154,7 +2147,7 @@ fn renderStatement(
indent: usize,
start_col: *usize,
base: *ast.Node,
-) (@TypeOf(stream).Child.Error || Error)!void {
+) (@TypeOf(stream).Error || Error)!void {
switch (base.id) {
.VarDecl => {
const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
@@ -2193,7 +2186,7 @@ fn renderTokenOffset(
start_col: *usize,
space: Space,
token_skip_bytes: usize,
-) (@TypeOf(stream).Child.Error || Error)!void {
+) (@TypeOf(stream).Error || Error)!void {
if (space == Space.BlockStart) {
if (start_col.* < indent + indent_delta)
return renderToken(tree, stream, token_index, indent, start_col, Space.Space);
@@ -2204,7 +2197,7 @@ fn renderTokenOffset(
}
var token = tree.tokens.at(token_index);
- try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));
+ try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " "));
if (space == Space.NoComment)
return;
@@ -2214,15 +2207,15 @@ fn renderTokenOffset(
if (space == Space.Comma) switch (next_token.id) {
.Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline),
.LineComment => {
- try stream.write(", ");
+ try stream.writeAll(", ");
return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline);
},
else => {
if (token_index + 2 < tree.tokens.len and tree.tokens.at(token_index + 2).id == .MultilineStringLiteralLine) {
- try stream.write(",");
+ try stream.writeAll(",");
return;
} else {
- try stream.write(",\n");
+ try stream.writeAll(",\n");
start_col.* = 0;
return;
}
@@ -2246,7 +2239,7 @@ fn renderTokenOffset(
if (next_token.id == .MultilineStringLiteralLine) {
return;
} else {
- try stream.write("\n");
+ try stream.writeAll("\n");
start_col.* = 0;
return;
}
@@ -2309,7 +2302,7 @@ fn renderTokenOffset(
if (next_token.id == .MultilineStringLiteralLine) {
return;
} else {
- try stream.write("\n");
+ try stream.writeAll("\n");
start_col.* = 0;
return;
}
@@ -2327,7 +2320,7 @@ fn renderTokenOffset(
const newline_count = if (loc.line == 1) @as(u8, 1) else @as(u8, 2);
try stream.writeByteNTimes('\n', newline_count);
try stream.writeByteNTimes(' ', indent);
- try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
+ try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
offset += 1;
token = next_token;
@@ -2338,7 +2331,7 @@ fn renderTokenOffset(
if (next_token.id == .MultilineStringLiteralLine) {
return;
} else {
- try stream.write("\n");
+ try stream.writeAll("\n");
start_col.* = 0;
return;
}
@@ -2381,7 +2374,7 @@ fn renderToken(
indent: usize,
start_col: *usize,
space: Space,
-) (@TypeOf(stream).Child.Error || Error)!void {
+) (@TypeOf(stream).Error || Error)!void {
return renderTokenOffset(tree, stream, token_index, indent, start_col, space, 0);
}
@@ -2391,7 +2384,7 @@ fn renderDocComments(
node: var,
indent: usize,
start_col: *usize,
-) (@TypeOf(stream).Child.Error || Error)!void {
+) (@TypeOf(stream).Error || Error)!void {
const comment = node.doc_comments orelse return;
var it = comment.lines.iterator(0);
const first_token = node.firstToken();
@@ -2401,7 +2394,7 @@ fn renderDocComments(
try stream.writeByteNTimes(' ', indent);
} else {
try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.NoComment);
- try stream.write("\n");
+ try stream.writeAll("\n");
try stream.writeByteNTimes(' ', indent);
}
}
@@ -2427,27 +2420,23 @@ fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
};
}
-// An OutStream that returns whether the given character has been written to it.
-// The contents are not written to anything.
+/// A `std.io.OutStream` that returns whether the given character has been written to it.
+/// The contents are not written to anything.
const FindByteOutStream = struct {
- const Self = FindByteOutStream;
- pub const Error = error{};
- pub const Stream = std.io.OutStream(Error);
-
- stream: Stream,
byte_found: bool,
byte: u8,
- pub fn init(byte: u8) Self {
- return Self{
- .stream = Stream{ .writeFn = writeFn },
+ pub const Error = error{};
+ pub const OutStream = std.io.OutStream(*FindByteOutStream, Error, write);
+
+ pub fn init(byte: u8) FindByteOutStream {
+ return FindByteOutStream{
.byte = byte,
.byte_found = false,
};
}
- fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
- const self = @fieldParentPtr(Self, "stream", out_stream);
+ pub fn write(self: *FindByteOutStream, bytes: []const u8) Error!usize {
if (self.byte_found) return bytes.len;
self.byte_found = blk: {
for (bytes) |b|
@@ -2456,11 +2445,15 @@ const FindByteOutStream = struct {
};
return bytes.len;
}
+
+ pub fn outStream(self: *FindByteOutStream) OutStream {
+ return .{ .context = self };
+ }
};
-fn copyFixingWhitespace(stream: var, slice: []const u8) @TypeOf(stream).Child.Error!void {
+fn copyFixingWhitespace(stream: var, slice: []const u8) @TypeOf(stream).Error!void {
for (slice) |byte| switch (byte) {
- '\t' => try stream.write(" "),
+ '\t' => try stream.writeAll(" "),
'\r' => {},
else => try stream.writeByte(byte),
};
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
index 41def3812..78aafeff2 100644
--- a/src-self-hosted/libc_installation.zig
+++ b/src-self-hosted/libc_installation.zig
@@ -38,7 +38,7 @@ pub const LibCInstallation = struct {
pub fn parse(
allocator: *Allocator,
libc_file: []const u8,
- stderr: *std.io.OutStream(fs.File.WriteError),
+ stderr: var,
) !LibCInstallation {
var self: LibCInstallation = .{};
@@ -123,7 +123,7 @@ pub const LibCInstallation = struct {
return self;
}
- pub fn render(self: LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void {
+ pub fn render(self: LibCInstallation, out: var) !void {
@setEvalBranchQuota(4000);
const include_dir = self.include_dir orelse "";
const sys_include_dir = self.sys_include_dir orelse "";
diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig
index bb3841ba2..473e3dfa5 100644
--- a/src-self-hosted/print_targets.zig
+++ b/src-self-hosted/print_targets.zig
@@ -52,7 +52,7 @@ const available_libcs = [_][]const u8{
"sparc-linux-gnu",
"sparcv9-linux-gnu",
"wasm32-freestanding-musl",
- "x86_64-linux-gnu (native)",
+ "x86_64-linux-gnu",
"x86_64-linux-gnux32",
"x86_64-linux-musl",
"x86_64-windows-gnu",
@@ -61,7 +61,8 @@ const available_libcs = [_][]const u8{
pub fn cmdTargets(
allocator: *Allocator,
args: []const []const u8,
- stdout: *io.OutStream(fs.File.WriteError),
+ /// Output stream
+ stdout: var,
native_target: Target,
) !void {
const available_glibcs = blk: {
@@ -92,9 +93,9 @@ pub fn cmdTargets(
};
defer allocator.free(available_glibcs);
- const BOS = io.BufferedOutStream(fs.File.WriteError);
- var bos = BOS.init(stdout);
- var jws = std.json.WriteStream(BOS.Stream, 6).init(&bos.stream);
+ var bos = io.bufferedOutStream(4096, stdout);
+ const bos_stream = bos.outStream();
+ var jws = std.json.WriteStream(@TypeOf(bos_stream), 6).init(bos_stream);
try jws.beginObject();
@@ -219,6 +220,6 @@ pub fn cmdTargets(
try jws.endObject();
- try bos.stream.writeByte('\n');
+ try bos_stream.writeByte('\n');
return bos.flush();
}
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index ee6789ab8..8f2656de4 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -18,8 +18,8 @@ const assert = std.debug.assert;
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
var stderr_file: fs.File = undefined;
-var stderr: *io.OutStream(fs.File.WriteError) = undefined;
-var stdout: *io.OutStream(fs.File.WriteError) = undefined;
+var stderr: fs.File.OutStream = undefined;
+var stdout: fs.File.OutStream = undefined;
comptime {
_ = @import("dep_tokenizer.zig");
@@ -146,7 +146,7 @@ export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, error
}
export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
- const c_out_stream = &std.io.COutStream.init(output_file).stream;
+ const c_out_stream = std.io.cOutStream(output_file);
_ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
error.SystemResources => return .SystemResources,
@@ -186,9 +186,9 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
try args_list.append(mem.toSliceConst(u8, argv[arg_i]));
}
- stdout = &std.io.getStdOut().outStream().stream;
+ stdout = std.io.getStdOut().outStream();
stderr_file = std.io.getStdErr();
- stderr = &stderr_file.outStream().stream;
+ stderr = stderr_file.outStream();
const args = args_list.toSliceConst()[2..];
@@ -203,11 +203,11 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
const arg = args[i];
if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "--help")) {
- try stdout.write(self_hosted_main.usage_fmt);
+ try stdout.writeAll(self_hosted_main.usage_fmt);
process.exit(0);
} else if (mem.eql(u8, arg, "--color")) {
if (i + 1 >= args.len) {
- try stderr.write("expected [auto|on|off] after --color\n");
+ try stderr.writeAll("expected [auto|on|off] after --color\n");
process.exit(1);
}
i += 1;
@@ -238,14 +238,14 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
if (stdin_flag) {
if (input_files.len != 0) {
- try stderr.write("cannot use --stdin with positional arguments\n");
+ try stderr.writeAll("cannot use --stdin with positional arguments\n");
process.exit(1);
}
const stdin_file = io.getStdIn();
var stdin = stdin_file.inStream();
- const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size);
+ const source_code = try stdin.readAllAlloc(allocator, self_hosted_main.max_src_size);
defer allocator.free(source_code);
const tree = std.zig.parse(allocator, source_code) catch |err| {
@@ -272,7 +272,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
}
if (input_files.len == 0) {
- try stderr.write("expected at least one source file argument\n");
+ try stderr.writeAll("expected at least one source file argument\n");
process.exit(1);
}
@@ -409,11 +409,11 @@ fn printErrMsgToFile(
const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
var text_buf = try std.Buffer.initSize(allocator, 0);
- var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
+ const out_stream = &text_buf.outStream();
try parse_error.render(&tree.tokens, out_stream);
const text = text_buf.toOwnedSlice();
- const stream = &file.outStream().stream;
+ const stream = &file.outStream();
try stream.print("{}:{}:{}: error: {}\n", .{ path, start_loc.line + 1, start_loc.column + 1, text });
if (!color_on) return;
@@ -641,7 +641,7 @@ fn cmdTargets(zig_triple: [*:0]const u8) !void {
return @import("print_targets.zig").cmdTargets(
std.heap.c_allocator,
&[0][]u8{},
- &std.io.getStdOut().outStream().stream,
+ std.io.getStdOut().outStream(),
target,
);
}
@@ -808,7 +808,7 @@ const Stage2LibCInstallation = extern struct {
// ABI warning
export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error {
stderr_file = std.io.getStdErr();
- stderr = &stderr_file.outStream().stream;
+ stderr = stderr_file.outStream();
const libc_file = mem.toSliceConst(u8, libc_file_z);
var libc = LibCInstallation.parse(std.heap.c_allocator, libc_file, stderr) catch |err| switch (err) {
error.ParseError => return .SemanticAnalyzeFail,
@@ -870,7 +870,7 @@ export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error {
// ABI warning
export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error {
var libc = stage1_libc.toStage2();
- const c_out_stream = &std.io.COutStream.init(output_file).stream;
+ const c_out_stream = std.io.cOutStream(output_file);
libc.render(c_out_stream) catch |err| switch (err) {
error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
error.SystemResources => return .SystemResources,
From 300fceac6eca99fd858678b03a47357e72856e10 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Tue, 10 Mar 2020 20:54:05 +0100
Subject: [PATCH 037/111] ir: Implement more safety checks for shl/shr
The checks are now valid on types whose size is not a power of two.
Closes #2096
---
src/all_types.hpp | 1 +
src/codegen.cpp | 32 +++++++++++++++++++++++++++
src/ir.cpp | 48 ++++++++++++++++++++---------------------
test/compile_errors.zig | 35 ++++++++++++++++++++++++++++--
test/runtime_safety.zig | 31 ++++++++++++++++++++++++++
5 files changed, 120 insertions(+), 27 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 14b99228c..53aae9e23 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1834,6 +1834,7 @@ enum PanicMsgId {
PanicMsgIdBadNoAsyncCall,
PanicMsgIdResumeNotSuspendedFn,
PanicMsgIdBadSentinel,
+ PanicMsgIdShxTooBigRhs,
PanicMsgIdCount,
};
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 22cb97520..d659e27d8 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -974,6 +974,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
return buf_create_from_str("resumed a non-suspended function");
case PanicMsgIdBadSentinel:
return buf_create_from_str("sentinel mismatch");
+ case PanicMsgIdShxTooBigRhs:
+ return buf_create_from_str("shift amount is greater than the type size");
}
zig_unreachable();
}
@@ -2841,6 +2843,26 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast
}
+static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type, LLVMValueRef value) {
+ // We only check if the rhs value of the shift expression is greater or
+ // equal to the number of bits of the lhs if it's not a power of two,
+ // otherwise the check is useful as the allowed values are limited by the
+ // operand type itself
+ if (!is_power_of_2(lhs_type->data.integral.bit_count)) {
+ LLVMValueRef bit_count_value = LLVMConstInt(get_llvm_type(g, rhs_type),
+ lhs_type->data.integral.bit_count, false);
+ LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, "");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckFail");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckOk");
+ LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_safety_crash(g, PanicMsgIdShxTooBigRhs);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+}
+
static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
IrInstGenBinOp *bin_op_instruction)
{
@@ -2949,6 +2971,11 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
{
assert(scalar_type->id == ZigTypeIdInt);
LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value->type, scalar_type, op2_value);
+
+ if (want_runtime_safety) {
+ gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value);
+ }
+
bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy);
if (is_sloppy) {
return LLVMBuildShl(g->builder, op1_value, op2_casted, "");
@@ -2965,6 +2992,11 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutableGen *executable,
{
assert(scalar_type->id == ZigTypeIdInt);
LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value->type, scalar_type, op2_value);
+
+ if (want_runtime_safety) {
+ gen_shift_rhs_check(g, scalar_type, op2->value->type, op2_value);
+ }
+
bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy);
if (is_sloppy) {
if (scalar_type->data.integral.is_signed) {
diff --git a/src/ir.cpp b/src/ir.cpp
index e5b28f84c..b9b42141b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -16648,36 +16648,34 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
return ira->codegen->invalid_inst_gen;
}
} else {
+ assert(op1->value->type->data.integral.bit_count > 0);
ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
- op1->value->type->data.integral.bit_count - 1);
- if (bin_op_instruction->op_id == IrBinOpBitShiftLeftLossy &&
- op2->value->type->id == ZigTypeIdComptimeInt) {
-
- ZigValue *op2_val = ir_resolve_const(ira, op2, UndefBad);
- if (op2_val == nullptr)
- return ira->codegen->invalid_inst_gen;
- if (!bigint_fits_in_bits(&op2_val->data.x_bigint,
- shift_amt_type->data.integral.bit_count,
- op2_val->data.x_bigint.is_negative)) {
- Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10);
- ErrorMsg* msg = ir_add_error(ira,
- &bin_op_instruction->base.base,
- buf_sprintf("RHS of shift is too large for LHS type"));
- add_error_note(
- ira->codegen,
- msg,
- op2->base.source_node,
- buf_sprintf("value %s cannot fit into type %s",
- buf_ptr(val_buf),
- buf_ptr(&shift_amt_type->name)));
- return ira->codegen->invalid_inst_gen;
- }
- }
+ op1->value->type->data.integral.bit_count - 1);
casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
if (type_is_invalid(casted_op2->value->type))
return ira->codegen->invalid_inst_gen;
+
+ if (instr_is_comptime(casted_op2)) {
+ ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
+ if (op2_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ BigInt bit_count_value = {0};
+ bigint_init_unsigned(&bit_count_value, op1->value->type->data.integral.bit_count);
+
+ if (bigint_cmp(&op2_val->data.x_bigint, &bit_count_value) != CmpLT) {
+ ErrorMsg* msg = ir_add_error(ira,
+ &bin_op_instruction->base.base,
+ buf_sprintf("RHS of shift is too large for LHS type"));
+ add_error_note(ira->codegen, msg, op1->base.source_node,
+ buf_sprintf("type %s has only %u bits",
+ buf_ptr(&op1->value->type->name),
+ op1->value->type->data.integral.bit_count));
+
+ return ira->codegen->invalid_inst_gen;
+ }
+ }
}
if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) {
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index a2d4e8ac2..507845333 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2,6 +2,38 @@ const tests = @import("tests.zig");
const std = @import("std");
pub fn addCases(cases: *tests.CompileErrorContext) void {
+ cases.addTest("shift on type with non-power-of-two size",
+ \\export fn entry() void {
+ \\ const S = struct {
+ \\ fn a() void {
+ \\ var x: u24 = 42;
+ \\ _ = x >> 24;
+ \\ }
+ \\ fn b() void {
+ \\ var x: u24 = 42;
+ \\ _ = x << 24;
+ \\ }
+ \\ fn c() void {
+ \\ var x: u24 = 42;
+ \\ _ = @shlExact(x, 24);
+ \\ }
+ \\ fn d() void {
+ \\ var x: u24 = 42;
+ \\ _ = @shrExact(x, 24);
+ \\ }
+ \\ };
+ \\ S.a();
+ \\ S.b();
+ \\ S.c();
+ \\ S.d();
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:5:19: error: RHS of shift is too large for LHS type",
+ "tmp.zig:9:19: error: RHS of shift is too large for LHS type",
+ "tmp.zig:13:17: error: RHS of shift is too large for LHS type",
+ "tmp.zig:17:17: error: RHS of shift is too large for LHS type",
+ });
+
cases.addTest("combination of noasync and async",
\\export fn entry() void {
\\ noasync {
@@ -4029,8 +4061,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\export fn entry() u16 { return f(); }
, &[_][]const u8{
- "tmp.zig:3:14: error: RHS of shift is too large for LHS type",
- "tmp.zig:3:17: note: value 8 cannot fit into type u3",
+ "tmp.zig:3:17: error: integer value 8 cannot be coerced to type 'u3'",
});
cases.add("missing function call param",
diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig
index e183c6979..9855aae16 100644
--- a/test/runtime_safety.zig
+++ b/test/runtime_safety.zig
@@ -1,6 +1,37 @@
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompareOutputContext) void {
+ cases.addRuntimeSafety("shift left by huge amount",
+ \\const std = @import("std");
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ std.debug.warn("{}\n", .{message});
+ \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
+ \\ std.process.exit(126); // good
+ \\ }
+ \\ std.process.exit(0); // test failed
+ \\}
+ \\pub fn main() void {
+ \\ var x: u24 = 42;
+ \\ var y: u5 = 24;
+ \\ var z = x >> y;
+ \\}
+ );
+
+ cases.addRuntimeSafety("shift right by huge amount",
+ \\const std = @import("std");
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
+ \\ std.process.exit(126); // good
+ \\ }
+ \\ std.process.exit(0); // test failed
+ \\}
+ \\pub fn main() void {
+ \\ var x: u24 = 42;
+ \\ var y: u5 = 24;
+ \\ var z = x << y;
+ \\}
+ );
+
cases.addRuntimeSafety("slice sentinel mismatch - optional pointers",
\\const std = @import("std");
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
From b6fbd524f122449e6e2bb4d73ce3f59b01286f50 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 16:31:04 -0400
Subject: [PATCH 038/111] (breaking) improve and simplify fixed buffer streams
API
---
lib/std/io.zig | 156 +------------------------
lib/std/io/buffered_atomic_file.zig | 4 +-
lib/std/io/buffered_in_stream.zig | 84 ++++++++++++++
lib/std/io/buffered_out_stream.zig | 23 +---
lib/std/io/fixed_buffer_stream.zig | 173 +++++++++++++++++++---------
lib/std/json.zig | 4 +-
lib/std/progress.zig | 2 +-
lib/std/std.zig | 1 -
src-self-hosted/print_targets.zig | 2 +-
9 files changed, 218 insertions(+), 231 deletions(-)
create mode 100644 lib/std/io/buffered_in_stream.zig
diff --git a/lib/std/io.zig b/lib/std/io.zig
index dcb0551dc..128346127 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -95,18 +95,18 @@ pub fn getStdIn() File {
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
pub const InStream = @import("io/in_stream.zig").InStream;
pub const OutStream = @import("io/out_stream.zig").OutStream;
-pub const FixedBufferInStream = @import("io/fixed_buffer_stream.zig").FixedBufferInStream;
pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile;
pub const BufferedOutStream = @import("io/buffered_out_stream.zig").BufferedOutStream;
-pub const BufferedOutStreamCustom = @import("io/buffered_out_stream.zig").BufferedOutStreamCustom;
pub const bufferedOutStream = @import("io/buffered_out_stream.zig").bufferedOutStream;
-pub const CountingOutStream = @import("io/counting_out_stream.zig").CountingOutStream;
+pub const BufferedInStream = @import("io/buffered_in_stream.zig").BufferedInStream;
+pub const bufferedInStream = @import("io/buffered_in_stream.zig").bufferedInStream;
-pub fn fixedBufferStream(bytes: []const u8) FixedBufferInStream {
- return (FixedBufferInStream{ .bytes = bytes, .pos = 0 });
-}
+pub const FixedBufferStream = @import("io/fixed_buffer_stream.zig").FixedBufferStream;
+pub const fixedBufferStream = @import("io/fixed_buffer_stream.zig").fixedBufferStream;
+
+pub const CountingOutStream = @import("io/counting_out_stream.zig").CountingOutStream;
pub fn cOutStream(c_file: *std.c.FILE) COutStream {
return .{ .context = c_file };
@@ -144,92 +144,6 @@ pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 {
return fs.cwd().readFileAlloc(allocator, path, math.maxInt(usize));
}
-pub fn BufferedInStream(comptime Error: type) type {
- return BufferedInStreamCustom(mem.page_size, Error);
-}
-
-pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
- return struct {
- const Self = @This();
- const Stream = InStream(Error);
-
- stream: Stream,
-
- unbuffered_in_stream: *Stream,
-
- const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
- fifo: FifoType,
-
- pub fn init(unbuffered_in_stream: *Stream) Self {
- return Self{
- .unbuffered_in_stream = unbuffered_in_stream,
- .fifo = FifoType.init(),
- .stream = Stream{ .readFn = readFn },
- };
- }
-
- fn readFn(in_stream: *Stream, dest: []u8) !usize {
- const self = @fieldParentPtr(Self, "stream", in_stream);
- var dest_index: usize = 0;
- while (dest_index < dest.len) {
- const written = self.fifo.read(dest[dest_index..]);
- if (written == 0) {
- // fifo empty, fill it
- const writable = self.fifo.writableSlice(0);
- assert(writable.len > 0);
- const n = try self.unbuffered_in_stream.read(writable);
- if (n == 0) {
- // reading from the unbuffered stream returned nothing
- // so we have nothing left to read.
- return dest_index;
- }
- self.fifo.update(n);
- }
- dest_index += written;
- }
- return dest.len;
- }
- };
-}
-
-test "io.BufferedInStream" {
- const OneByteReadInStream = struct {
- const Error = error{NoError};
- const Stream = InStream(Error);
-
- stream: Stream,
- str: []const u8,
- curr: usize,
-
- fn init(str: []const u8) @This() {
- return @This(){
- .stream = Stream{ .readFn = readFn },
- .str = str,
- .curr = 0,
- };
- }
-
- fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
- const self = @fieldParentPtr(@This(), "stream", in_stream);
- if (self.str.len <= self.curr or dest.len == 0)
- return 0;
-
- dest[0] = self.str[self.curr];
- self.curr += 1;
- return 1;
- }
- };
-
- const str = "This is a test";
- var one_byte_stream = OneByteReadInStream.init(str);
- var buf_in_stream = BufferedInStream(OneByteReadInStream.Error).init(&one_byte_stream.stream);
- const stream = &buf_in_stream.stream;
-
- const res = try stream.readAllAlloc(testing.allocator, str.len + 1);
- defer testing.allocator.free(res);
- testing.expectEqualSlices(u8, str, res);
-}
-
/// Creates a stream which supports 'un-reading' data, so that it can be read again.
/// This makes look-ahead style parsing much easier.
pub fn PeekStream(comptime buffer_type: std.fifo.LinearFifoBufferType, comptime InStreamError: type) type {
@@ -473,64 +387,6 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
};
}
-/// This is a simple OutStream that writes to a fixed buffer. If the returned number
-/// of bytes written is less than requested, the buffer is full.
-/// Returns error.OutOfMemory when no bytes would be written.
-pub const SliceOutStream = struct {
- pub const Error = error{OutOfMemory};
- pub const Stream = OutStream(Error);
-
- stream: Stream,
-
- pos: usize,
- slice: []u8,
-
- pub fn init(slice: []u8) SliceOutStream {
- return SliceOutStream{
- .slice = slice,
- .pos = 0,
- .stream = Stream{ .writeFn = writeFn },
- };
- }
-
- pub fn getWritten(self: *const SliceOutStream) []const u8 {
- return self.slice[0..self.pos];
- }
-
- pub fn reset(self: *SliceOutStream) void {
- self.pos = 0;
- }
-
- fn writeFn(out_stream: *Stream, bytes: []const u8) Error!usize {
- const self = @fieldParentPtr(SliceOutStream, "stream", out_stream);
-
- if (bytes.len == 0) return 0;
-
- assert(self.pos <= self.slice.len);
-
- const n = if (self.pos + bytes.len <= self.slice.len)
- bytes.len
- else
- self.slice.len - self.pos;
-
- std.mem.copy(u8, self.slice[self.pos .. self.pos + n], bytes[0..n]);
- self.pos += n;
-
- if (n == 0) return error.OutOfMemory;
-
- return n;
- }
-};
-
-test "io.SliceOutStream" {
- var buf: [255]u8 = undefined;
- var slice_stream = SliceOutStream.init(buf[0..]);
- const stream = &slice_stream.stream;
-
- try stream.print("{}{}!", .{ "Hello", "World" });
- testing.expectEqualSlices(u8, "HelloWorld!", slice_stream.getWritten());
-}
-
/// An OutStream that doesn't write to anything.
pub const null_out_stream = @as(NullOutStream, .{ .context = {} });
diff --git a/lib/std/io/buffered_atomic_file.zig b/lib/std/io/buffered_atomic_file.zig
index 48c550c90..e2f8c75af 100644
--- a/lib/std/io/buffered_atomic_file.zig
+++ b/lib/std/io/buffered_atomic_file.zig
@@ -10,7 +10,7 @@ pub const BufferedAtomicFile = struct {
allocator: *mem.Allocator,
pub const buffer_size = 4096;
- pub const BufferedOutStream = std.io.BufferedOutStreamCustom(buffer_size, File.OutStream);
+ pub const BufferedOutStream = std.io.BufferedOutStream(buffer_size, File.OutStream);
pub const OutStream = std.io.OutStream(*BufferedOutStream, BufferedOutStream.Error, BufferedOutStream.write);
/// TODO when https://github.com/ziglang/zig/issues/2761 is solved
@@ -29,7 +29,7 @@ pub const BufferedAtomicFile = struct {
errdefer self.atomic_file.deinit();
self.file_stream = self.atomic_file.file.outStream();
- self.buffered_stream = std.io.bufferedOutStream(buffer_size, self.file_stream);
+ self.buffered_stream = .{ .unbuffered_out_stream = self.file_stream };
return self;
}
diff --git a/lib/std/io/buffered_in_stream.zig b/lib/std/io/buffered_in_stream.zig
new file mode 100644
index 000000000..72f1b30b7
--- /dev/null
+++ b/lib/std/io/buffered_in_stream.zig
@@ -0,0 +1,84 @@
+const std = @import("../std.zig");
+const io = std.io;
+
+pub fn BufferedInStream(comptime buffer_size: usize, comptime InStreamType) type {
+ return struct {
+ unbuffered_in_stream: InStreamType,
+ fifo: FifoType = FifoType.init(),
+
+ pub const Error = InStreamType.Error;
+ pub const InStream = io.InStream(*Self, Error, read);
+
+ const Self = @This();
+ const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
+
+ pub fn read(self: *Self, dest: []u8) Error!usize {
+ var dest_index: usize = 0;
+ while (dest_index < dest.len) {
+ const written = self.fifo.read(dest[dest_index..]);
+ if (written == 0) {
+ // fifo empty, fill it
+ const writable = self.fifo.writableSlice(0);
+ assert(writable.len > 0);
+ const n = try self.unbuffered_in_stream.read(writable);
+ if (n == 0) {
+ // reading from the unbuffered stream returned nothing
+ // so we have nothing left to read.
+ return dest_index;
+ }
+ self.fifo.update(n);
+ }
+ dest_index += written;
+ }
+ return dest.len;
+ }
+
+ pub fn inStream(self: *Self) InStream {
+ return .{ .context = self };
+ }
+ };
+}
+
+pub fn bufferedInStream(underlying_stream: var) BufferedInStream(4096, @TypeOf(underlying_stream)) {
+ return .{ .unbuffered_in_stream = underlying_stream };
+}
+
+test "io.BufferedInStream" {
+ const OneByteReadInStream = struct {
+ str: []const u8,
+ curr: usize,
+
+ const Error = error{NoError};
+ const Self = @This();
+ const InStream = io.InStream(*Self, Error, read);
+
+ fn init(str: []const u8) Self {
+ return Self{
+ .str = str,
+ .curr = 0,
+ };
+ }
+
+ fn read(self: *Self, dest: []u8) Error!usize {
+ if (self.str.len <= self.curr or dest.len == 0)
+ return 0;
+
+ dest[0] = self.str[self.curr];
+ self.curr += 1;
+ return 1;
+ }
+
+ fn inStream(self: *Self) InStream {
+ return .{ .context = self };
+ }
+ };
+
+ const str = "This is a test";
+ var one_byte_stream = OneByteReadInStream.init(str);
+ var buf_in_stream = bufferedInStream(one_byte_stream.inStream());
+ const stream = buf_in_stream.inStream();
+
+ const res = try stream.readAllAlloc(testing.allocator, str.len + 1);
+ defer testing.allocator.free(res);
+ testing.expectEqualSlices(u8, str, res);
+}
diff --git a/lib/std/io/buffered_out_stream.zig b/lib/std/io/buffered_out_stream.zig
index 3650022b2..43af83c53 100644
--- a/lib/std/io/buffered_out_stream.zig
+++ b/lib/std/io/buffered_out_stream.zig
@@ -1,14 +1,10 @@
const std = @import("../std.zig");
const io = std.io;
-pub fn BufferedOutStream(comptime OutStreamType: type) type {
- return BufferedOutStreamCustom(4096, OutStreamType);
-}
-
-pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamType: type) type {
+pub fn BufferedOutStream(comptime buffer_size: usize, comptime OutStreamType: type) type {
return struct {
unbuffered_out_stream: OutStreamType,
- fifo: FifoType,
+ fifo: FifoType = FifoType.init(),
pub const Error = OutStreamType.Error;
pub const OutStream = io.OutStream(*Self, Error, write);
@@ -16,13 +12,6 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamTy
const Self = @This();
const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size });
- pub fn init(unbuffered_out_stream: OutStreamType) Self {
- return Self{
- .unbuffered_out_stream = unbuffered_out_stream,
- .fifo = FifoType.init(),
- };
- }
-
pub fn flush(self: *Self) !void {
while (true) {
const slice = self.fifo.readableSlice(0);
@@ -47,10 +36,6 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamTy
};
}
-pub fn bufferedOutStream(
- comptime buffer_size: usize,
- underlying_stream: var,
-) BufferedOutStreamCustom(buffer_size, @TypeOf(underlying_stream)) {
- return BufferedOutStreamCustom(buffer_size, @TypeOf(underlying_stream)).init(underlying_stream);
+pub fn bufferedOutStream(underlying_stream: var) BufferedOutStream(4096, @TypeOf(underlying_stream)) {
+ return .{ .unbuffered_out_stream = underlying_stream };
}
-
diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig
index 847feeae0..75a337d3d 100644
--- a/lib/std/io/fixed_buffer_stream.zig
+++ b/lib/std/io/fixed_buffer_stream.zig
@@ -1,66 +1,129 @@
const std = @import("../std.zig");
const io = std.io;
+const testing = std.testing;
-pub const FixedBufferInStream = struct {
- bytes: []const u8,
- pos: usize,
+/// This turns a slice into an `io.OutStream`, `io.InStream`, or `io.SeekableStream`.
+/// If the supplied slice is const, then `io.OutStream` is not available.
+pub fn FixedBufferStream(comptime Buffer: type) type {
+ return struct {
+ /// `Buffer` is either a `[]u8` or `[]const u8`.
+ buffer: Buffer,
+ pos: usize,
- pub const SeekError = error{EndOfStream};
- pub const GetSeekPosError = error{};
+ pub const ReadError = error{EndOfStream};
+ pub const WriteError = error{OutOfMemory};
+ pub const SeekError = error{EndOfStream};
+ pub const GetSeekPosError = error{};
- pub const InStream = io.InStream(*FixedBufferInStream, error{}, read);
+ pub const InStream = io.InStream(*Self, ReadError, read);
+ pub const OutStream = io.OutStream(*Self, WriteError, write);
- pub fn inStream(self: *FixedBufferInStream) InStream {
- return .{ .context = self };
- }
+ pub const SeekableStream = io.SeekableStream(
+ *Self,
+ SeekError,
+ GetSeekPosError,
+ seekTo,
+ seekBy,
+ getPos,
+ getEndPos,
+ );
- pub const SeekableStream = io.SeekableStream(
- *FixedBufferInStream,
- SeekError,
- GetSeekPosError,
- seekTo,
- seekBy,
- getPos,
- getEndPos,
- );
+ const Self = @This();
- pub fn seekableStream(self: *FixedBufferInStream) SeekableStream {
- return .{ .context = self };
- }
-
- pub fn read(self: *FixedBufferInStream, dest: []u8) error{}!usize {
- const size = std.math.min(dest.len, self.bytes.len - self.pos);
- const end = self.pos + size;
-
- std.mem.copy(u8, dest[0..size], self.bytes[self.pos..end]);
- self.pos = end;
-
- return size;
- }
-
- pub fn seekTo(self: *FixedBufferInStream, pos: u64) SeekError!void {
- const usize_pos = std.math.cast(usize, pos) catch return error.EndOfStream;
- if (usize_pos > self.bytes.len) return error.EndOfStream;
- self.pos = usize_pos;
- }
-
- pub fn seekBy(self: *FixedBufferInStream, amt: i64) SeekError!void {
- if (amt < 0) {
- const abs_amt = std.math.cast(usize, -amt) catch return error.EndOfStream;
- if (abs_amt > self.pos) return error.EndOfStream;
- self.pos -= abs_amt;
- } else {
- const usize_amt = std.math.cast(usize, amt) catch return error.EndOfStream;
- if (self.pos + usize_amt > self.bytes.len) return error.EndOfStream;
- self.pos += usize_amt;
+ pub fn inStream(self: *Self) InStream {
+ return .{ .context = self };
}
- }
- pub fn getEndPos(self: *FixedBufferInStream) GetSeekPosError!u64 {
- return self.bytes.len;
- }
+ pub fn outStream(self: *Self) OutStream {
+ return .{ .context = self };
+ }
- pub fn getPos(self: *FixedBufferInStream) GetSeekPosError!u64 {
- return self.pos;
- }
-};
+ pub fn seekableStream(self: *Self) SeekableStream {
+ return .{ .context = self };
+ }
+
+ pub fn read(self: *Self, dest: []u8) ReadError!usize {
+ const size = std.math.min(dest.len, self.buffer.len - self.pos);
+ const end = self.pos + size;
+
+ std.mem.copy(u8, dest[0..size], self.buffer[self.pos..end]);
+ self.pos = end;
+
+ if (size == 0) return error.EndOfStream;
+ return size;
+ }
+
+ /// If the returned number of bytes written is less than requested, the
+ /// buffer is full. Returns `error.OutOfMemory` when no bytes would be written.
+ pub fn write(self: *Self, bytes: []const u8) WriteError!usize {
+ if (bytes.len == 0) return 0;
+
+ assert(self.pos <= self.buffer.len);
+
+ const n = if (self.pos + bytes.len <= self.buffer.len)
+ bytes.len
+ else
+ self.buffer.len - self.pos;
+
+ std.mem.copy(u8, self.buffer[self.pos .. self.pos + n], bytes[0..n]);
+ self.pos += n;
+
+ if (n == 0) return error.OutOfMemory;
+
+ return n;
+ }
+
+ pub fn seekTo(self: *Self, pos: u64) SeekError!void {
+ const usize_pos = std.math.cast(usize, pos) catch return error.EndOfStream;
+ if (usize_pos > self.buffer.len) return error.EndOfStream;
+ self.pos = usize_pos;
+ }
+
+ pub fn seekBy(self: *Self, amt: i64) SeekError!void {
+ if (amt < 0) {
+ const abs_amt = std.math.cast(usize, -amt) catch return error.EndOfStream;
+ if (abs_amt > self.pos) return error.EndOfStream;
+ self.pos -= abs_amt;
+ } else {
+ const usize_amt = std.math.cast(usize, amt) catch return error.EndOfStream;
+ if (self.pos + usize_amt > self.buffer.len) return error.EndOfStream;
+ self.pos += usize_amt;
+ }
+ }
+
+ pub fn getEndPos(self: *Self) GetSeekPosError!u64 {
+ return self.buffer.len;
+ }
+
+ pub fn getPos(self: *Self) GetSeekPosError!u64 {
+ return self.pos;
+ }
+
+ pub fn getWritten(self: Self) []const u8 {
+ return self.slice[0..self.pos];
+ }
+
+ pub fn reset(self: *Self) void {
+ self.pos = 0;
+ }
+ };
+}
+
+pub fn fixedBufferStream(buffer: var) FixedBufferStream(NonSentinelSpan(@TypeOf(buffer))) {
+ return .{ .buffer = std.mem.span(buffer), .pos = 0 };
+}
+
+fn NonSentinelSpan(comptime T: type) type {
+ var ptr_info = @typeInfo(std.mem.Span(T)).Pointer;
+ ptr_info.sentinel = null;
+ return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info });
+}
+
+test "FixedBufferStream" {
+ var buf: [255]u8 = undefined;
+ var fbs = fixedBufferStream(&buf);
+ const stream = fbs.outStream();
+
+ try stream.print("{}{}!", .{ "Hello", "World" });
+ testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
+}
diff --git a/lib/std/json.zig b/lib/std/json.zig
index bb59b4e0f..f2cf68d7e 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -2107,8 +2107,8 @@ test "import more json tests" {
test "write json then parse it" {
var out_buffer: [1000]u8 = undefined;
- var slice_out_stream = std.io.SliceOutStream.init(&out_buffer);
- const out_stream = &slice_out_stream.stream;
+ var fixed_buffer_stream = std.io.fixedBufferStream(&out_buffer);
+ const out_stream = fixed_buffer_stream.outStream();
var jw = WriteStream(@TypeOf(out_stream).Child, 4).init(out_stream);
try jw.beginObject();
diff --git a/lib/std/progress.zig b/lib/std/progress.zig
index 1c5ecd261..0264d99c9 100644
--- a/lib/std/progress.zig
+++ b/lib/std/progress.zig
@@ -177,7 +177,7 @@ pub const Progress = struct {
pub fn log(self: *Progress, comptime format: []const u8, args: var) void {
const file = self.terminal orelse return;
self.refresh();
- file.outStream().stream.print(format, args) catch {
+ file.outStream().print(format, args) catch {
self.terminal = null;
return;
};
diff --git a/lib/std/std.zig b/lib/std/std.zig
index dd4d968ef..9277370ca 100644
--- a/lib/std/std.zig
+++ b/lib/std/std.zig
@@ -5,7 +5,6 @@ pub const BloomFilter = @import("bloom_filter.zig").BloomFilter;
pub const BufMap = @import("buf_map.zig").BufMap;
pub const BufSet = @import("buf_set.zig").BufSet;
pub const Buffer = @import("buffer.zig").Buffer;
-pub const BufferOutStream = @import("io.zig").BufferOutStream;
pub const ChildProcess = @import("child_process.zig").ChildProcess;
pub const DynLib = @import("dynamic_library.zig").DynLib;
pub const HashMap = @import("hash_map.zig").HashMap;
diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig
index 473e3dfa5..ad506425d 100644
--- a/src-self-hosted/print_targets.zig
+++ b/src-self-hosted/print_targets.zig
@@ -93,7 +93,7 @@ pub fn cmdTargets(
};
defer allocator.free(available_glibcs);
- var bos = io.bufferedOutStream(4096, stdout);
+ var bos = io.bufferedOutStream(stdout);
const bos_stream = bos.outStream();
var jws = std.json.WriteStream(@TypeOf(bos_stream), 6).init(bos_stream);
From 8dc188ebe06b5b78dcead521561858fc27e25204 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Tue, 10 Mar 2020 22:33:32 +0200
Subject: [PATCH 039/111] support atomic operations with bools
---
src/codegen.cpp | 43 ++++++++++++++++++++++++++++++++
src/ir.cpp | 6 +++++
test/stage1/behavior/atomics.zig | 10 ++++++++
3 files changed, 59 insertions(+)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 22cb97520..7238d5041 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5224,6 +5224,15 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
+ ZigType *operand_type = instruction->new_value->value->type;
+ if (operand_type->id == ZigTypeIdBool) {
+ // treat bool as u8
+ ptr_val = LLVMBuildBitCast(g->builder, ptr_val,
+ LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), "");
+ cmp_val = LLVMConstZExt(cmp_val, g->builtin_types.entry_u8->llvm_type);
+ new_val = LLVMConstZExt(new_val, g->builtin_types.entry_u8->llvm_type);
+ }
+
LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
@@ -5236,6 +5245,9 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
if (!handle_is_ptr(g, optional_type)) {
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
+ if (operand_type->id == ZigTypeIdBool) {
+ payload_val = LLVMBuildTrunc(g->builder, payload_val, g->builtin_types.entry_bool->llvm_type, "");
+ }
LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, "");
}
@@ -5250,6 +5262,9 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
ir_assert(type_has_bits(g, child_type), &instruction->base);
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
+ if (operand_type->id == ZigTypeIdBool) {
+ payload_val = LLVMBuildTrunc(g->builder, payload_val, g->builtin_types.entry_bool->llvm_type, "");
+ }
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val);
@@ -5827,6 +5842,16 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutableGen *executable
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
+ if (operand_type->id == ZigTypeIdBool) {
+ // treat bool as u8
+ LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
+ LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), "");
+ LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_u8->llvm_type, "");
+ LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
+ g->is_single_threaded);
+ return LLVMBuildTrunc(g->builder, uncasted_result, g->builtin_types.entry_bool->llvm_type, "");
+ }
+
if (get_codegen_ptr_type_bail(g, operand_type) == nullptr) {
return ZigLLVMBuildAtomicRMW(g->builder, op, ptr, operand, ordering, g->is_single_threaded);
}
@@ -5845,6 +5870,16 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutableGen *executabl
{
LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->ordering);
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
+
+ ZigType *operand_type = instruction->ptr->value->type->data.pointer.child_type;
+ if (operand_type->id == ZigTypeIdBool) {
+ // treat bool as u8
+ ptr = LLVMBuildBitCast(g->builder, ptr,
+ LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), "");
+ LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, "");
+ LLVMSetOrdering(load_inst, ordering);
+ return LLVMBuildTrunc(g->builder, load_inst, g->builtin_types.entry_bool->llvm_type, "");
+ }
LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, "");
LLVMSetOrdering(load_inst, ordering);
return load_inst;
@@ -5856,6 +5891,14 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutableGen *executab
LLVMAtomicOrdering ordering = to_LLVMAtomicOrdering(instruction->ordering);
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
LLVMValueRef value = ir_llvm_value(g, instruction->value);
+
+ ZigType *operand_type = instruction->value->value->type;
+ if (operand_type->id == ZigTypeIdBool) {
+ // treat bool as u8
+ ptr = LLVMBuildBitCast(g->builder, ptr,
+ LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), "");
+ value = LLVMConstZExt(value, g->builtin_types.entry_u8->llvm_type);
+ }
LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value->type);
LLVMSetOrdering(store_inst, ordering);
return nullptr;
diff --git a/src/ir.cpp b/src/ir.cpp
index e5b28f84c..c6978ca0a 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -28357,6 +28357,8 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) {
max_atomic_bits, (uint32_t) operand_type->data.floating.bit_count));
return ira->codegen->builtin_types.entry_invalid;
}
+ } else if (operand_type->id == ZigTypeIdBool) {
+ // will be treated as u8
} else {
Error err;
ZigType *operand_ptr_type;
@@ -28397,6 +28399,10 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
ir_add_error(ira, &instruction->op->base,
buf_sprintf("@atomicRmw on enum only works with .Xchg"));
return ira->codegen->invalid_inst_gen;
+ } else if (operand_type->id == ZigTypeIdBool && op != AtomicRmwOp_xchg) {
+ ir_add_error(ira, &instruction->op->base,
+ buf_sprintf("@atomicRmw on bool only works with .Xchg"));
+ return ira->codegen->invalid_inst_gen;
} else if (operand_type->id == ZigTypeIdFloat && op > AtomicRmwOp_sub) {
ir_add_error(ira, &instruction->op->base,
buf_sprintf("@atomicRmw with float only works with .Xchg, .Add and .Sub"));
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index 0347f6f94..bda0a8469 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -161,3 +161,13 @@ fn testAtomicRmwFloat() void {
_ = @atomicRmw(f32, &x, .Sub, 2, .SeqCst);
expect(x == 4);
}
+
+test "atomics with bool" {
+ var x = false;
+ @atomicStore(bool, &x, true, .SeqCst);
+ expect(x == true);
+ expect(@atomicLoad(bool, &x, .SeqCst) == true);
+ expect(@atomicRmw(bool, &x, .Xchg, false, .SeqCst) == true);
+ expect(@cmpxchgStrong(bool, &x, false, true, .SeqCst, .SeqCst) == null);
+ expect(@cmpxchgStrong(bool, &x, false, true, .SeqCst, .SeqCst).? == true);
+}
From ee5b00a8b90ef375d0cd4432d31e3a4ed0b6f632 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Tue, 10 Mar 2020 22:46:19 +0200
Subject: [PATCH 040/111] use atomic bools in std lib
---
lib/std/atomic/queue.zig | 20 +++++++++-----------
lib/std/atomic/stack.zig | 31 +++++++++++++++----------------
lib/std/event/channel.zig | 24 ++++++++++++------------
lib/std/event/lock.zig | 36 +++++++++++++++++-------------------
lib/std/event/rwlock.zig | 32 ++++++++++++++++----------------
src/ir.cpp | 6 +++---
test/compile_errors.zig | 13 +++++++++++--
7 files changed, 83 insertions(+), 79 deletions(-)
diff --git a/lib/std/atomic/queue.zig b/lib/std/atomic/queue.zig
index 1969587f3..5c40acc3c 100644
--- a/lib/std/atomic/queue.zig
+++ b/lib/std/atomic/queue.zig
@@ -1,7 +1,5 @@
const std = @import("../std.zig");
const builtin = @import("builtin");
-const AtomicOrder = builtin.AtomicOrder;
-const AtomicRmwOp = builtin.AtomicRmwOp;
const assert = std.debug.assert;
const expect = std.testing.expect;
@@ -149,7 +147,7 @@ const Context = struct {
put_sum: isize,
get_sum: isize,
get_count: usize,
- puts_done: u8, // TODO make this a bool
+ puts_done: bool,
};
// TODO add lazy evaluated build options and then put puts_per_thread behind
@@ -173,7 +171,7 @@ test "std.atomic.Queue" {
.queue = &queue,
.put_sum = 0,
.get_sum = 0,
- .puts_done = 0,
+ .puts_done = false,
.get_count = 0,
};
@@ -186,7 +184,7 @@ test "std.atomic.Queue" {
}
}
expect(!context.queue.isEmpty());
- context.puts_done = 1;
+ context.puts_done = true;
{
var i: usize = 0;
while (i < put_thread_count) : (i += 1) {
@@ -208,7 +206,7 @@ test "std.atomic.Queue" {
for (putters) |t|
t.wait();
- @atomicStore(u8, &context.puts_done, 1, AtomicOrder.SeqCst);
+ @atomicStore(bool, &context.puts_done, true, .SeqCst);
for (getters) |t|
t.wait();
@@ -235,25 +233,25 @@ fn startPuts(ctx: *Context) u8 {
std.time.sleep(1); // let the os scheduler be our fuzz
const x = @bitCast(i32, r.random.scalar(u32));
const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
- node.* = Queue(i32).Node{
+ node.* = .{
.prev = undefined,
.next = undefined,
.data = x,
};
ctx.queue.put(node);
- _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
+ _ = @atomicRmw(isize, &ctx.put_sum, .Add, x, .SeqCst);
}
return 0;
}
fn startGets(ctx: *Context) u8 {
while (true) {
- const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
+ const last = @atomicLoad(bool, &ctx.puts_done, .SeqCst);
while (ctx.queue.get()) |node| {
std.time.sleep(1); // let the os scheduler be our fuzz
- _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
- _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
+ _ = @atomicRmw(isize, &ctx.get_sum, .Add, node.data, .SeqCst);
+ _ = @atomicRmw(usize, &ctx.get_count, .Add, 1, .SeqCst);
}
if (last) return 0;
diff --git a/lib/std/atomic/stack.zig b/lib/std/atomic/stack.zig
index 0f67a257c..07cb16e45 100644
--- a/lib/std/atomic/stack.zig
+++ b/lib/std/atomic/stack.zig
@@ -1,6 +1,5 @@
const assert = std.debug.assert;
const builtin = @import("builtin");
-const AtomicOrder = builtin.AtomicOrder;
const expect = std.testing.expect;
/// Many reader, many writer, non-allocating, thread-safe
@@ -11,7 +10,7 @@ pub fn Stack(comptime T: type) type {
root: ?*Node,
lock: @TypeOf(lock_init),
- const lock_init = if (builtin.single_threaded) {} else @as(u8, 0);
+ const lock_init = if (builtin.single_threaded) {} else false;
pub const Self = @This();
@@ -31,7 +30,7 @@ pub fn Stack(comptime T: type) type {
/// being the first item in the stack, returns the other item that was there.
pub fn pushFirst(self: *Self, node: *Node) ?*Node {
node.next = null;
- return @cmpxchgStrong(?*Node, &self.root, null, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst);
+ return @cmpxchgStrong(?*Node, &self.root, null, node, .SeqCst, .SeqCst);
}
pub fn push(self: *Self, node: *Node) void {
@@ -39,8 +38,8 @@ pub fn Stack(comptime T: type) type {
node.next = self.root;
self.root = node;
} else {
- while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
- defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
+ while (@atomicRmw(bool, &self.lock, .Xchg, true, .SeqCst) != false) {}
+ defer assert(@atomicRmw(bool, &self.lock, .Xchg, false, .SeqCst) == true);
node.next = self.root;
self.root = node;
@@ -53,8 +52,8 @@ pub fn Stack(comptime T: type) type {
self.root = root.next;
return root;
} else {
- while (@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) != 0) {}
- defer assert(@atomicRmw(u8, &self.lock, builtin.AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst) == 1);
+ while (@atomicRmw(bool, &self.lock, .Xchg, true, .SeqCst) != false) {}
+ defer assert(@atomicRmw(bool, &self.lock, .Xchg, false, .SeqCst) == true);
const root = self.root orelse return null;
self.root = root.next;
@@ -63,7 +62,7 @@ pub fn Stack(comptime T: type) type {
}
pub fn isEmpty(self: *Self) bool {
- return @atomicLoad(?*Node, &self.root, AtomicOrder.SeqCst) == null;
+ return @atomicLoad(?*Node, &self.root, .SeqCst) == null;
}
};
}
@@ -75,7 +74,7 @@ const Context = struct {
put_sum: isize,
get_sum: isize,
get_count: usize,
- puts_done: u8, // TODO make this a bool
+ puts_done: bool,
};
// TODO add lazy evaluated build options and then put puts_per_thread behind
// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
@@ -98,7 +97,7 @@ test "std.atomic.stack" {
.stack = &stack,
.put_sum = 0,
.get_sum = 0,
- .puts_done = 0,
+ .puts_done = false,
.get_count = 0,
};
@@ -109,7 +108,7 @@ test "std.atomic.stack" {
expect(startPuts(&context) == 0);
}
}
- context.puts_done = 1;
+ context.puts_done = true;
{
var i: usize = 0;
while (i < put_thread_count) : (i += 1) {
@@ -128,7 +127,7 @@ test "std.atomic.stack" {
for (putters) |t|
t.wait();
- @atomicStore(u8, &context.puts_done, 1, AtomicOrder.SeqCst);
+ @atomicStore(bool, &context.puts_done, true, .SeqCst);
for (getters) |t|
t.wait();
}
@@ -158,19 +157,19 @@ fn startPuts(ctx: *Context) u8 {
.data = x,
};
ctx.stack.push(node);
- _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
+ _ = @atomicRmw(isize, &ctx.put_sum, .Add, x, .SeqCst);
}
return 0;
}
fn startGets(ctx: *Context) u8 {
while (true) {
- const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
+ const last = @atomicLoad(bool, &ctx.puts_done, .SeqCst) == true;
while (ctx.stack.pop()) |node| {
std.time.sleep(1); // let the os scheduler be our fuzz
- _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
- _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
+ _ = @atomicRmw(isize, &ctx.get_sum, .Add, node.data, .SeqCst);
+ _ = @atomicRmw(usize, &ctx.get_count, .Add, 1, .SeqCst);
}
if (last) return 0;
diff --git a/lib/std/event/channel.zig b/lib/std/event/channel.zig
index 3c5b48d04..355bd7829 100644
--- a/lib/std/event/channel.zig
+++ b/lib/std/event/channel.zig
@@ -14,8 +14,8 @@ pub fn Channel(comptime T: type) type {
putters: std.atomic.Queue(PutNode),
get_count: usize,
put_count: usize,
- dispatch_lock: u8, // TODO make this a bool
- need_dispatch: u8, // TODO make this a bool
+ dispatch_lock: bool,
+ need_dispatch: bool,
// simple fixed size ring buffer
buffer_nodes: []T,
@@ -62,8 +62,8 @@ pub fn Channel(comptime T: type) type {
.buffer_len = 0,
.buffer_nodes = buffer,
.buffer_index = 0,
- .dispatch_lock = 0,
- .need_dispatch = 0,
+ .dispatch_lock = false,
+ .need_dispatch = false,
.getters = std.atomic.Queue(GetNode).init(),
.putters = std.atomic.Queue(PutNode).init(),
.or_null_queue = std.atomic.Queue(*std.atomic.Queue(GetNode).Node).init(),
@@ -165,15 +165,15 @@ pub fn Channel(comptime T: type) type {
fn dispatch(self: *SelfChannel) void {
// set the "need dispatch" flag
- @atomicStore(u8, &self.need_dispatch, 1, .SeqCst);
+ @atomicStore(bool, &self.need_dispatch, true, .SeqCst);
lock: while (true) {
// set the lock flag
- const prev_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 1, .SeqCst);
+ const prev_lock = @atomicRmw(bool, &self.dispatch_lock, .Xchg, true, .SeqCst);
if (prev_lock != 0) return;
// clear the need_dispatch flag since we're about to do it
- @atomicStore(u8, &self.need_dispatch, 0, .SeqCst);
+ @atomicStore(bool, &self.need_dispatch, false, .SeqCst);
while (true) {
one_dispatch: {
@@ -250,14 +250,14 @@ pub fn Channel(comptime T: type) type {
}
// clear need-dispatch flag
- const need_dispatch = @atomicRmw(u8, &self.need_dispatch, .Xchg, 0, .SeqCst);
- if (need_dispatch != 0) continue;
+ const need_dispatch = @atomicRmw(bool, &self.need_dispatch, .Xchg, false, .SeqCst);
+ if (need_dispatch) continue;
- const my_lock = @atomicRmw(u8, &self.dispatch_lock, .Xchg, 0, .SeqCst);
- assert(my_lock != 0);
+ const my_lock = @atomicRmw(bool, &self.dispatch_lock, .Xchg, false, .SeqCst);
+ assert(my_lock);
// we have to check again now that we unlocked
- if (@atomicLoad(u8, &self.need_dispatch, .SeqCst) != 0) continue :lock;
+ if (@atomicLoad(bool, &self.need_dispatch, .SeqCst)) continue :lock;
return;
}
diff --git a/lib/std/event/lock.zig b/lib/std/event/lock.zig
index b9cbb5d95..6b27bbd8c 100644
--- a/lib/std/event/lock.zig
+++ b/lib/std/event/lock.zig
@@ -11,9 +11,9 @@ const Loop = std.event.Loop;
/// Allows only one actor to hold the lock.
/// TODO: make this API also work in blocking I/O mode.
pub const Lock = struct {
- shared_bit: u8, // TODO make this a bool
+ shared: bool,
queue: Queue,
- queue_empty_bit: u8, // TODO make this a bool
+ queue_empty: bool,
const Queue = std.atomic.Queue(anyframe);
@@ -31,20 +31,19 @@ pub const Lock = struct {
}
// We need to release the lock.
- @atomicStore(u8, &self.lock.queue_empty_bit, 1, .SeqCst);
- @atomicStore(u8, &self.lock.shared_bit, 0, .SeqCst);
+ @atomicStore(bool, &self.lock.queue_empty, true, .SeqCst);
+ @atomicStore(bool, &self.lock.shared, false, .SeqCst);
// There might be a queue item. If we know the queue is empty, we can be done,
// because the other actor will try to obtain the lock.
// But if there's a queue item, we are the actor which must loop and attempt
// to grab the lock again.
- if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
+ if (@atomicLoad(bool, &self.lock.queue_empty, .SeqCst)) {
return;
}
while (true) {
- const old_bit = @atomicRmw(u8, &self.lock.shared_bit, .Xchg, 1, .SeqCst);
- if (old_bit != 0) {
+ if (@atomicRmw(bool, &self.lock.shared, .Xchg, true, .SeqCst)) {
// We did not obtain the lock. Great, the queue is someone else's problem.
return;
}
@@ -56,11 +55,11 @@ pub const Lock = struct {
}
// Release the lock again.
- @atomicStore(u8, &self.lock.queue_empty_bit, 1, .SeqCst);
- @atomicStore(u8, &self.lock.shared_bit, 0, .SeqCst);
+ @atomicStore(bool, &self.lock.queue_empty, true, .SeqCst);
+ @atomicStore(bool, &self.lock.shared, false, .SeqCst);
// Find out if we can be done.
- if (@atomicLoad(u8, &self.lock.queue_empty_bit, .SeqCst) == 1) {
+ if (@atomicLoad(bool, &self.lock.queue_empty, .SeqCst)) {
return;
}
}
@@ -69,24 +68,24 @@ pub const Lock = struct {
pub fn init() Lock {
return Lock{
- .shared_bit = 0,
+ .shared = false,
.queue = Queue.init(),
- .queue_empty_bit = 1,
+ .queue_empty = true,
};
}
pub fn initLocked() Lock {
return Lock{
- .shared_bit = 1,
+ .shared = true,
.queue = Queue.init(),
- .queue_empty_bit = 1,
+ .queue_empty = true,
};
}
/// Must be called when not locked. Not thread safe.
/// All calls to acquire() and release() must complete before calling deinit().
pub fn deinit(self: *Lock) void {
- assert(self.shared_bit == 0);
+ assert(!self.shared);
while (self.queue.get()) |node| resume node.data;
}
@@ -99,12 +98,11 @@ pub const Lock = struct {
// At this point, we are in the queue, so we might have already been resumed.
- // We set this bit so that later we can rely on the fact, that if queue_empty_bit is 1, some actor
+ // We set this bit so that later we can rely on the fact, that if queue_empty == true, some actor
// will attempt to grab the lock.
- @atomicStore(u8, &self.queue_empty_bit, 0, .SeqCst);
+ @atomicStore(bool, &self.queue_empty, false, .SeqCst);
- const old_bit = @atomicRmw(u8, &self.shared_bit, .Xchg, 1, .SeqCst);
- if (old_bit == 0) {
+ if (!@atomicRmw(bool, &self.shared, .Xchg, true, .SeqCst)) {
if (self.queue.get()) |node| {
// Whether this node is us or someone else, we tail resume it.
resume node.data;
diff --git a/lib/std/event/rwlock.zig b/lib/std/event/rwlock.zig
index f4b13d008..425088063 100644
--- a/lib/std/event/rwlock.zig
+++ b/lib/std/event/rwlock.zig
@@ -16,8 +16,8 @@ pub const RwLock = struct {
shared_state: State,
writer_queue: Queue,
reader_queue: Queue,
- writer_queue_empty_bit: u8, // TODO make this a bool
- reader_queue_empty_bit: u8, // TODO make this a bool
+ writer_queue_empty: bool,
+ reader_queue_empty: bool,
reader_lock_count: usize,
const State = enum(u8) {
@@ -40,7 +40,7 @@ pub const RwLock = struct {
return;
}
- @atomicStore(u8, &self.lock.reader_queue_empty_bit, 1, .SeqCst);
+ @atomicStore(bool, &self.lock.reader_queue_empty, true, .SeqCst);
if (@cmpxchgStrong(State, &self.lock.shared_state, .ReadLock, .Unlocked, .SeqCst, .SeqCst) != null) {
// Didn't unlock. Someone else's problem.
return;
@@ -62,7 +62,7 @@ pub const RwLock = struct {
}
// We need to release the write lock. Check if any readers are waiting to grab the lock.
- if (@atomicLoad(u8, &self.lock.reader_queue_empty_bit, .SeqCst) == 0) {
+ if (!@atomicLoad(bool, &self.lock.reader_queue_empty, .SeqCst)) {
// Switch to a read lock.
@atomicStore(State, &self.lock.shared_state, .ReadLock, .SeqCst);
while (self.lock.reader_queue.get()) |node| {
@@ -71,7 +71,7 @@ pub const RwLock = struct {
return;
}
- @atomicStore(u8, &self.lock.writer_queue_empty_bit, 1, .SeqCst);
+ @atomicStore(bool, &self.lock.writer_queue_empty, true, .SeqCst);
@atomicStore(State, &self.lock.shared_state, .Unlocked, .SeqCst);
self.lock.commonPostUnlock();
@@ -79,12 +79,12 @@ pub const RwLock = struct {
};
pub fn init() RwLock {
- return RwLock{
+ return .{
.shared_state = .Unlocked,
.writer_queue = Queue.init(),
- .writer_queue_empty_bit = 1,
+ .writer_queue_empty = true,
.reader_queue = Queue.init(),
- .reader_queue_empty_bit = 1,
+ .reader_queue_empty = true,
.reader_lock_count = 0,
};
}
@@ -111,9 +111,9 @@ pub const RwLock = struct {
// At this point, we are in the reader_queue, so we might have already been resumed.
- // We set this bit so that later we can rely on the fact, that if reader_queue_empty_bit is 1,
+ // We set this bit so that later we can rely on the fact, that if reader_queue_empty == true,
// some actor will attempt to grab the lock.
- @atomicStore(u8, &self.reader_queue_empty_bit, 0, .SeqCst);
+ @atomicStore(bool, &self.reader_queue_empty, false, .SeqCst);
// Here we don't care if we are the one to do the locking or if it was already locked for reading.
const have_read_lock = if (@cmpxchgStrong(State, &self.shared_state, .Unlocked, .ReadLock, .SeqCst, .SeqCst)) |old_state| old_state == .ReadLock else true;
@@ -142,9 +142,9 @@ pub const RwLock = struct {
// At this point, we are in the writer_queue, so we might have already been resumed.
- // We set this bit so that later we can rely on the fact, that if writer_queue_empty_bit is 1,
+ // We set this bit so that later we can rely on the fact, that if writer_queue_empty == true,
// some actor will attempt to grab the lock.
- @atomicStore(u8, &self.writer_queue_empty_bit, 0, .SeqCst);
+ @atomicStore(bool, &self.writer_queue_empty, false, .SeqCst);
// Here we must be the one to acquire the write lock. It cannot already be locked.
if (@cmpxchgStrong(State, &self.shared_state, .Unlocked, .WriteLock, .SeqCst, .SeqCst) == null) {
@@ -165,7 +165,7 @@ pub const RwLock = struct {
// obtain the lock.
// But if there's a writer_queue item or a reader_queue item,
// we are the actor which must loop and attempt to grab the lock again.
- if (@atomicLoad(u8, &self.writer_queue_empty_bit, .SeqCst) == 0) {
+ if (!@atomicLoad(bool, &self.writer_queue_empty, .SeqCst)) {
if (@cmpxchgStrong(State, &self.shared_state, .Unlocked, .WriteLock, .SeqCst, .SeqCst) != null) {
// We did not obtain the lock. Great, the queues are someone else's problem.
return;
@@ -176,12 +176,12 @@ pub const RwLock = struct {
return;
}
// Release the lock again.
- @atomicStore(u8, &self.writer_queue_empty_bit, 1, .SeqCst);
+ @atomicStore(bool, &self.writer_queue_empty, true, .SeqCst);
@atomicStore(State, &self.shared_state, .Unlocked, .SeqCst);
continue;
}
- if (@atomicLoad(u8, &self.reader_queue_empty_bit, .SeqCst) == 0) {
+ if (!@atomicLoad(bool, &self.reader_queue_empty, .SeqCst)) {
if (@cmpxchgStrong(State, &self.shared_state, .Unlocked, .ReadLock, .SeqCst, .SeqCst) != null) {
// We did not obtain the lock. Great, the queues are someone else's problem.
return;
@@ -195,7 +195,7 @@ pub const RwLock = struct {
return;
}
// Release the lock again.
- @atomicStore(u8, &self.reader_queue_empty_bit, 1, .SeqCst);
+ @atomicStore(bool, &self.reader_queue_empty, true, .SeqCst);
if (@cmpxchgStrong(State, &self.shared_state, .ReadLock, .Unlocked, .SeqCst, .SeqCst) != null) {
// Didn't unlock. Someone else's problem.
return;
diff --git a/src/ir.cpp b/src/ir.cpp
index c6978ca0a..cad1d382e 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -28397,15 +28397,15 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
if (operand_type->id == ZigTypeIdEnum && op != AtomicRmwOp_xchg) {
ir_add_error(ira, &instruction->op->base,
- buf_sprintf("@atomicRmw on enum only works with .Xchg"));
+ buf_sprintf("@atomicRmw with enum only allowed with .Xchg"));
return ira->codegen->invalid_inst_gen;
} else if (operand_type->id == ZigTypeIdBool && op != AtomicRmwOp_xchg) {
ir_add_error(ira, &instruction->op->base,
- buf_sprintf("@atomicRmw on bool only works with .Xchg"));
+ buf_sprintf("@atomicRmw with bool only allowed with .Xchg"));
return ira->codegen->invalid_inst_gen;
} else if (operand_type->id == ZigTypeIdFloat && op > AtomicRmwOp_sub) {
ir_add_error(ira, &instruction->op->base,
- buf_sprintf("@atomicRmw with float only works with .Xchg, .Add and .Sub"));
+ buf_sprintf("@atomicRmw with float only allowed with .Xchg, .Add and .Sub"));
return ira->codegen->invalid_inst_gen;
}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index a2d4e8ac2..28529b3f5 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2,6 +2,15 @@ const tests = @import("tests.zig");
const std = @import("std");
pub fn addCases(cases: *tests.CompileErrorContext) void {
+ cases.add("atomicrmw with bool op not .Xchg",
+ \\export fn entry() void {
+ \\ var x = false;
+ \\ _ = @atomicRmw(bool, &x, .Add, true, .SeqCst);
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:3:30: error: @atomicRmw with bool only allowed with .Xchg",
+ });
+
cases.addTest("combination of noasync and async",
\\export fn entry() void {
\\ noasync {
@@ -325,7 +334,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @atomicRmw(f32, &x, .And, 2, .SeqCst);
\\}
, &[_][]const u8{
- "tmp.zig:3:29: error: @atomicRmw with float only works with .Xchg, .Add and .Sub",
+ "tmp.zig:3:29: error: @atomicRmw with float only allowed with .Xchg, .Add and .Sub",
});
cases.add("intToPtr with misaligned address",
@@ -542,7 +551,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = @atomicRmw(E, &x, .Add, .b, .SeqCst);
\\}
, &[_][]const u8{
- "tmp.zig:9:27: error: @atomicRmw on enum only works with .Xchg",
+ "tmp.zig:9:27: error: @atomicRmw with enum only allowed with .Xchg",
});
cases.add("disallow coercion from non-null-terminated pointer to null-terminated pointer",
From 4ab13a359dfb14c93869e7f88320ec2aa438da9c Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Tue, 10 Mar 2020 23:04:49 +0100
Subject: [PATCH 041/111] ir: Fix shift code for u0 operands
---
src/ir.cpp | 46 +++++++++++++++++++++++------------
test/stage1/behavior/math.zig | 19 +++++++++++++++
2 files changed, 50 insertions(+), 15 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index b9b42141b..bb2dc75c6 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -16635,34 +16635,47 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
IrInstGen *casted_op2;
IrBinOp op_id = bin_op_instruction->op_id;
if (op1->value->type->id == ZigTypeIdComptimeInt) {
+ // comptime_int has no finite bit width
casted_op2 = op2;
if (op_id == IrBinOpBitShiftLeftLossy) {
op_id = IrBinOpBitShiftLeftExact;
}
- if (casted_op2->value->data.x_bigint.is_negative) {
+ if (!instr_is_comptime(op2)) {
+ ir_add_error(ira, &bin_op_instruction->base.base,
+ buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known"));
+ return ira->codegen->invalid_inst_gen;
+ }
+
+ ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
+ if (op2_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ if (op2_val->data.x_bigint.is_negative) {
Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &casted_op2->value->data.x_bigint, 10);
- ir_add_error(ira, &casted_op2->base, buf_sprintf("shift by negative value %s", buf_ptr(val_buf)));
+ bigint_append_buf(val_buf, &op2_val->data.x_bigint, 10);
+ ir_add_error(ira, &casted_op2->base,
+ buf_sprintf("shift by negative value %s", buf_ptr(val_buf)));
return ira->codegen->invalid_inst_gen;
}
} else {
- assert(op1->value->type->data.integral.bit_count > 0);
+ const unsigned bit_count = op1->value->type->data.integral.bit_count;
ZigType *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
- op1->value->type->data.integral.bit_count - 1);
+ bit_count > 0 ? bit_count - 1 : 0);
casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
if (type_is_invalid(casted_op2->value->type))
return ira->codegen->invalid_inst_gen;
- if (instr_is_comptime(casted_op2)) {
+ // This check is only valid iff op1 has at least one bit
+ if (bit_count > 0 && instr_is_comptime(casted_op2)) {
ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
if (op2_val == nullptr)
return ira->codegen->invalid_inst_gen;
BigInt bit_count_value = {0};
- bigint_init_unsigned(&bit_count_value, op1->value->type->data.integral.bit_count);
+ bigint_init_unsigned(&bit_count_value, bit_count);
if (bigint_cmp(&op2_val->data.x_bigint, &bit_count_value) != CmpLT) {
ErrorMsg* msg = ir_add_error(ira,
@@ -16670,14 +16683,23 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
buf_sprintf("RHS of shift is too large for LHS type"));
add_error_note(ira->codegen, msg, op1->base.source_node,
buf_sprintf("type %s has only %u bits",
- buf_ptr(&op1->value->type->name),
- op1->value->type->data.integral.bit_count));
+ buf_ptr(&op1->value->type->name), bit_count));
return ira->codegen->invalid_inst_gen;
}
}
}
+ // Fast path for zero RHS
+ if (instr_is_comptime(casted_op2)) {
+ ZigValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
+ if (op2_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ if (bigint_cmp_zero(&op2_val->data.x_bigint) == CmpEQ)
+ return ir_analyze_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1);
+ }
+
if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) {
ZigValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
if (op1_val == nullptr)
@@ -16688,12 +16710,6 @@ static IrInstGen *ir_analyze_bit_shift(IrAnalyze *ira, IrInstSrcBinOp *bin_op_in
return ira->codegen->invalid_inst_gen;
return ir_analyze_math_op(ira, &bin_op_instruction->base.base, op1->value->type, op1_val, op_id, op2_val);
- } else if (op1->value->type->id == ZigTypeIdComptimeInt) {
- ir_add_error(ira, &bin_op_instruction->base.base,
- buf_sprintf("LHS of shift must be an integer type, or RHS must be compile-time known"));
- return ira->codegen->invalid_inst_gen;
- } else if (instr_is_comptime(casted_op2) && bigint_cmp_zero(&casted_op2->value->data.x_bigint) == CmpEQ) {
- return ir_build_cast(ira, &bin_op_instruction->base.base, op1->value->type, op1, CastOpNoop);
}
return ir_build_bin_op_gen(ira, &bin_op_instruction->base.base, op1->value->type,
diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig
index e657b5472..fb70fb7e4 100644
--- a/test/stage1/behavior/math.zig
+++ b/test/stage1/behavior/math.zig
@@ -453,6 +453,25 @@ fn testShrExact(x: u8) void {
expect(shifted == 0b00101101);
}
+test "shift left/right on u0 operand" {
+ const S = struct {
+ fn doTheTest() void {
+ var x: u0 = 0;
+ var y: u0 = 0;
+ expectEqual(@as(u0, 0), x << 0);
+ expectEqual(@as(u0, 0), x >> 0);
+ expectEqual(@as(u0, 0), x << y);
+ expectEqual(@as(u0, 0), x >> y);
+ expectEqual(@as(u0, 0), @shlExact(x, 0));
+ expectEqual(@as(u0, 0), @shrExact(x, 0));
+ expectEqual(@as(u0, 0), @shlExact(x, y));
+ expectEqual(@as(u0, 0), @shrExact(x, y));
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
test "comptime_int addition" {
comptime {
expect(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
From 83f6f730cdd5bb9c2a12b30c0aac33d858a1eaa8 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Tue, 10 Mar 2020 15:22:29 -0400
Subject: [PATCH 042/111] std: simplify format enum-literals
---
lib/std/fmt.zig | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index deae0a717..a7525ba79 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -492,10 +492,7 @@ pub fn formatType(
},
.Type => return output(context, @typeName(T)),
.EnumLiteral => {
- const name = @tagName(value);
- var buffer: [name.len + 1]u8 = undefined;
- buffer[0] = '.';
- std.mem.copy(u8, buffer[1..], name);
+ const buffer = [_]u8{'.'} ++ @tagName(value);
return formatType(buffer, fmt, options, context, Errors, output, max_depth);
},
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
From 18f1fef1426cb0405c733890b2e1d8d48627e4fe Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 18:44:30 -0400
Subject: [PATCH 043/111] update standard library to new I/O streams API
---
lib/std/atomic/queue.zig | 33 +-
lib/std/buffer.zig | 12 +
lib/std/debug/leb128.zig | 24 +-
lib/std/heap.zig | 1 +
lib/std/heap/logging_allocator.zig | 106 ++--
lib/std/io.zig | 762 +----------------------------
lib/std/io/bit_in_stream.zig | 237 +++++++++
lib/std/io/bit_out_stream.zig | 197 ++++++++
lib/std/io/buffered_in_stream.zig | 4 +-
lib/std/io/c_out_stream.zig | 44 ++
lib/std/io/counting_out_stream.zig | 25 +-
lib/std/io/fixed_buffer_stream.zig | 56 ++-
lib/std/io/in_stream.zig | 3 +-
lib/std/io/peek_stream.zig | 112 +++++
lib/std/io/serialization.zig | 606 +++++++++++++++++++++++
lib/std/io/test.zig | 534 +-------------------
lib/std/json.zig | 5 +-
lib/std/json/write_stream.zig | 13 +-
lib/std/net.zig | 4 +-
lib/std/os/test.zig | 11 +-
lib/std/zig/parser_test.zig | 11 +-
lib/std/zig/render.zig | 2 +-
22 files changed, 1417 insertions(+), 1385 deletions(-)
create mode 100644 lib/std/io/bit_in_stream.zig
create mode 100644 lib/std/io/bit_out_stream.zig
create mode 100644 lib/std/io/c_out_stream.zig
create mode 100644 lib/std/io/peek_stream.zig
create mode 100644 lib/std/io/serialization.zig
diff --git a/lib/std/atomic/queue.zig b/lib/std/atomic/queue.zig
index 1969587f3..1a0f39587 100644
--- a/lib/std/atomic/queue.zig
+++ b/lib/std/atomic/queue.zig
@@ -104,21 +104,17 @@ pub fn Queue(comptime T: type) type {
}
pub fn dump(self: *Self) void {
- var stderr_file = std.io.getStdErr() catch return;
- const stderr = &stderr_file.outStream().stream;
- const Error = @typeInfo(@TypeOf(stderr)).Pointer.child.Error;
-
- self.dumpToStream(Error, stderr) catch return;
+ self.dumpToStream(std.io.getStdErr().outStream()) catch return;
}
- pub fn dumpToStream(self: *Self, comptime Error: type, stream: *std.io.OutStream(Error)) Error!void {
+ pub fn dumpToStream(self: *Self, stream: var) !void {
const S = struct {
fn dumpRecursive(
- s: *std.io.OutStream(Error),
+ s: var,
optional_node: ?*Node,
indent: usize,
comptime depth: comptime_int,
- ) Error!void {
+ ) !void {
try s.writeByteNTimes(' ', indent);
if (optional_node) |node| {
try s.print("0x{x}={}\n", .{ @ptrToInt(node), node.data });
@@ -326,17 +322,16 @@ test "std.atomic.Queue single-threaded" {
test "std.atomic.Queue dump" {
const mem = std.mem;
- const SliceOutStream = std.io.SliceOutStream;
var buffer: [1024]u8 = undefined;
var expected_buffer: [1024]u8 = undefined;
- var sos = SliceOutStream.init(buffer[0..]);
+ var fbs = std.io.fixedBufferStream(&buffer);
var queue = Queue(i32).init();
// Test empty stream
- sos.reset();
- try queue.dumpToStream(SliceOutStream.Error, &sos.stream);
- expect(mem.eql(u8, buffer[0..sos.pos],
+ fbs.reset();
+ try queue.dumpToStream(fbs.outStream());
+ expect(mem.eql(u8, buffer[0..fbs.pos],
\\head: (null)
\\tail: (null)
\\
@@ -350,8 +345,8 @@ test "std.atomic.Queue dump" {
};
queue.put(&node_0);
- sos.reset();
- try queue.dumpToStream(SliceOutStream.Error, &sos.stream);
+ fbs.reset();
+ try queue.dumpToStream(fbs.outStream());
var expected = try std.fmt.bufPrint(expected_buffer[0..],
\\head: 0x{x}=1
@@ -360,7 +355,7 @@ test "std.atomic.Queue dump" {
\\ (null)
\\
, .{ @ptrToInt(queue.head), @ptrToInt(queue.tail) });
- expect(mem.eql(u8, buffer[0..sos.pos], expected));
+ expect(mem.eql(u8, buffer[0..fbs.pos], expected));
// Test a stream with two elements
var node_1 = Queue(i32).Node{
@@ -370,8 +365,8 @@ test "std.atomic.Queue dump" {
};
queue.put(&node_1);
- sos.reset();
- try queue.dumpToStream(SliceOutStream.Error, &sos.stream);
+ fbs.reset();
+ try queue.dumpToStream(fbs.outStream());
expected = try std.fmt.bufPrint(expected_buffer[0..],
\\head: 0x{x}=1
@@ -381,5 +376,5 @@ test "std.atomic.Queue dump" {
\\ (null)
\\
, .{ @ptrToInt(queue.head), @ptrToInt(queue.head.?.next), @ptrToInt(queue.tail) });
- expect(mem.eql(u8, buffer[0..sos.pos], expected));
+ expect(mem.eql(u8, buffer[0..fbs.pos], expected));
}
diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig
index a33670b6d..28ce2a561 100644
--- a/lib/std/buffer.zig
+++ b/lib/std/buffer.zig
@@ -219,3 +219,15 @@ test "Buffer.print" {
try buf.print("Hello {} the {}", .{ 2, "world" });
testing.expect(buf.eql("Hello 2 the world"));
}
+
+test "Buffer.outStream" {
+ var buffer = try Buffer.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.toSlice(), "x: 42\ny: 1234\n"));
+}
diff --git a/lib/std/debug/leb128.zig b/lib/std/debug/leb128.zig
index 1d81b9390..e2157335b 100644
--- a/lib/std/debug/leb128.zig
+++ b/lib/std/debug/leb128.zig
@@ -121,18 +121,18 @@ pub fn readILEB128Mem(comptime T: type, ptr: *[*]const u8) !T {
}
fn test_read_stream_ileb128(comptime T: type, encoded: []const u8) !T {
- var in_stream = std.io.SliceInStream.init(encoded);
- return try readILEB128(T, &in_stream.stream);
+ var in_stream = std.io.fixedBufferStream(encoded);
+ return try readILEB128(T, in_stream.inStream());
}
fn test_read_stream_uleb128(comptime T: type, encoded: []const u8) !T {
- var in_stream = std.io.SliceInStream.init(encoded);
- return try readULEB128(T, &in_stream.stream);
+ var in_stream = std.io.fixedBufferStream(encoded);
+ return try readULEB128(T, in_stream.inStream());
}
fn test_read_ileb128(comptime T: type, encoded: []const u8) !T {
- var in_stream = std.io.SliceInStream.init(encoded);
- const v1 = readILEB128(T, &in_stream.stream);
+ var in_stream = std.io.fixedBufferStream(encoded);
+ const v1 = readILEB128(T, in_stream.inStream());
var in_ptr = encoded.ptr;
const v2 = readILEB128Mem(T, &in_ptr);
testing.expectEqual(v1, v2);
@@ -140,8 +140,8 @@ fn test_read_ileb128(comptime T: type, encoded: []const u8) !T {
}
fn test_read_uleb128(comptime T: type, encoded: []const u8) !T {
- var in_stream = std.io.SliceInStream.init(encoded);
- const v1 = readULEB128(T, &in_stream.stream);
+ var in_stream = std.io.fixedBufferStream(encoded);
+ const v1 = readULEB128(T, in_stream.inStream());
var in_ptr = encoded.ptr;
const v2 = readULEB128Mem(T, &in_ptr);
testing.expectEqual(v1, v2);
@@ -149,22 +149,22 @@ fn test_read_uleb128(comptime T: type, encoded: []const u8) !T {
}
fn test_read_ileb128_seq(comptime T: type, comptime N: usize, encoded: []const u8) void {
- var in_stream = std.io.SliceInStream.init(encoded);
+ var in_stream = std.io.fixedBufferStream(encoded);
var in_ptr = encoded.ptr;
var i: usize = 0;
while (i < N) : (i += 1) {
- const v1 = readILEB128(T, &in_stream.stream);
+ const v1 = readILEB128(T, in_stream.inStream());
const v2 = readILEB128Mem(T, &in_ptr);
testing.expectEqual(v1, v2);
}
}
fn test_read_uleb128_seq(comptime T: type, comptime N: usize, encoded: []const u8) void {
- var in_stream = std.io.SliceInStream.init(encoded);
+ var in_stream = std.io.fixedBufferStream(encoded);
var in_ptr = encoded.ptr;
var i: usize = 0;
while (i < N) : (i += 1) {
- const v1 = readULEB128(T, &in_stream.stream);
+ const v1 = readULEB128(T, in_stream.inStream());
const v2 = readULEB128Mem(T, &in_ptr);
testing.expectEqual(v1, v2);
}
diff --git a/lib/std/heap.zig b/lib/std/heap.zig
index 65809e97b..8c79249d4 100644
--- a/lib/std/heap.zig
+++ b/lib/std/heap.zig
@@ -10,6 +10,7 @@ const c = std.c;
const maxInt = std.math.maxInt;
pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator;
+pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator;
const Allocator = mem.Allocator;
diff --git a/lib/std/heap/logging_allocator.zig b/lib/std/heap/logging_allocator.zig
index 7dce7bc20..0d15986a7 100644
--- a/lib/std/heap/logging_allocator.zig
+++ b/lib/std/heap/logging_allocator.zig
@@ -1,63 +1,69 @@
const std = @import("../std.zig");
const Allocator = std.mem.Allocator;
-const AnyErrorOutStream = std.io.OutStream(anyerror);
-
/// This allocator is used in front of another allocator and logs to the provided stream
/// on every call to the allocator. Stream errors are ignored.
/// If https://github.com/ziglang/zig/issues/2586 is implemented, this API can be improved.
-pub const LoggingAllocator = struct {
- allocator: Allocator,
+pub fn LoggingAllocator(comptime OutStreamType: type) type {
+ return struct {
+ allocator: Allocator,
+ parent_allocator: *Allocator,
+ out_stream: OutStreamType,
+
+ const Self = @This();
+
+ pub fn init(parent_allocator: *Allocator, out_stream: OutStreamType) Self {
+ return Self{
+ .allocator = Allocator{
+ .reallocFn = realloc,
+ .shrinkFn = shrink,
+ },
+ .parent_allocator = parent_allocator,
+ .out_stream = out_stream,
+ };
+ }
+
+ fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
+ const self = @fieldParentPtr(Self, "allocator", allocator);
+ if (old_mem.len == 0) {
+ self.out_stream.print("allocation of {} ", .{new_size}) catch {};
+ } else {
+ self.out_stream.print("resize from {} to {} ", .{ old_mem.len, new_size }) catch {};
+ }
+ const result = self.parent_allocator.reallocFn(self.parent_allocator, old_mem, old_align, new_size, new_align);
+ if (result) |buff| {
+ self.out_stream.print("success!\n", .{}) catch {};
+ } else |err| {
+ self.out_stream.print("failure!\n", .{}) catch {};
+ }
+ return result;
+ }
+
+ fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
+ const self = @fieldParentPtr(Self, "allocator", allocator);
+ const result = self.parent_allocator.shrinkFn(self.parent_allocator, old_mem, old_align, new_size, new_align);
+ if (new_size == 0) {
+ self.out_stream.print("free of {} bytes success!\n", .{old_mem.len}) catch {};
+ } else {
+ self.out_stream.print("shrink from {} bytes to {} bytes success!\n", .{ old_mem.len, new_size }) catch {};
+ }
+ return result;
+ }
+ };
+}
+
+pub fn loggingAllocator(
parent_allocator: *Allocator,
- out_stream: *AnyErrorOutStream,
-
- const Self = @This();
-
- pub fn init(parent_allocator: *Allocator, out_stream: *AnyErrorOutStream) Self {
- return Self{
- .allocator = Allocator{
- .reallocFn = realloc,
- .shrinkFn = shrink,
- },
- .parent_allocator = parent_allocator,
- .out_stream = out_stream,
- };
- }
-
- fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
- const self = @fieldParentPtr(Self, "allocator", allocator);
- if (old_mem.len == 0) {
- self.out_stream.print("allocation of {} ", .{new_size}) catch {};
- } else {
- self.out_stream.print("resize from {} to {} ", .{ old_mem.len, new_size }) catch {};
- }
- const result = self.parent_allocator.reallocFn(self.parent_allocator, old_mem, old_align, new_size, new_align);
- if (result) |buff| {
- self.out_stream.print("success!\n", .{}) catch {};
- } else |err| {
- self.out_stream.print("failure!\n", .{}) catch {};
- }
- return result;
- }
-
- fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
- const self = @fieldParentPtr(Self, "allocator", allocator);
- const result = self.parent_allocator.shrinkFn(self.parent_allocator, old_mem, old_align, new_size, new_align);
- if (new_size == 0) {
- self.out_stream.print("free of {} bytes success!\n", .{old_mem.len}) catch {};
- } else {
- self.out_stream.print("shrink from {} bytes to {} bytes success!\n", .{ old_mem.len, new_size }) catch {};
- }
- return result;
- }
-};
+ out_stream: var,
+) LoggingAllocator(@TypeOf(out_stream)) {
+ return LoggingAllocator(@TypeOf(out_stream)).init(parent_allocator, out_stream);
+}
test "LoggingAllocator" {
var buf: [255]u8 = undefined;
- var slice_stream = std.io.SliceOutStream.init(buf[0..]);
- const stream = &slice_stream.stream;
+ var fbs = std.io.fixedBufferStream(&buf);
- const allocator = &LoggingAllocator.init(std.testing.allocator, @ptrCast(*AnyErrorOutStream, stream)).allocator;
+ const allocator = &loggingAllocator(std.testing.allocator, fbs.outStream()).allocator;
const ptr = try allocator.alloc(u8, 10);
allocator.free(ptr);
@@ -66,5 +72,5 @@ test "LoggingAllocator" {
\\allocation of 10 success!
\\free of 10 bytes success!
\\
- , slice_stream.getWritten());
+ , fbs.getWritten());
}
diff --git a/lib/std/io.zig b/lib/std/io.zig
index 128346127..22af5c06b 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -4,17 +4,13 @@ const root = @import("root");
const c = std.c;
const math = std.math;
-const debug = std.debug;
-const assert = debug.assert;
+const assert = std.debug.assert;
const os = std.os;
const fs = std.fs;
const mem = std.mem;
const meta = std.meta;
const trait = meta.trait;
-const Buffer = std.Buffer;
-const fmt = std.fmt;
const File = std.fs.File;
-const testing = std.testing;
pub const Mode = enum {
/// I/O operates normally, waiting for the operating system syscalls to complete.
@@ -92,10 +88,9 @@ pub fn getStdIn() File {
};
}
-pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
pub const InStream = @import("io/in_stream.zig").InStream;
pub const OutStream = @import("io/out_stream.zig").OutStream;
-pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile;
+pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
pub const BufferedOutStream = @import("io/buffered_out_stream.zig").BufferedOutStream;
pub const bufferedOutStream = @import("io/buffered_out_stream.zig").bufferedOutStream;
@@ -103,36 +98,33 @@ pub const bufferedOutStream = @import("io/buffered_out_stream.zig").bufferedOutS
pub const BufferedInStream = @import("io/buffered_in_stream.zig").BufferedInStream;
pub const bufferedInStream = @import("io/buffered_in_stream.zig").bufferedInStream;
+pub const PeekStream = @import("io/peek_stream.zig").PeekStream;
+pub const peekStream = @import("io/peek_stream.zig").peekStream;
+
pub const FixedBufferStream = @import("io/fixed_buffer_stream.zig").FixedBufferStream;
pub const fixedBufferStream = @import("io/fixed_buffer_stream.zig").fixedBufferStream;
+pub const COutStream = @import("io/c_out_stream.zig").COutStream;
+pub const cOutStream = @import("io/c_out_stream.zig").cOutStream;
+
pub const CountingOutStream = @import("io/counting_out_stream.zig").CountingOutStream;
+pub const countingOutStream = @import("io/counting_out_stream.zig").countingOutStream;
-pub fn cOutStream(c_file: *std.c.FILE) COutStream {
- return .{ .context = c_file };
-}
+pub const BitInStream = @import("io/bit_in_stream.zig").BitInStream;
+pub const bitInStream = @import("io/bit_in_stream.zig").bitInStream;
-pub const COutStream = OutStream(*std.c.FILE, std.fs.File.WriteError, cOutStreamWrite);
+pub const BitOutStream = @import("io/bit_out_stream.zig").BitOutStream;
+pub const bitOutStream = @import("io/bit_out_stream.zig").bitOutStream;
-pub fn cOutStreamWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
- const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
- if (amt_written >= 0) return amt_written;
- switch (std.c._errno().*) {
- 0 => unreachable,
- os.EINVAL => unreachable,
- os.EFAULT => unreachable,
- os.EAGAIN => unreachable, // this is a blocking API
- os.EBADF => unreachable, // always a race condition
- os.EDESTADDRREQ => unreachable, // connect was never called
- os.EDQUOT => return error.DiskQuota,
- os.EFBIG => return error.FileTooBig,
- os.EIO => return error.InputOutput,
- os.ENOSPC => return error.NoSpaceLeft,
- os.EPERM => return error.AccessDenied,
- os.EPIPE => return error.BrokenPipe,
- else => |err| return os.unexpectedErrno(@intCast(usize, err)),
- }
-}
+pub const Packing = @import("io/serialization.zig").Packing;
+
+pub const Serializer = @import("io/serialization.zig").Serializer;
+pub const serializer = @import("io/serialization.zig").serializer;
+
+pub const Deserializer = @import("io/serialization.zig").Deserializer;
+pub const deserializer = @import("io/serialization.zig").deserializer;
+
+pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile;
/// Deprecated; use `std.fs.Dir.writeFile`.
pub fn writeFile(path: []const u8, data: []const u8) !void {
@@ -144,249 +136,6 @@ pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 {
return fs.cwd().readFileAlloc(allocator, path, math.maxInt(usize));
}
-/// Creates a stream which supports 'un-reading' data, so that it can be read again.
-/// This makes look-ahead style parsing much easier.
-pub fn PeekStream(comptime buffer_type: std.fifo.LinearFifoBufferType, comptime InStreamError: type) type {
- return struct {
- const Self = @This();
- pub const Error = InStreamError;
- pub const Stream = InStream(Error);
-
- stream: Stream,
- base: *Stream,
-
- const FifoType = std.fifo.LinearFifo(u8, buffer_type);
- fifo: FifoType,
-
- pub usingnamespace switch (buffer_type) {
- .Static => struct {
- pub fn init(base: *Stream) Self {
- return .{
- .base = base,
- .fifo = FifoType.init(),
- .stream = Stream{ .readFn = readFn },
- };
- }
- },
- .Slice => struct {
- pub fn init(base: *Stream, buf: []u8) Self {
- return .{
- .base = base,
- .fifo = FifoType.init(buf),
- .stream = Stream{ .readFn = readFn },
- };
- }
- },
- .Dynamic => struct {
- pub fn init(base: *Stream, allocator: *mem.Allocator) Self {
- return .{
- .base = base,
- .fifo = FifoType.init(allocator),
- .stream = Stream{ .readFn = readFn },
- };
- }
- },
- };
-
- pub fn putBackByte(self: *Self, byte: u8) !void {
- try self.putBack(&[_]u8{byte});
- }
-
- pub fn putBack(self: *Self, bytes: []const u8) !void {
- try self.fifo.unget(bytes);
- }
-
- fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
- const self = @fieldParentPtr(Self, "stream", in_stream);
-
- // copy over anything putBack()'d
- var dest_index = self.fifo.read(dest);
- if (dest_index == dest.len) return dest_index;
-
- // ask the backing stream for more
- dest_index += try self.base.read(dest[dest_index..]);
- return dest_index;
- }
- };
-}
-
-pub const SliceInStream = struct {
- const Self = @This();
- pub const Error = error{};
- pub const Stream = InStream(Error);
-
- stream: Stream,
-
- pos: usize,
- slice: []const u8,
-
- pub fn init(slice: []const u8) Self {
- return Self{
- .slice = slice,
- .pos = 0,
- .stream = Stream{ .readFn = readFn },
- };
- }
-
- fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
- const self = @fieldParentPtr(Self, "stream", in_stream);
- const size = math.min(dest.len, self.slice.len - self.pos);
- const end = self.pos + size;
-
- mem.copy(u8, dest[0..size], self.slice[self.pos..end]);
- self.pos = end;
-
- return size;
- }
-};
-
-/// Creates a stream which allows for reading bit fields from another stream
-pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
- return struct {
- const Self = @This();
-
- in_stream: *Stream,
- bit_buffer: u7,
- bit_count: u3,
- stream: Stream,
-
- pub const Stream = InStream(Error);
- const u8_bit_count = comptime meta.bitCount(u8);
- const u7_bit_count = comptime meta.bitCount(u7);
- const u4_bit_count = comptime meta.bitCount(u4);
-
- pub fn init(in_stream: *Stream) Self {
- return Self{
- .in_stream = in_stream,
- .bit_buffer = 0,
- .bit_count = 0,
- .stream = Stream{ .readFn = read },
- };
- }
-
- /// Reads `bits` bits from the stream and returns a specified unsigned int type
- /// containing them in the least significant end, returning an error if the
- /// specified number of bits could not be read.
- pub fn readBitsNoEof(self: *Self, comptime U: type, bits: usize) !U {
- var n: usize = undefined;
- const result = try self.readBits(U, bits, &n);
- if (n < bits) return error.EndOfStream;
- return result;
- }
-
- /// Reads `bits` bits from the stream and returns a specified unsigned int type
- /// containing them in the least significant end. The number of bits successfully
- /// read is placed in `out_bits`, as reaching the end of the stream is not an error.
- pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
- comptime assert(trait.isUnsignedInt(U));
-
- //by extending the buffer to a minimum of u8 we can cover a number of edge cases
- // related to shifting and casting.
- const u_bit_count = comptime meta.bitCount(U);
- const buf_bit_count = bc: {
- assert(u_bit_count >= bits);
- break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
- };
- const Buf = std.meta.IntType(false, buf_bit_count);
- const BufShift = math.Log2Int(Buf);
-
- out_bits.* = @as(usize, 0);
- if (U == u0 or bits == 0) return 0;
- var out_buffer = @as(Buf, 0);
-
- if (self.bit_count > 0) {
- const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;
- const shift = u7_bit_count - n;
- switch (endian) {
- .Big => {
- out_buffer = @as(Buf, self.bit_buffer >> shift);
- self.bit_buffer <<= n;
- },
- .Little => {
- const value = (self.bit_buffer << shift) >> shift;
- out_buffer = @as(Buf, value);
- self.bit_buffer >>= n;
- },
- }
- self.bit_count -= n;
- out_bits.* = n;
- }
- //at this point we know bit_buffer is empty
-
- //copy bytes until we have enough bits, then leave the rest in bit_buffer
- while (out_bits.* < bits) {
- const n = bits - out_bits.*;
- const next_byte = self.in_stream.readByte() catch |err| {
- if (err == error.EndOfStream) {
- return @intCast(U, out_buffer);
- }
- //@BUG: See #1810. Not sure if the bug is that I have to do this for some
- // streams, or that I don't for streams with emtpy errorsets.
- return @errSetCast(Error, err);
- };
-
- switch (endian) {
- .Big => {
- if (n >= u8_bit_count) {
- out_buffer <<= @intCast(u3, u8_bit_count - 1);
- out_buffer <<= 1;
- out_buffer |= @as(Buf, next_byte);
- out_bits.* += u8_bit_count;
- continue;
- }
-
- const shift = @intCast(u3, u8_bit_count - n);
- out_buffer <<= @intCast(BufShift, n);
- out_buffer |= @as(Buf, next_byte >> shift);
- out_bits.* += n;
- self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));
- self.bit_count = shift;
- },
- .Little => {
- if (n >= u8_bit_count) {
- out_buffer |= @as(Buf, next_byte) << @intCast(BufShift, out_bits.*);
- out_bits.* += u8_bit_count;
- continue;
- }
-
- const shift = @intCast(u3, u8_bit_count - n);
- const value = (next_byte << shift) >> shift;
- out_buffer |= @as(Buf, value) << @intCast(BufShift, out_bits.*);
- out_bits.* += n;
- self.bit_buffer = @truncate(u7, next_byte >> @intCast(u3, n));
- self.bit_count = shift;
- },
- }
- }
-
- return @intCast(U, out_buffer);
- }
-
- pub fn alignToByte(self: *Self) void {
- self.bit_buffer = 0;
- self.bit_count = 0;
- }
-
- pub fn read(self_stream: *Stream, buffer: []u8) Error!usize {
- var self = @fieldParentPtr(Self, "stream", self_stream);
-
- var out_bits: usize = undefined;
- var out_bits_total = @as(usize, 0);
- //@NOTE: I'm not sure this is a good idea, maybe alignToByte should be forced
- if (self.bit_count > 0) {
- for (buffer) |*b, i| {
- b.* = try self.readBits(u8, u8_bit_count, &out_bits);
- out_bits_total += out_bits;
- }
- const incomplete_byte = @boolToInt(out_bits_total % u8_bit_count > 0);
- return (out_bits_total / u8_bit_count) + incomplete_byte;
- }
-
- return self.in_stream.read(buffer);
- }
- };
-}
-
/// An OutStream that doesn't write to anything.
pub const null_out_stream = @as(NullOutStream, .{ .context = {} });
@@ -396,472 +145,9 @@ fn dummyWrite(context: void, data: []const u8) error{}!usize {
}
test "null_out_stream" {
- null_out_stream.writeAll("yay" ** 1000) catch |err| switch (err) {};
-}
-
-/// Creates a stream which allows for writing bit fields to another stream
-pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
- return struct {
- const Self = @This();
-
- out_stream: *Stream,
- bit_buffer: u8,
- bit_count: u4,
- stream: Stream,
-
- pub const Stream = OutStream(Error);
- const u8_bit_count = comptime meta.bitCount(u8);
- const u4_bit_count = comptime meta.bitCount(u4);
-
- pub fn init(out_stream: *Stream) Self {
- return Self{
- .out_stream = out_stream,
- .bit_buffer = 0,
- .bit_count = 0,
- .stream = Stream{ .writeFn = write },
- };
- }
-
- /// Write the specified number of bits to the stream from the least significant bits of
- /// the specified unsigned int value. Bits will only be written to the stream when there
- /// are enough to fill a byte.
- pub fn writeBits(self: *Self, value: var, bits: usize) Error!void {
- if (bits == 0) return;
-
- const U = @TypeOf(value);
- comptime assert(trait.isUnsignedInt(U));
-
- //by extending the buffer to a minimum of u8 we can cover a number of edge cases
- // related to shifting and casting.
- const u_bit_count = comptime meta.bitCount(U);
- const buf_bit_count = bc: {
- assert(u_bit_count >= bits);
- break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
- };
- const Buf = std.meta.IntType(false, buf_bit_count);
- const BufShift = math.Log2Int(Buf);
-
- const buf_value = @intCast(Buf, value);
-
- const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);
- var in_buffer = switch (endian) {
- .Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
- .Little => buf_value,
- };
- var in_bits = bits;
-
- if (self.bit_count > 0) {
- const bits_remaining = u8_bit_count - self.bit_count;
- const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);
- switch (endian) {
- .Big => {
- const shift = @intCast(BufShift, high_byte_shift + self.bit_count);
- const v = @intCast(u8, in_buffer >> shift);
- self.bit_buffer |= v;
- in_buffer <<= n;
- },
- .Little => {
- const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);
- self.bit_buffer |= v;
- in_buffer >>= n;
- },
- }
- self.bit_count += n;
- in_bits -= n;
-
- //if we didn't fill the buffer, it's because bits < bits_remaining;
- if (self.bit_count != u8_bit_count) return;
- try self.out_stream.writeByte(self.bit_buffer);
- self.bit_buffer = 0;
- self.bit_count = 0;
- }
- //at this point we know bit_buffer is empty
-
- //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer
- while (in_bits >= u8_bit_count) {
- switch (endian) {
- .Big => {
- const v = @intCast(u8, in_buffer >> high_byte_shift);
- try self.out_stream.writeByte(v);
- in_buffer <<= @intCast(u3, u8_bit_count - 1);
- in_buffer <<= 1;
- },
- .Little => {
- const v = @truncate(u8, in_buffer);
- try self.out_stream.writeByte(v);
- in_buffer >>= @intCast(u3, u8_bit_count - 1);
- in_buffer >>= 1;
- },
- }
- in_bits -= u8_bit_count;
- }
-
- if (in_bits > 0) {
- self.bit_count = @intCast(u4, in_bits);
- self.bit_buffer = switch (endian) {
- .Big => @truncate(u8, in_buffer >> high_byte_shift),
- .Little => @truncate(u8, in_buffer),
- };
- }
- }
-
- /// Flush any remaining bits to the stream.
- pub fn flushBits(self: *Self) Error!void {
- if (self.bit_count == 0) return;
- try self.out_stream.writeByte(self.bit_buffer);
- self.bit_buffer = 0;
- self.bit_count = 0;
- }
-
- pub fn write(self_stream: *Stream, buffer: []const u8) Error!usize {
- var self = @fieldParentPtr(Self, "stream", self_stream);
-
- // TODO: I'm not sure this is a good idea, maybe flushBits should be forced
- if (self.bit_count > 0) {
- for (buffer) |b, i|
- try self.writeBits(b, u8_bit_count);
- return buffer.len;
- }
-
- return self.out_stream.write(buffer);
- }
- };
-}
-
-pub const Packing = enum {
- /// Pack data to byte alignment
- Byte,
-
- /// Pack data to bit alignment
- Bit,
-};
-
-/// Creates a deserializer that deserializes types from any stream.
-/// If `is_packed` is true, the data stream is treated as bit-packed,
-/// otherwise data is expected to be packed to the smallest byte.
-/// Types may implement a custom deserialization routine with a
-/// function named `deserialize` in the form of:
-/// pub fn deserialize(self: *Self, deserializer: var) !void
-/// which will be called when the deserializer is used to deserialize
-/// that type. It will pass a pointer to the type instance to deserialize
-/// into and a pointer to the deserializer struct.
-pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime Error: type) type {
- return struct {
- const Self = @This();
-
- in_stream: if (packing == .Bit) BitInStream(endian, Stream.Error) else *Stream,
-
- pub const Stream = InStream(Error);
-
- pub fn init(in_stream: *Stream) Self {
- return Self{
- .in_stream = switch (packing) {
- .Bit => BitInStream(endian, Stream.Error).init(in_stream),
- .Byte => in_stream,
- },
- };
- }
-
- pub fn alignToByte(self: *Self) void {
- if (packing == .Byte) return;
- self.in_stream.alignToByte();
- }
-
- //@BUG: inferred error issue. See: #1386
- fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T {
- comptime assert(trait.is(.Int)(T) or trait.is(.Float)(T));
-
- const u8_bit_count = 8;
- const t_bit_count = comptime meta.bitCount(T);
-
- const U = std.meta.IntType(false, t_bit_count);
- const Log2U = math.Log2Int(U);
- const int_size = (U.bit_count + 7) / 8;
-
- if (packing == .Bit) {
- const result = try self.in_stream.readBitsNoEof(U, t_bit_count);
- return @bitCast(T, result);
- }
-
- var buffer: [int_size]u8 = undefined;
- const read_size = try self.in_stream.read(buffer[0..]);
- if (read_size < int_size) return error.EndOfStream;
-
- if (int_size == 1) {
- if (t_bit_count == 8) return @bitCast(T, buffer[0]);
- const PossiblySignedByte = std.meta.IntType(T.is_signed, 8);
- return @truncate(T, @bitCast(PossiblySignedByte, buffer[0]));
- }
-
- var result = @as(U, 0);
- for (buffer) |byte, i| {
- switch (endian) {
- .Big => {
- result = (result << u8_bit_count) | byte;
- },
- .Little => {
- result |= @as(U, byte) << @intCast(Log2U, u8_bit_count * i);
- },
- }
- }
-
- return @bitCast(T, result);
- }
-
- /// Deserializes and returns data of the specified type from the stream
- pub fn deserialize(self: *Self, comptime T: type) !T {
- var value: T = undefined;
- try self.deserializeInto(&value);
- return value;
- }
-
- /// Deserializes data into the type pointed to by `ptr`
- pub fn deserializeInto(self: *Self, ptr: var) !void {
- const T = @TypeOf(ptr);
- comptime assert(trait.is(.Pointer)(T));
-
- if (comptime trait.isSlice(T) or comptime trait.isPtrTo(.Array)(T)) {
- for (ptr) |*v|
- try self.deserializeInto(v);
- return;
- }
-
- comptime assert(trait.isSingleItemPtr(T));
-
- const C = comptime meta.Child(T);
- const child_type_id = @typeInfo(C);
-
- //custom deserializer: fn(self: *Self, deserializer: var) !void
- if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self);
-
- if (comptime trait.isPacked(C) and packing != .Bit) {
- var packed_deserializer = Deserializer(endian, .Bit, Error).init(self.in_stream);
- return packed_deserializer.deserializeInto(ptr);
- }
-
- switch (child_type_id) {
- .Void => return,
- .Bool => ptr.* = (try self.deserializeInt(u1)) > 0,
- .Float, .Int => ptr.* = try self.deserializeInt(C),
- .Struct => {
- const info = @typeInfo(C).Struct;
-
- inline for (info.fields) |*field_info| {
- const name = field_info.name;
- const FieldType = field_info.field_type;
-
- if (FieldType == void or FieldType == u0) continue;
-
- //it doesn't make any sense to read pointers
- if (comptime trait.is(.Pointer)(FieldType)) {
- @compileError("Will not " ++ "read field " ++ name ++ " of struct " ++
- @typeName(C) ++ " because it " ++ "is of pointer-type " ++
- @typeName(FieldType) ++ ".");
- }
-
- try self.deserializeInto(&@field(ptr, name));
- }
- },
- .Union => {
- const info = @typeInfo(C).Union;
- if (info.tag_type) |TagType| {
- //we avoid duplicate iteration over the enum tags
- // by getting the int directly and casting it without
- // safety. If it is bad, it will be caught anyway.
- const TagInt = @TagType(TagType);
- const tag = try self.deserializeInt(TagInt);
-
- inline for (info.fields) |field_info| {
- if (field_info.enum_field.?.value == tag) {
- const name = field_info.name;
- const FieldType = field_info.field_type;
- ptr.* = @unionInit(C, name, undefined);
- try self.deserializeInto(&@field(ptr, name));
- return;
- }
- }
- //This is reachable if the enum data is bad
- return error.InvalidEnumTag;
- }
- @compileError("Cannot meaningfully deserialize " ++ @typeName(C) ++
- " because it is an untagged union. Use a custom deserialize().");
- },
- .Optional => {
- const OC = comptime meta.Child(C);
- const exists = (try self.deserializeInt(u1)) > 0;
- if (!exists) {
- ptr.* = null;
- return;
- }
-
- ptr.* = @as(OC, undefined); //make it non-null so the following .? is guaranteed safe
- const val_ptr = &ptr.*.?;
- try self.deserializeInto(val_ptr);
- },
- .Enum => {
- var value = try self.deserializeInt(@TagType(C));
- ptr.* = try meta.intToEnum(C, value);
- },
- else => {
- @compileError("Cannot deserialize " ++ @tagName(child_type_id) ++ " types (unimplemented).");
- },
- }
- }
- };
-}
-
-/// Creates a serializer that serializes types to any stream.
-/// If `is_packed` is true, the data will be bit-packed into the stream.
-/// Note that the you must call `serializer.flush()` when you are done
-/// writing bit-packed data in order ensure any unwritten bits are committed.
-/// If `is_packed` is false, data is packed to the smallest byte. In the case
-/// of packed structs, the struct will written bit-packed and with the specified
-/// endianess, after which data will resume being written at the next byte boundary.
-/// Types may implement a custom serialization routine with a
-/// function named `serialize` in the form of:
-/// pub fn serialize(self: Self, serializer: var) !void
-/// which will be called when the serializer is used to serialize that type. It will
-/// pass a const pointer to the type instance to be serialized and a pointer
-/// to the serializer struct.
-pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime Error: type) type {
- return struct {
- const Self = @This();
-
- out_stream: if (packing == .Bit) BitOutStream(endian, Stream.Error) else *Stream,
-
- pub const Stream = OutStream(Error);
-
- pub fn init(out_stream: *Stream) Self {
- return Self{
- .out_stream = switch (packing) {
- .Bit => BitOutStream(endian, Stream.Error).init(out_stream),
- .Byte => out_stream,
- },
- };
- }
-
- /// Flushes any unwritten bits to the stream
- pub fn flush(self: *Self) Error!void {
- if (packing == .Bit) return self.out_stream.flushBits();
- }
-
- fn serializeInt(self: *Self, value: var) Error!void {
- const T = @TypeOf(value);
- comptime assert(trait.is(.Int)(T) or trait.is(.Float)(T));
-
- const t_bit_count = comptime meta.bitCount(T);
- const u8_bit_count = comptime meta.bitCount(u8);
-
- const U = std.meta.IntType(false, t_bit_count);
- const Log2U = math.Log2Int(U);
- const int_size = (U.bit_count + 7) / 8;
-
- const u_value = @bitCast(U, value);
-
- if (packing == .Bit) return self.out_stream.writeBits(u_value, t_bit_count);
-
- var buffer: [int_size]u8 = undefined;
- if (int_size == 1) buffer[0] = u_value;
-
- for (buffer) |*byte, i| {
- const idx = switch (endian) {
- .Big => int_size - i - 1,
- .Little => i,
- };
- const shift = @intCast(Log2U, idx * u8_bit_count);
- const v = u_value >> shift;
- byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v);
- }
-
- try self.out_stream.write(&buffer);
- }
-
- /// Serializes the passed value into the stream
- pub fn serialize(self: *Self, value: var) Error!void {
- const T = comptime @TypeOf(value);
-
- if (comptime trait.isIndexable(T)) {
- for (value) |v|
- try self.serialize(v);
- return;
- }
-
- //custom serializer: fn(self: Self, serializer: var) !void
- if (comptime trait.hasFn("serialize")(T)) return T.serialize(value, self);
-
- if (comptime trait.isPacked(T) and packing != .Bit) {
- var packed_serializer = Serializer(endian, .Bit, Error).init(self.out_stream);
- try packed_serializer.serialize(value);
- try packed_serializer.flush();
- return;
- }
-
- switch (@typeInfo(T)) {
- .Void => return,
- .Bool => try self.serializeInt(@as(u1, @boolToInt(value))),
- .Float, .Int => try self.serializeInt(value),
- .Struct => {
- const info = @typeInfo(T);
-
- inline for (info.Struct.fields) |*field_info| {
- const name = field_info.name;
- const FieldType = field_info.field_type;
-
- if (FieldType == void or FieldType == u0) continue;
-
- //It doesn't make sense to write pointers
- if (comptime trait.is(.Pointer)(FieldType)) {
- @compileError("Will not " ++ "serialize field " ++ name ++
- " of struct " ++ @typeName(T) ++ " because it " ++
- "is of pointer-type " ++ @typeName(FieldType) ++ ".");
- }
- try self.serialize(@field(value, name));
- }
- },
- .Union => {
- const info = @typeInfo(T).Union;
- if (info.tag_type) |TagType| {
- const active_tag = meta.activeTag(value);
- try self.serialize(active_tag);
- //This inline loop is necessary because active_tag is a runtime
- // value, but @field requires a comptime value. Our alternative
- // is to check each field for a match
- inline for (info.fields) |field_info| {
- if (field_info.enum_field.?.value == @enumToInt(active_tag)) {
- const name = field_info.name;
- const FieldType = field_info.field_type;
- try self.serialize(@field(value, name));
- return;
- }
- }
- unreachable;
- }
- @compileError("Cannot meaningfully serialize " ++ @typeName(T) ++
- " because it is an untagged union. Use a custom serialize().");
- },
- .Optional => {
- if (value == null) {
- try self.serializeInt(@as(u1, @boolToInt(false)));
- return;
- }
- try self.serializeInt(@as(u1, @boolToInt(true)));
-
- const OC = comptime meta.Child(T);
- const val_ptr = &value.?;
- try self.serialize(val_ptr.*);
- },
- .Enum => {
- try self.serializeInt(@enumToInt(value));
- },
- else => @compileError("Cannot serialize " ++ @tagName(@typeInfo(T)) ++ " types (unimplemented)."),
- }
- }
- };
+ null_out_stream.writeAll("yay" ** 10) catch |err| switch (err) {};
}
test "" {
- comptime {
- _ = @import("io/test.zig");
- }
- std.meta.refAllDecls(@This());
+ _ = @import("io/test.zig");
}
diff --git a/lib/std/io/bit_in_stream.zig b/lib/std/io/bit_in_stream.zig
new file mode 100644
index 000000000..876621343
--- /dev/null
+++ b/lib/std/io/bit_in_stream.zig
@@ -0,0 +1,237 @@
+const std = @import("../std.zig");
+const builtin = std.builtin;
+const io = std.io;
+const assert = std.debug.assert;
+const testing = std.testing;
+const trait = std.meta.trait;
+const meta = std.meta;
+const math = std.math;
+
+/// Creates a stream which allows for reading bit fields from another stream
+pub fn BitInStream(endian: builtin.Endian, comptime InStreamType: type) type {
+ return struct {
+ in_stream: InStreamType,
+ bit_buffer: u7,
+ bit_count: u3,
+
+ pub const Error = InStreamType.Error;
+ pub const InStream = io.InStream(*Self, Error, read);
+
+ const Self = @This();
+ const u8_bit_count = comptime meta.bitCount(u8);
+ const u7_bit_count = comptime meta.bitCount(u7);
+ const u4_bit_count = comptime meta.bitCount(u4);
+
+ pub fn init(in_stream: InStreamType) Self {
+ return Self{
+ .in_stream = in_stream,
+ .bit_buffer = 0,
+ .bit_count = 0,
+ };
+ }
+
+ /// Reads `bits` bits from the stream and returns a specified unsigned int type
+ /// containing them in the least significant end, returning an error if the
+ /// specified number of bits could not be read.
+ pub fn readBitsNoEof(self: *Self, comptime U: type, bits: usize) !U {
+ var n: usize = undefined;
+ const result = try self.readBits(U, bits, &n);
+ if (n < bits) return error.EndOfStream;
+ return result;
+ }
+
+ /// Reads `bits` bits from the stream and returns a specified unsigned int type
+ /// containing them in the least significant end. The number of bits successfully
+ /// read is placed in `out_bits`, as reaching the end of the stream is not an error.
+ pub fn readBits(self: *Self, comptime U: type, bits: usize, out_bits: *usize) Error!U {
+ comptime assert(trait.isUnsignedInt(U));
+
+ //by extending the buffer to a minimum of u8 we can cover a number of edge cases
+ // related to shifting and casting.
+ const u_bit_count = comptime meta.bitCount(U);
+ const buf_bit_count = bc: {
+ assert(u_bit_count >= bits);
+ break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
+ };
+ const Buf = std.meta.IntType(false, buf_bit_count);
+ const BufShift = math.Log2Int(Buf);
+
+ out_bits.* = @as(usize, 0);
+ if (U == u0 or bits == 0) return 0;
+ var out_buffer = @as(Buf, 0);
+
+ if (self.bit_count > 0) {
+ const n = if (self.bit_count >= bits) @intCast(u3, bits) else self.bit_count;
+ const shift = u7_bit_count - n;
+ switch (endian) {
+ .Big => {
+ out_buffer = @as(Buf, self.bit_buffer >> shift);
+ self.bit_buffer <<= n;
+ },
+ .Little => {
+ const value = (self.bit_buffer << shift) >> shift;
+ out_buffer = @as(Buf, value);
+ self.bit_buffer >>= n;
+ },
+ }
+ self.bit_count -= n;
+ out_bits.* = n;
+ }
+ //at this point we know bit_buffer is empty
+
+ //copy bytes until we have enough bits, then leave the rest in bit_buffer
+ while (out_bits.* < bits) {
+ const n = bits - out_bits.*;
+ const next_byte = self.in_stream.readByte() catch |err| {
+ if (err == error.EndOfStream) {
+ return @intCast(U, out_buffer);
+ }
+ //@BUG: See #1810. Not sure if the bug is that I have to do this for some
+ // streams, or that I don't for streams with emtpy errorsets.
+ return @errSetCast(Error, err);
+ };
+
+ switch (endian) {
+ .Big => {
+ if (n >= u8_bit_count) {
+ out_buffer <<= @intCast(u3, u8_bit_count - 1);
+ out_buffer <<= 1;
+ out_buffer |= @as(Buf, next_byte);
+ out_bits.* += u8_bit_count;
+ continue;
+ }
+
+ const shift = @intCast(u3, u8_bit_count - n);
+ out_buffer <<= @intCast(BufShift, n);
+ out_buffer |= @as(Buf, next_byte >> shift);
+ out_bits.* += n;
+ self.bit_buffer = @truncate(u7, next_byte << @intCast(u3, n - 1));
+ self.bit_count = shift;
+ },
+ .Little => {
+ if (n >= u8_bit_count) {
+ out_buffer |= @as(Buf, next_byte) << @intCast(BufShift, out_bits.*);
+ out_bits.* += u8_bit_count;
+ continue;
+ }
+
+ const shift = @intCast(u3, u8_bit_count - n);
+ const value = (next_byte << shift) >> shift;
+ out_buffer |= @as(Buf, value) << @intCast(BufShift, out_bits.*);
+ out_bits.* += n;
+ self.bit_buffer = @truncate(u7, next_byte >> @intCast(u3, n));
+ self.bit_count = shift;
+ },
+ }
+ }
+
+ return @intCast(U, out_buffer);
+ }
+
+ pub fn alignToByte(self: *Self) void {
+ self.bit_buffer = 0;
+ self.bit_count = 0;
+ }
+
+ pub fn read(self: *Self, buffer: []u8) Error!usize {
+ var out_bits: usize = undefined;
+ var out_bits_total = @as(usize, 0);
+ //@NOTE: I'm not sure this is a good idea, maybe alignToByte should be forced
+ if (self.bit_count > 0) {
+ for (buffer) |*b, i| {
+ b.* = try self.readBits(u8, u8_bit_count, &out_bits);
+ out_bits_total += out_bits;
+ }
+ const incomplete_byte = @boolToInt(out_bits_total % u8_bit_count > 0);
+ return (out_bits_total / u8_bit_count) + incomplete_byte;
+ }
+
+ return self.in_stream.read(buffer);
+ }
+
+ pub fn inStream(self: *Self) InStream {
+ return .{ .context = self };
+ }
+ };
+}
+
+pub fn bitInStream(
+ comptime endian: builtin.Endian,
+ underlying_stream: var,
+) BitInStream(endian, @TypeOf(underlying_stream)) {
+ return BitInStream(endian, @TypeOf(underlying_stream)).init(underlying_stream);
+}
+
+test "api coverage" {
+ const mem_be = [_]u8{ 0b11001101, 0b00001011 };
+ const mem_le = [_]u8{ 0b00011101, 0b10010101 };
+
+ var mem_in_be = io.fixedBufferStream(&mem_be);
+ var bit_stream_be = bitInStream(.Big, mem_in_be.inStream());
+
+ var out_bits: usize = undefined;
+
+ const expect = testing.expect;
+ const expectError = testing.expectError;
+
+ expect(1 == try bit_stream_be.readBits(u2, 1, &out_bits));
+ expect(out_bits == 1);
+ expect(2 == try bit_stream_be.readBits(u5, 2, &out_bits));
+ expect(out_bits == 2);
+ expect(3 == try bit_stream_be.readBits(u128, 3, &out_bits));
+ expect(out_bits == 3);
+ expect(4 == try bit_stream_be.readBits(u8, 4, &out_bits));
+ expect(out_bits == 4);
+ expect(5 == try bit_stream_be.readBits(u9, 5, &out_bits));
+ expect(out_bits == 5);
+ expect(1 == try bit_stream_be.readBits(u1, 1, &out_bits));
+ expect(out_bits == 1);
+
+ mem_in_be.pos = 0;
+ bit_stream_be.bit_count = 0;
+ expect(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits));
+ expect(out_bits == 15);
+
+ mem_in_be.pos = 0;
+ bit_stream_be.bit_count = 0;
+ expect(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits));
+ expect(out_bits == 16);
+
+ _ = try bit_stream_be.readBits(u0, 0, &out_bits);
+
+ expect(0 == try bit_stream_be.readBits(u1, 1, &out_bits));
+ expect(out_bits == 0);
+ expectError(error.EndOfStream, bit_stream_be.readBitsNoEof(u1, 1));
+
+ var mem_in_le = io.fixedBufferStream(&mem_le);
+ var bit_stream_le = bitInStream(.Little, mem_in_le.inStream());
+
+ expect(1 == try bit_stream_le.readBits(u2, 1, &out_bits));
+ expect(out_bits == 1);
+ expect(2 == try bit_stream_le.readBits(u5, 2, &out_bits));
+ expect(out_bits == 2);
+ expect(3 == try bit_stream_le.readBits(u128, 3, &out_bits));
+ expect(out_bits == 3);
+ expect(4 == try bit_stream_le.readBits(u8, 4, &out_bits));
+ expect(out_bits == 4);
+ expect(5 == try bit_stream_le.readBits(u9, 5, &out_bits));
+ expect(out_bits == 5);
+ expect(1 == try bit_stream_le.readBits(u1, 1, &out_bits));
+ expect(out_bits == 1);
+
+ mem_in_le.pos = 0;
+ bit_stream_le.bit_count = 0;
+ expect(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits));
+ expect(out_bits == 15);
+
+ mem_in_le.pos = 0;
+ bit_stream_le.bit_count = 0;
+ expect(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits));
+ expect(out_bits == 16);
+
+ _ = try bit_stream_le.readBits(u0, 0, &out_bits);
+
+ expect(0 == try bit_stream_le.readBits(u1, 1, &out_bits));
+ expect(out_bits == 0);
+ expectError(error.EndOfStream, bit_stream_le.readBitsNoEof(u1, 1));
+}
diff --git a/lib/std/io/bit_out_stream.zig b/lib/std/io/bit_out_stream.zig
new file mode 100644
index 000000000..1a2bb62e7
--- /dev/null
+++ b/lib/std/io/bit_out_stream.zig
@@ -0,0 +1,197 @@
+const std = @import("../std.zig");
+const builtin = std.builtin;
+const io = std.io;
+const testing = std.testing;
+const assert = std.debug.assert;
+const trait = std.meta.trait;
+const meta = std.meta;
+const math = std.math;
+
+/// Creates a stream which allows for writing bit fields to another stream
+pub fn BitOutStream(endian: builtin.Endian, comptime OutStreamType: type) type {
+ return struct {
+ out_stream: OutStreamType,
+ bit_buffer: u8,
+ bit_count: u4,
+
+ pub const Error = OutStreamType.Error;
+ pub const OutStream = io.OutStream(*Self, Error, write);
+
+ const Self = @This();
+ const u8_bit_count = comptime meta.bitCount(u8);
+ const u4_bit_count = comptime meta.bitCount(u4);
+
+ pub fn init(out_stream: OutStreamType) Self {
+ return Self{
+ .out_stream = out_stream,
+ .bit_buffer = 0,
+ .bit_count = 0,
+ };
+ }
+
+ /// Write the specified number of bits to the stream from the least significant bits of
+ /// the specified unsigned int value. Bits will only be written to the stream when there
+ /// are enough to fill a byte.
+ pub fn writeBits(self: *Self, value: var, bits: usize) Error!void {
+ if (bits == 0) return;
+
+ const U = @TypeOf(value);
+ comptime assert(trait.isUnsignedInt(U));
+
+ //by extending the buffer to a minimum of u8 we can cover a number of edge cases
+ // related to shifting and casting.
+ const u_bit_count = comptime meta.bitCount(U);
+ const buf_bit_count = bc: {
+ assert(u_bit_count >= bits);
+ break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count;
+ };
+ const Buf = std.meta.IntType(false, buf_bit_count);
+ const BufShift = math.Log2Int(Buf);
+
+ const buf_value = @intCast(Buf, value);
+
+ const high_byte_shift = @intCast(BufShift, buf_bit_count - u8_bit_count);
+ var in_buffer = switch (endian) {
+ .Big => buf_value << @intCast(BufShift, buf_bit_count - bits),
+ .Little => buf_value,
+ };
+ var in_bits = bits;
+
+ if (self.bit_count > 0) {
+ const bits_remaining = u8_bit_count - self.bit_count;
+ const n = @intCast(u3, if (bits_remaining > bits) bits else bits_remaining);
+ switch (endian) {
+ .Big => {
+ const shift = @intCast(BufShift, high_byte_shift + self.bit_count);
+ const v = @intCast(u8, in_buffer >> shift);
+ self.bit_buffer |= v;
+ in_buffer <<= n;
+ },
+ .Little => {
+ const v = @truncate(u8, in_buffer) << @intCast(u3, self.bit_count);
+ self.bit_buffer |= v;
+ in_buffer >>= n;
+ },
+ }
+ self.bit_count += n;
+ in_bits -= n;
+
+ //if we didn't fill the buffer, it's because bits < bits_remaining;
+ if (self.bit_count != u8_bit_count) return;
+ try self.out_stream.writeByte(self.bit_buffer);
+ self.bit_buffer = 0;
+ self.bit_count = 0;
+ }
+ //at this point we know bit_buffer is empty
+
+ //copy bytes until we can't fill one anymore, then leave the rest in bit_buffer
+ while (in_bits >= u8_bit_count) {
+ switch (endian) {
+ .Big => {
+ const v = @intCast(u8, in_buffer >> high_byte_shift);
+ try self.out_stream.writeByte(v);
+ in_buffer <<= @intCast(u3, u8_bit_count - 1);
+ in_buffer <<= 1;
+ },
+ .Little => {
+ const v = @truncate(u8, in_buffer);
+ try self.out_stream.writeByte(v);
+ in_buffer >>= @intCast(u3, u8_bit_count - 1);
+ in_buffer >>= 1;
+ },
+ }
+ in_bits -= u8_bit_count;
+ }
+
+ if (in_bits > 0) {
+ self.bit_count = @intCast(u4, in_bits);
+ self.bit_buffer = switch (endian) {
+ .Big => @truncate(u8, in_buffer >> high_byte_shift),
+ .Little => @truncate(u8, in_buffer),
+ };
+ }
+ }
+
+ /// Flush any remaining bits to the stream.
+ pub fn flushBits(self: *Self) Error!void {
+ if (self.bit_count == 0) return;
+ try self.out_stream.writeByte(self.bit_buffer);
+ self.bit_buffer = 0;
+ self.bit_count = 0;
+ }
+
+ pub fn write(self: *Self, buffer: []const u8) Error!usize {
+ // TODO: I'm not sure this is a good idea, maybe flushBits should be forced
+ if (self.bit_count > 0) {
+ for (buffer) |b, i|
+ try self.writeBits(b, u8_bit_count);
+ return buffer.len;
+ }
+
+ return self.out_stream.write(buffer);
+ }
+
+ pub fn outStream(self: *Self) OutStream {
+ return .{ .context = self };
+ }
+ };
+}
+
+pub fn bitOutStream(
+ comptime endian: builtin.Endian,
+ underlying_stream: var,
+) BitOutStream(endian, @TypeOf(underlying_stream)) {
+ return BitOutStream(endian, @TypeOf(underlying_stream)).init(underlying_stream);
+}
+
+test "api coverage" {
+ var mem_be = [_]u8{0} ** 2;
+ var mem_le = [_]u8{0} ** 2;
+
+ var mem_out_be = io.fixedBufferStream(&mem_be);
+ var bit_stream_be = bitOutStream(.Big, mem_out_be.outStream());
+
+ try bit_stream_be.writeBits(@as(u2, 1), 1);
+ try bit_stream_be.writeBits(@as(u5, 2), 2);
+ try bit_stream_be.writeBits(@as(u128, 3), 3);
+ try bit_stream_be.writeBits(@as(u8, 4), 4);
+ try bit_stream_be.writeBits(@as(u9, 5), 5);
+ try bit_stream_be.writeBits(@as(u1, 1), 1);
+
+ testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011);
+
+ mem_out_be.pos = 0;
+
+ try bit_stream_be.writeBits(@as(u15, 0b110011010000101), 15);
+ try bit_stream_be.flushBits();
+ testing.expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010);
+
+ mem_out_be.pos = 0;
+ try bit_stream_be.writeBits(@as(u32, 0b110011010000101), 16);
+ testing.expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101);
+
+ try bit_stream_be.writeBits(@as(u0, 0), 0);
+
+ var mem_out_le = io.fixedBufferStream(&mem_le);
+ var bit_stream_le = bitOutStream(.Little, mem_out_le.outStream());
+
+ try bit_stream_le.writeBits(@as(u2, 1), 1);
+ try bit_stream_le.writeBits(@as(u5, 2), 2);
+ try bit_stream_le.writeBits(@as(u128, 3), 3);
+ try bit_stream_le.writeBits(@as(u8, 4), 4);
+ try bit_stream_le.writeBits(@as(u9, 5), 5);
+ try bit_stream_le.writeBits(@as(u1, 1), 1);
+
+ testing.expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101);
+
+ mem_out_le.pos = 0;
+ try bit_stream_le.writeBits(@as(u15, 0b110011010000101), 15);
+ try bit_stream_le.flushBits();
+ testing.expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110);
+
+ mem_out_le.pos = 0;
+ try bit_stream_le.writeBits(@as(u32, 0b1100110100001011), 16);
+ testing.expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101);
+
+ try bit_stream_le.writeBits(@as(u0, 0), 0);
+}
diff --git a/lib/std/io/buffered_in_stream.zig b/lib/std/io/buffered_in_stream.zig
index 72f1b30b7..7f76c8c57 100644
--- a/lib/std/io/buffered_in_stream.zig
+++ b/lib/std/io/buffered_in_stream.zig
@@ -1,7 +1,9 @@
const std = @import("../std.zig");
const io = std.io;
+const assert = std.debug.assert;
+const testing = std.testing;
-pub fn BufferedInStream(comptime buffer_size: usize, comptime InStreamType) type {
+pub fn BufferedInStream(comptime buffer_size: usize, comptime InStreamType: type) type {
return struct {
unbuffered_in_stream: InStreamType,
fifo: FifoType = FifoType.init(),
diff --git a/lib/std/io/c_out_stream.zig b/lib/std/io/c_out_stream.zig
new file mode 100644
index 000000000..106fc601a
--- /dev/null
+++ b/lib/std/io/c_out_stream.zig
@@ -0,0 +1,44 @@
+const std = @import("../std.zig");
+const builtin = std.builtin;
+const io = std.io;
+const testing = std.testing;
+
+pub const COutStream = io.OutStream(*std.c.FILE, std.fs.File.WriteError, cOutStreamWrite);
+
+pub fn cOutStream(c_file: *std.c.FILE) COutStream {
+ return .{ .context = c_file };
+}
+
+fn cOutStreamWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
+ const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
+ if (amt_written >= 0) return amt_written;
+ switch (std.c._errno().*) {
+ 0 => unreachable,
+ os.EINVAL => unreachable,
+ os.EFAULT => unreachable,
+ os.EAGAIN => unreachable, // this is a blocking API
+ os.EBADF => unreachable, // always a race condition
+ os.EDESTADDRREQ => unreachable, // connect was never called
+ os.EDQUOT => return error.DiskQuota,
+ os.EFBIG => return error.FileTooBig,
+ os.EIO => return error.InputOutput,
+ os.ENOSPC => return error.NoSpaceLeft,
+ os.EPERM => return error.AccessDenied,
+ os.EPIPE => return error.BrokenPipe,
+ else => |err| return os.unexpectedErrno(@intCast(usize, err)),
+ }
+}
+
+test "" {
+ if (!builtin.link_libc) return error.SkipZigTest;
+
+ const filename = "tmp_io_test_file.txt";
+ const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
+ defer {
+ _ = std.c.fclose(out_file);
+ fs.cwd().deleteFileC(filename) catch {};
+ }
+
+ const out_stream = &io.COutStream.init(out_file).stream;
+ try out_stream.print("hi: {}\n", .{@as(i32, 123)});
+}
diff --git a/lib/std/io/counting_out_stream.zig b/lib/std/io/counting_out_stream.zig
index 2b0cba29f..f5bd6634f 100644
--- a/lib/std/io/counting_out_stream.zig
+++ b/lib/std/io/counting_out_stream.zig
@@ -1,5 +1,6 @@
const std = @import("../std.zig");
const io = std.io;
+const testing = std.testing;
/// An OutStream that counts how many bytes has been written to it.
pub fn CountingOutStream(comptime OutStreamType: type) type {
@@ -12,13 +13,6 @@ pub fn CountingOutStream(comptime OutStreamType: type) type {
const Self = @This();
- pub fn init(child_stream: OutStreamType) Self {
- return Self{
- .bytes_written = 0,
- .child_stream = child_stream,
- };
- }
-
pub fn write(self: *Self, bytes: []const u8) Error!usize {
const amt = try self.child_stream.write(bytes);
self.bytes_written += amt;
@@ -31,12 +25,15 @@ pub fn CountingOutStream(comptime OutStreamType: type) type {
};
}
-test "io.CountingOutStream" {
- var counting_stream = CountingOutStream(NullOutStream.Error).init(std.io.null_out_stream);
- const stream = &counting_stream.stream;
-
- const bytes = "yay" ** 10000;
- stream.write(bytes) catch unreachable;
- testing.expect(counting_stream.bytes_written == bytes.len);
+pub fn countingOutStream(child_stream: var) CountingOutStream(@TypeOf(child_stream)) {
+ return .{ .bytes_written = 0, .child_stream = child_stream };
}
+test "io.CountingOutStream" {
+ var counting_stream = countingOutStream(std.io.null_out_stream);
+ const stream = counting_stream.outStream();
+
+ const bytes = "yay" ** 100;
+ stream.writeAll(bytes) catch unreachable;
+ testing.expect(counting_stream.bytes_written == bytes.len);
+}
diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig
index 75a337d3d..9cdad7dc5 100644
--- a/lib/std/io/fixed_buffer_stream.zig
+++ b/lib/std/io/fixed_buffer_stream.zig
@@ -1,9 +1,11 @@
const std = @import("../std.zig");
const io = std.io;
const testing = std.testing;
+const mem = std.mem;
+const assert = std.debug.assert;
-/// This turns a slice into an `io.OutStream`, `io.InStream`, or `io.SeekableStream`.
-/// If the supplied slice is const, then `io.OutStream` is not available.
+/// This turns a byte buffer into an `io.OutStream`, `io.InStream`, or `io.SeekableStream`.
+/// If the supplied byte buffer is const, then `io.OutStream` is not available.
pub fn FixedBufferStream(comptime Buffer: type) type {
return struct {
/// `Buffer` is either a `[]u8` or `[]const u8`.
@@ -46,7 +48,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
const size = std.math.min(dest.len, self.buffer.len - self.pos);
const end = self.pos + size;
- std.mem.copy(u8, dest[0..size], self.buffer[self.pos..end]);
+ mem.copy(u8, dest[0..size], self.buffer[self.pos..end]);
self.pos = end;
if (size == 0) return error.EndOfStream;
@@ -65,7 +67,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
else
self.buffer.len - self.pos;
- std.mem.copy(u8, self.buffer[self.pos .. self.pos + n], bytes[0..n]);
+ mem.copy(u8, self.buffer[self.pos .. self.pos + n], bytes[0..n]);
self.pos += n;
if (n == 0) return error.OutOfMemory;
@@ -100,7 +102,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
}
pub fn getWritten(self: Self) []const u8 {
- return self.slice[0..self.pos];
+ return self.buffer[0..self.pos];
}
pub fn reset(self: *Self) void {
@@ -110,16 +112,16 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
}
pub fn fixedBufferStream(buffer: var) FixedBufferStream(NonSentinelSpan(@TypeOf(buffer))) {
- return .{ .buffer = std.mem.span(buffer), .pos = 0 };
+ return .{ .buffer = mem.span(buffer), .pos = 0 };
}
fn NonSentinelSpan(comptime T: type) type {
- var ptr_info = @typeInfo(std.mem.Span(T)).Pointer;
+ var ptr_info = @typeInfo(mem.Span(T)).Pointer;
ptr_info.sentinel = null;
return @Type(std.builtin.TypeInfo{ .Pointer = ptr_info });
}
-test "FixedBufferStream" {
+test "FixedBufferStream output" {
var buf: [255]u8 = undefined;
var fbs = fixedBufferStream(&buf);
const stream = fbs.outStream();
@@ -127,3 +129,41 @@ test "FixedBufferStream" {
try stream.print("{}{}!", .{ "Hello", "World" });
testing.expectEqualSlices(u8, "HelloWorld!", fbs.getWritten());
}
+
+test "FixedBufferStream output 2" {
+ var buffer: [10]u8 = undefined;
+ var fbs = fixedBufferStream(&buffer);
+
+ try fbs.outStream().writeAll("Hello");
+ testing.expect(mem.eql(u8, fbs.getWritten(), "Hello"));
+
+ try fbs.outStream().writeAll("world");
+ testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
+
+ testing.expectError(error.OutOfMemory, fbs.outStream().writeAll("!"));
+ testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
+
+ fbs.reset();
+ testing.expect(fbs.getWritten().len == 0);
+
+ testing.expectError(error.OutOfMemory, fbs.outStream().writeAll("Hello world!"));
+ testing.expect(mem.eql(u8, fbs.getWritten(), "Hello worl"));
+}
+
+test "FixedBufferStream input" {
+ const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7 };
+ var fbs = fixedBufferStream(&bytes);
+
+ var dest: [4]u8 = undefined;
+
+ var read = try fbs.inStream().read(dest[0..4]);
+ testing.expect(read == 4);
+ testing.expect(mem.eql(u8, dest[0..4], bytes[0..4]));
+
+ read = try fbs.inStream().read(dest[0..4]);
+ testing.expect(read == 3);
+ testing.expect(mem.eql(u8, dest[0..3], bytes[4..7]));
+
+ read = try fbs.inStream().read(dest[0..4]);
+ testing.expect(read == 0);
+}
diff --git a/lib/std/io/in_stream.zig b/lib/std/io/in_stream.zig
index d181f4df4..283058248 100644
--- a/lib/std/io/in_stream.zig
+++ b/lib/std/io/in_stream.zig
@@ -273,8 +273,7 @@ pub fn InStream(
test "InStream" {
var buf = "a\x02".*;
- var slice_stream = std.io.SliceInStream.init(&buf);
- const in_stream = &slice_stream.stream;
+ const in_stream = std.io.fixedBufferStream(&buf).inStream();
testing.expect((try in_stream.readByte()) == 'a');
testing.expect((try in_stream.readEnum(enum(u8) {
a = 0,
diff --git a/lib/std/io/peek_stream.zig b/lib/std/io/peek_stream.zig
new file mode 100644
index 000000000..5ee30ce27
--- /dev/null
+++ b/lib/std/io/peek_stream.zig
@@ -0,0 +1,112 @@
+const std = @import("../std.zig");
+const io = std.io;
+const mem = std.mem;
+const testing = std.testing;
+
+/// Creates a stream which supports 'un-reading' data, so that it can be read again.
+/// This makes look-ahead style parsing much easier.
+/// TODO merge this with `std.io.BufferedInStream`: https://github.com/ziglang/zig/issues/4501
+pub fn PeekStream(
+ comptime buffer_type: std.fifo.LinearFifoBufferType,
+ comptime InStreamType: type,
+) type {
+ return struct {
+ unbuffered_in_stream: InStreamType,
+ fifo: FifoType,
+
+ pub const Error = InStreamType.Error;
+ pub const InStream = io.InStream(*Self, Error, read);
+
+ const Self = @This();
+ const FifoType = std.fifo.LinearFifo(u8, buffer_type);
+
+ pub usingnamespace switch (buffer_type) {
+ .Static => struct {
+ pub fn init(base: InStreamType) Self {
+ return .{
+ .base = base,
+ .fifo = FifoType.init(),
+ };
+ }
+ },
+ .Slice => struct {
+ pub fn init(base: InStreamType, buf: []u8) Self {
+ return .{
+ .base = base,
+ .fifo = FifoType.init(buf),
+ };
+ }
+ },
+ .Dynamic => struct {
+ pub fn init(base: InStreamType, allocator: *mem.Allocator) Self {
+ return .{
+ .base = base,
+ .fifo = FifoType.init(allocator),
+ };
+ }
+ },
+ };
+
+ pub fn putBackByte(self: *Self, byte: u8) !void {
+ try self.putBack(&[_]u8{byte});
+ }
+
+ pub fn putBack(self: *Self, bytes: []const u8) !void {
+ try self.fifo.unget(bytes);
+ }
+
+ pub fn read(self: *Self, dest: []u8) Error!usize {
+ // copy over anything putBack()'d
+ var dest_index = self.fifo.read(dest);
+ if (dest_index == dest.len) return dest_index;
+
+ // ask the backing stream for more
+ dest_index += try self.base.read(dest[dest_index..]);
+ return dest_index;
+ }
+
+ pub fn inStream(self: *Self) InStream {
+ return .{ .context = self };
+ }
+ };
+}
+
+pub fn peekStream(
+ comptime lookahead: comptime_int,
+ underlying_stream: var,
+) PeekStream(.{ .Static = lookahead }, @TypeOf(underlying_stream)) {
+ return PeekStream(.{ .Static = lookahead }, @TypeOf(underlying_stream)).init(underlying_stream);
+}
+
+test "PeekStream" {
+ const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
+ var fbs = io.fixedBufferStream(&bytes);
+ var ps = peekStream(2, fbs.inStream());
+
+ var dest: [4]u8 = undefined;
+
+ try ps.putBackByte(9);
+ try ps.putBackByte(10);
+
+ var read = try ps.inStream().read(dest[0..4]);
+ testing.expect(read == 4);
+ testing.expect(dest[0] == 10);
+ testing.expect(dest[1] == 9);
+ testing.expect(mem.eql(u8, dest[2..4], bytes[0..2]));
+
+ read = try ps.inStream().read(dest[0..4]);
+ testing.expect(read == 4);
+ testing.expect(mem.eql(u8, dest[0..4], bytes[2..6]));
+
+ read = try ps.inStream().read(dest[0..4]);
+ testing.expect(read == 2);
+ testing.expect(mem.eql(u8, dest[0..2], bytes[6..8]));
+
+ try ps.putBackByte(11);
+ try ps.putBackByte(12);
+
+ read = try ps.inStream().read(dest[0..4]);
+ testing.expect(read == 2);
+ testing.expect(dest[0] == 12);
+ testing.expect(dest[1] == 11);
+}
diff --git a/lib/std/io/serialization.zig b/lib/std/io/serialization.zig
new file mode 100644
index 000000000..4aa462aab
--- /dev/null
+++ b/lib/std/io/serialization.zig
@@ -0,0 +1,606 @@
+const std = @import("../std.zig");
+const builtin = std.builtin;
+const io = std.io;
+
+pub const Packing = enum {
+ /// Pack data to byte alignment
+ Byte,
+
+ /// Pack data to bit alignment
+ Bit,
+};
+
+/// Creates a deserializer that deserializes types from any stream.
+/// If `is_packed` is true, the data stream is treated as bit-packed,
+/// otherwise data is expected to be packed to the smallest byte.
+/// Types may implement a custom deserialization routine with a
+/// function named `deserialize` in the form of:
+/// pub fn deserialize(self: *Self, deserializer: var) !void
+/// which will be called when the deserializer is used to deserialize
+/// that type. It will pass a pointer to the type instance to deserialize
+/// into and a pointer to the deserializer struct.
+pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime InStreamType: type) type {
+ return struct {
+ in_stream: if (packing == .Bit) io.BitInStream(endian, InStreamType) else InStreamType,
+
+ const Self = @This();
+
+ pub fn init(in_stream: InStreamType) Self {
+ return Self{
+ .in_stream = switch (packing) {
+ .Bit => io.bitInStream(endian, in_stream),
+ .Byte => in_stream,
+ },
+ };
+ }
+
+ pub fn alignToByte(self: *Self) void {
+ if (packing == .Byte) return;
+ self.in_stream.alignToByte();
+ }
+
+ //@BUG: inferred error issue. See: #1386
+ fn deserializeInt(self: *Self, comptime T: type) (InStreamType.Error || error{EndOfStream})!T {
+ comptime assert(trait.is(.Int)(T) or trait.is(.Float)(T));
+
+ const u8_bit_count = 8;
+ const t_bit_count = comptime meta.bitCount(T);
+
+ const U = std.meta.IntType(false, t_bit_count);
+ const Log2U = math.Log2Int(U);
+ const int_size = (U.bit_count + 7) / 8;
+
+ if (packing == .Bit) {
+ const result = try self.in_stream.readBitsNoEof(U, t_bit_count);
+ return @bitCast(T, result);
+ }
+
+ var buffer: [int_size]u8 = undefined;
+ const read_size = try self.in_stream.read(buffer[0..]);
+ if (read_size < int_size) return error.EndOfStream;
+
+ if (int_size == 1) {
+ if (t_bit_count == 8) return @bitCast(T, buffer[0]);
+ const PossiblySignedByte = std.meta.IntType(T.is_signed, 8);
+ return @truncate(T, @bitCast(PossiblySignedByte, buffer[0]));
+ }
+
+ var result = @as(U, 0);
+ for (buffer) |byte, i| {
+ switch (endian) {
+ .Big => {
+ result = (result << u8_bit_count) | byte;
+ },
+ .Little => {
+ result |= @as(U, byte) << @intCast(Log2U, u8_bit_count * i);
+ },
+ }
+ }
+
+ return @bitCast(T, result);
+ }
+
+ /// Deserializes and returns data of the specified type from the stream
+ pub fn deserialize(self: *Self, comptime T: type) !T {
+ var value: T = undefined;
+ try self.deserializeInto(&value);
+ return value;
+ }
+
+ /// Deserializes data into the type pointed to by `ptr`
+ pub fn deserializeInto(self: *Self, ptr: var) !void {
+ const T = @TypeOf(ptr);
+ comptime assert(trait.is(.Pointer)(T));
+
+ if (comptime trait.isSlice(T) or comptime trait.isPtrTo(.Array)(T)) {
+ for (ptr) |*v|
+ try self.deserializeInto(v);
+ return;
+ }
+
+ comptime assert(trait.isSingleItemPtr(T));
+
+ const C = comptime meta.Child(T);
+ const child_type_id = @typeInfo(C);
+
+ //custom deserializer: fn(self: *Self, deserializer: var) !void
+ if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self);
+
+ if (comptime trait.isPacked(C) and packing != .Bit) {
+ var packed_deserializer = deserializer(endian, .Bit, self.in_stream);
+ return packed_deserializer.deserializeInto(ptr);
+ }
+
+ switch (child_type_id) {
+ .Void => return,
+ .Bool => ptr.* = (try self.deserializeInt(u1)) > 0,
+ .Float, .Int => ptr.* = try self.deserializeInt(C),
+ .Struct => {
+ const info = @typeInfo(C).Struct;
+
+ inline for (info.fields) |*field_info| {
+ const name = field_info.name;
+ const FieldType = field_info.field_type;
+
+ if (FieldType == void or FieldType == u0) continue;
+
+ //it doesn't make any sense to read pointers
+ if (comptime trait.is(.Pointer)(FieldType)) {
+ @compileError("Will not " ++ "read field " ++ name ++ " of struct " ++
+ @typeName(C) ++ " because it " ++ "is of pointer-type " ++
+ @typeName(FieldType) ++ ".");
+ }
+
+ try self.deserializeInto(&@field(ptr, name));
+ }
+ },
+ .Union => {
+ const info = @typeInfo(C).Union;
+ if (info.tag_type) |TagType| {
+ //we avoid duplicate iteration over the enum tags
+ // by getting the int directly and casting it without
+ // safety. If it is bad, it will be caught anyway.
+ const TagInt = @TagType(TagType);
+ const tag = try self.deserializeInt(TagInt);
+
+ inline for (info.fields) |field_info| {
+ if (field_info.enum_field.?.value == tag) {
+ const name = field_info.name;
+ const FieldType = field_info.field_type;
+ ptr.* = @unionInit(C, name, undefined);
+ try self.deserializeInto(&@field(ptr, name));
+ return;
+ }
+ }
+ //This is reachable if the enum data is bad
+ return error.InvalidEnumTag;
+ }
+ @compileError("Cannot meaningfully deserialize " ++ @typeName(C) ++
+ " because it is an untagged union. Use a custom deserialize().");
+ },
+ .Optional => {
+ const OC = comptime meta.Child(C);
+ const exists = (try self.deserializeInt(u1)) > 0;
+ if (!exists) {
+ ptr.* = null;
+ return;
+ }
+
+ ptr.* = @as(OC, undefined); //make it non-null so the following .? is guaranteed safe
+ const val_ptr = &ptr.*.?;
+ try self.deserializeInto(val_ptr);
+ },
+ .Enum => {
+ var value = try self.deserializeInt(@TagType(C));
+ ptr.* = try meta.intToEnum(C, value);
+ },
+ else => {
+ @compileError("Cannot deserialize " ++ @tagName(child_type_id) ++ " types (unimplemented).");
+ },
+ }
+ }
+ };
+}
+
+pub fn deserializer(
+ comptime endian: builtin.Endian,
+ comptime packing: Packing,
+ in_stream: var,
+) Deserializer(endian, packing, @TypeOf(in_stream)) {
+ return Deserializer(endian, packing, @TypeOf(in_stream)).init(in_stream);
+}
+
+/// Creates a serializer that serializes types to any stream.
+/// If `is_packed` is true, the data will be bit-packed into the stream.
+/// Note that the you must call `serializer.flush()` when you are done
+/// writing bit-packed data in order ensure any unwritten bits are committed.
+/// If `is_packed` is false, data is packed to the smallest byte. In the case
+/// of packed structs, the struct will written bit-packed and with the specified
+/// endianess, after which data will resume being written at the next byte boundary.
+/// Types may implement a custom serialization routine with a
+/// function named `serialize` in the form of:
+/// pub fn serialize(self: Self, serializer: var) !void
+/// which will be called when the serializer is used to serialize that type. It will
+/// pass a const pointer to the type instance to be serialized and a pointer
+/// to the serializer struct.
+pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime OutStreamType: type) type {
+ return struct {
+ out_stream: if (packing == .Bit) BitOutStream(endian, OutStreamType) else OutStreamType,
+
+ const Self = @This();
+ pub const Error = OutStreamType.Error;
+
+ pub fn init(out_stream: OutStreamType) Self {
+ return Self{
+ .out_stream = switch (packing) {
+ .Bit => io.bitOutStream(endian, out_stream),
+ .Byte => out_stream,
+ },
+ };
+ }
+
+ /// Flushes any unwritten bits to the stream
+ pub fn flush(self: *Self) Error!void {
+ if (packing == .Bit) return self.out_stream.flushBits();
+ }
+
+ fn serializeInt(self: *Self, value: var) Error!void {
+ const T = @TypeOf(value);
+ comptime assert(trait.is(.Int)(T) or trait.is(.Float)(T));
+
+ const t_bit_count = comptime meta.bitCount(T);
+ const u8_bit_count = comptime meta.bitCount(u8);
+
+ const U = std.meta.IntType(false, t_bit_count);
+ const Log2U = math.Log2Int(U);
+ const int_size = (U.bit_count + 7) / 8;
+
+ const u_value = @bitCast(U, value);
+
+ if (packing == .Bit) return self.out_stream.writeBits(u_value, t_bit_count);
+
+ var buffer: [int_size]u8 = undefined;
+ if (int_size == 1) buffer[0] = u_value;
+
+ for (buffer) |*byte, i| {
+ const idx = switch (endian) {
+ .Big => int_size - i - 1,
+ .Little => i,
+ };
+ const shift = @intCast(Log2U, idx * u8_bit_count);
+ const v = u_value >> shift;
+ byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v);
+ }
+
+ try self.out_stream.write(&buffer);
+ }
+
+ /// Serializes the passed value into the stream
+ pub fn serialize(self: *Self, value: var) Error!void {
+ const T = comptime @TypeOf(value);
+
+ if (comptime trait.isIndexable(T)) {
+ for (value) |v|
+ try self.serialize(v);
+ return;
+ }
+
+ //custom serializer: fn(self: Self, serializer: var) !void
+ if (comptime trait.hasFn("serialize")(T)) return T.serialize(value, self);
+
+ if (comptime trait.isPacked(T) and packing != .Bit) {
+ var packed_serializer = Serializer(endian, .Bit, Error).init(self.out_stream);
+ try packed_serializer.serialize(value);
+ try packed_serializer.flush();
+ return;
+ }
+
+ switch (@typeInfo(T)) {
+ .Void => return,
+ .Bool => try self.serializeInt(@as(u1, @boolToInt(value))),
+ .Float, .Int => try self.serializeInt(value),
+ .Struct => {
+ const info = @typeInfo(T);
+
+ inline for (info.Struct.fields) |*field_info| {
+ const name = field_info.name;
+ const FieldType = field_info.field_type;
+
+ if (FieldType == void or FieldType == u0) continue;
+
+ //It doesn't make sense to write pointers
+ if (comptime trait.is(.Pointer)(FieldType)) {
+ @compileError("Will not " ++ "serialize field " ++ name ++
+ " of struct " ++ @typeName(T) ++ " because it " ++
+ "is of pointer-type " ++ @typeName(FieldType) ++ ".");
+ }
+ try self.serialize(@field(value, name));
+ }
+ },
+ .Union => {
+ const info = @typeInfo(T).Union;
+ if (info.tag_type) |TagType| {
+ const active_tag = meta.activeTag(value);
+ try self.serialize(active_tag);
+ //This inline loop is necessary because active_tag is a runtime
+ // value, but @field requires a comptime value. Our alternative
+ // is to check each field for a match
+ inline for (info.fields) |field_info| {
+ if (field_info.enum_field.?.value == @enumToInt(active_tag)) {
+ const name = field_info.name;
+ const FieldType = field_info.field_type;
+ try self.serialize(@field(value, name));
+ return;
+ }
+ }
+ unreachable;
+ }
+ @compileError("Cannot meaningfully serialize " ++ @typeName(T) ++
+ " because it is an untagged union. Use a custom serialize().");
+ },
+ .Optional => {
+ if (value == null) {
+ try self.serializeInt(@as(u1, @boolToInt(false)));
+ return;
+ }
+ try self.serializeInt(@as(u1, @boolToInt(true)));
+
+ const OC = comptime meta.Child(T);
+ const val_ptr = &value.?;
+ try self.serialize(val_ptr.*);
+ },
+ .Enum => {
+ try self.serializeInt(@enumToInt(value));
+ },
+ else => @compileError("Cannot serialize " ++ @tagName(@typeInfo(T)) ++ " types (unimplemented)."),
+ }
+ }
+ };
+}
+
+pub fn serializer(
+ comptime endian: builtin.Endian,
+ comptime packing: Packing,
+ out_stream: var,
+) Serializer(endian, packing, @TypeOf(out_stream)) {
+ return Serializer(endian, packing, @TypeOf(out_stream)).init(out_stream);
+}
+
+fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
+ @setEvalBranchQuota(1500);
+ //@NOTE: if this test is taking too long, reduce the maximum tested bitsize
+ const max_test_bitsize = 128;
+
+ const total_bytes = comptime blk: {
+ var bytes = 0;
+ comptime var i = 0;
+ while (i <= max_test_bitsize) : (i += 1) bytes += (i / 8) + @boolToInt(i % 8 > 0);
+ break :blk bytes * 2;
+ };
+
+ var data_mem: [total_bytes]u8 = undefined;
+ var out = io.fixedBufferStream(&data_mem);
+ var serializer = serializer(endian, packing, out.outStream());
+
+ var in = io.fixedBufferStream(&data_mem);
+ var deserializer = Deserializer(endian, packing, in.inStream());
+
+ comptime var i = 0;
+ inline while (i <= max_test_bitsize) : (i += 1) {
+ const U = std.meta.IntType(false, i);
+ const S = std.meta.IntType(true, i);
+ try serializer.serializeInt(@as(U, i));
+ if (i != 0) try serializer.serializeInt(@as(S, -1)) else try serializer.serialize(@as(S, 0));
+ }
+ try serializer.flush();
+
+ i = 0;
+ inline while (i <= max_test_bitsize) : (i += 1) {
+ const U = std.meta.IntType(false, i);
+ const S = std.meta.IntType(true, i);
+ const x = try deserializer.deserializeInt(U);
+ const y = try deserializer.deserializeInt(S);
+ expect(x == @as(U, i));
+ if (i != 0) expect(y == @as(S, -1)) else expect(y == 0);
+ }
+
+ const u8_bit_count = comptime meta.bitCount(u8);
+ //0 + 1 + 2 + ... n = (n * (n + 1)) / 2
+ //and we have each for unsigned and signed, so * 2
+ const total_bits = (max_test_bitsize * (max_test_bitsize + 1));
+ const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0);
+ const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte;
+
+ expect(in.pos == if (packing == .Bit) total_packed_bytes else total_bytes);
+
+ //Verify that empty error set works with serializer.
+ //deserializer is covered by FixedBufferStream
+ var null_serializer = io.serializer(endian, packing, std.io.null_out_stream);
+ try null_serializer.serialize(data_mem[0..]);
+ try null_serializer.flush();
+}
+
+test "Serializer/Deserializer Int" {
+ try testIntSerializerDeserializer(.Big, .Byte);
+ try testIntSerializerDeserializer(.Little, .Byte);
+ // TODO these tests are disabled due to tripping an LLVM assertion
+ // https://github.com/ziglang/zig/issues/2019
+ //try testIntSerializerDeserializer(builtin.Endian.Big, true);
+ //try testIntSerializerDeserializer(builtin.Endian.Little, true);
+}
+
+fn testIntSerializerDeserializerInfNaN(
+ comptime endian: builtin.Endian,
+ comptime packing: io.Packing,
+) !void {
+ const mem_size = (16 * 2 + 32 * 2 + 64 * 2 + 128 * 2) / comptime meta.bitCount(u8);
+ var data_mem: [mem_size]u8 = undefined;
+
+ var out = io.fixedBufferStream(&data_mem);
+ var serializer = serializer(endian, packing, out.outStream());
+
+ var in = io.fixedBufferStream(&data_mem);
+ var deserializer = deserializer(endian, packing, in.inStream());
+
+ //@TODO: isInf/isNan not currently implemented for f128.
+ try serializer.serialize(std.math.nan(f16));
+ try serializer.serialize(std.math.inf(f16));
+ try serializer.serialize(std.math.nan(f32));
+ try serializer.serialize(std.math.inf(f32));
+ try serializer.serialize(std.math.nan(f64));
+ try serializer.serialize(std.math.inf(f64));
+ //try serializer.serialize(std.math.nan(f128));
+ //try serializer.serialize(std.math.inf(f128));
+ const nan_check_f16 = try deserializer.deserialize(f16);
+ const inf_check_f16 = try deserializer.deserialize(f16);
+ const nan_check_f32 = try deserializer.deserialize(f32);
+ deserializer.alignToByte();
+ const inf_check_f32 = try deserializer.deserialize(f32);
+ const nan_check_f64 = try deserializer.deserialize(f64);
+ const inf_check_f64 = try deserializer.deserialize(f64);
+ //const nan_check_f128 = try deserializer.deserialize(f128);
+ //const inf_check_f128 = try deserializer.deserialize(f128);
+ expect(std.math.isNan(nan_check_f16));
+ expect(std.math.isInf(inf_check_f16));
+ expect(std.math.isNan(nan_check_f32));
+ expect(std.math.isInf(inf_check_f32));
+ expect(std.math.isNan(nan_check_f64));
+ expect(std.math.isInf(inf_check_f64));
+ //expect(std.math.isNan(nan_check_f128));
+ //expect(std.math.isInf(inf_check_f128));
+}
+
+test "Serializer/Deserializer Int: Inf/NaN" {
+ try testIntSerializerDeserializerInfNaN(.Big, .Byte);
+ try testIntSerializerDeserializerInfNaN(.Little, .Byte);
+ try testIntSerializerDeserializerInfNaN(.Big, .Bit);
+ try testIntSerializerDeserializerInfNaN(.Little, .Bit);
+}
+
+fn testAlternateSerializer(self: var, serializer: var) !void {
+ try serializer.serialize(self.f_f16);
+}
+
+fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
+ const ColorType = enum(u4) {
+ RGB8 = 1,
+ RA16 = 2,
+ R32 = 3,
+ };
+
+ const TagAlign = union(enum(u32)) {
+ A: u8,
+ B: u8,
+ C: u8,
+ };
+
+ const Color = union(ColorType) {
+ RGB8: struct {
+ r: u8,
+ g: u8,
+ b: u8,
+ a: u8,
+ },
+ RA16: struct {
+ r: u16,
+ a: u16,
+ },
+ R32: u32,
+ };
+
+ const PackedStruct = packed struct {
+ f_i3: i3,
+ f_u2: u2,
+ };
+
+ //to test custom serialization
+ const Custom = struct {
+ f_f16: f16,
+ f_unused_u32: u32,
+
+ pub fn deserialize(self: *@This(), deserializer: var) !void {
+ try deserializer.deserializeInto(&self.f_f16);
+ self.f_unused_u32 = 47;
+ }
+
+ pub const serialize = testAlternateSerializer;
+ };
+
+ const MyStruct = struct {
+ f_i3: i3,
+ f_u8: u8,
+ f_tag_align: TagAlign,
+ f_u24: u24,
+ f_i19: i19,
+ f_void: void,
+ f_f32: f32,
+ f_f128: f128,
+ f_packed_0: PackedStruct,
+ f_i7arr: [10]i7,
+ f_of64n: ?f64,
+ f_of64v: ?f64,
+ f_color_type: ColorType,
+ f_packed_1: PackedStruct,
+ f_custom: Custom,
+ f_color: Color,
+ };
+
+ const my_inst = MyStruct{
+ .f_i3 = -1,
+ .f_u8 = 8,
+ .f_tag_align = TagAlign{ .B = 148 },
+ .f_u24 = 24,
+ .f_i19 = 19,
+ .f_void = {},
+ .f_f32 = 32.32,
+ .f_f128 = 128.128,
+ .f_packed_0 = PackedStruct{ .f_i3 = -1, .f_u2 = 2 },
+ .f_i7arr = [10]i7{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+ .f_of64n = null,
+ .f_of64v = 64.64,
+ .f_color_type = ColorType.R32,
+ .f_packed_1 = PackedStruct{ .f_i3 = 1, .f_u2 = 1 },
+ .f_custom = Custom{ .f_f16 = 38.63, .f_unused_u32 = 47 },
+ .f_color = Color{ .R32 = 123822 },
+ };
+
+ var data_mem: [@sizeOf(MyStruct)]u8 = undefined;
+ var out = io.fixedBufferStream(&data_mem);
+ var serializer = serializer(endian, packing, out.outStream());
+
+ var in = io.fixedBufferStream(&data_mem);
+ var deserializer = deserializer(endian, packing, in.inStream());
+
+ try serializer.serialize(my_inst);
+
+ const my_copy = try deserializer.deserialize(MyStruct);
+ expect(meta.eql(my_copy, my_inst));
+}
+
+test "Serializer/Deserializer generic" {
+ if (std.Target.current.os.tag == .windows) {
+ // TODO https://github.com/ziglang/zig/issues/508
+ return error.SkipZigTest;
+ }
+ try testSerializerDeserializer(builtin.Endian.Big, .Byte);
+ try testSerializerDeserializer(builtin.Endian.Little, .Byte);
+ try testSerializerDeserializer(builtin.Endian.Big, .Bit);
+ try testSerializerDeserializer(builtin.Endian.Little, .Bit);
+}
+
+fn testBadData(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
+ const E = enum(u14) {
+ One = 1,
+ Two = 2,
+ };
+
+ const A = struct {
+ e: E,
+ };
+
+ const C = union(E) {
+ One: u14,
+ Two: f16,
+ };
+
+ var data_mem: [4]u8 = undefined;
+ var out = io.fixedBufferStream.init(&data_mem);
+ var serializer = serializer(endian, packing, out.outStream());
+
+ var in = io.fixedBufferStream(&data_mem);
+ var deserializer = deserializer(endian, packing, in.inStream());
+
+ try serializer.serialize(@as(u14, 3));
+ expectError(error.InvalidEnumTag, deserializer.deserialize(A));
+ out.pos = 0;
+ try serializer.serialize(@as(u14, 3));
+ try serializer.serialize(@as(u14, 88));
+ expectError(error.InvalidEnumTag, deserializer.deserialize(C));
+}
+
+test "Deserializer bad data" {
+ try testBadData(.Big, .Byte);
+ try testBadData(.Little, .Byte);
+ try testBadData(.Big, .Bit);
+ try testBadData(.Little, .Bit);
+}
diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig
index 1ab0f8231..38dd2bb67 100644
--- a/lib/std/io/test.zig
+++ b/lib/std/io/test.zig
@@ -22,11 +22,10 @@ test "write a file, read it, then delete it" {
var file = try cwd.createFile(tmp_file_name, .{});
defer file.close();
- var file_out_stream = file.outStream();
- var buf_stream = io.BufferedOutStream(File.WriteError).init(&file_out_stream.stream);
- const st = &buf_stream.stream;
+ var buf_stream = io.bufferedOutStream(file.outStream());
+ const st = buf_stream.outStream();
try st.print("begin", .{});
- try st.write(data[0..]);
+ try st.writeAll(data[0..]);
try st.print("end", .{});
try buf_stream.flush();
}
@@ -48,9 +47,8 @@ test "write a file, read it, then delete it" {
const expected_file_size: u64 = "begin".len + data.len + "end".len;
expectEqual(expected_file_size, file_size);
- var file_in_stream = file.inStream();
- var buf_stream = io.BufferedInStream(File.ReadError).init(&file_in_stream.stream);
- const st = &buf_stream.stream;
+ var buf_stream = io.bufferedInStream(file.inStream());
+ const st = buf_stream.inStream();
const contents = try st.readAllAlloc(std.testing.allocator, 2 * 1024);
defer std.testing.allocator.free(contents);
@@ -61,224 +59,13 @@ test "write a file, read it, then delete it" {
try cwd.deleteFile(tmp_file_name);
}
-test "BufferOutStream" {
- var buffer = try std.Buffer.initSize(std.testing.allocator, 0);
- defer buffer.deinit();
- var buf_stream = &std.io.BufferOutStream.init(&buffer).stream;
-
- const x: i32 = 42;
- const y: i32 = 1234;
- try buf_stream.print("x: {}\ny: {}\n", .{ x, y });
-
- expect(mem.eql(u8, buffer.toSlice(), "x: 42\ny: 1234\n"));
-}
-
-test "SliceInStream" {
- const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7 };
- var ss = io.SliceInStream.init(&bytes);
-
- var dest: [4]u8 = undefined;
-
- var read = try ss.stream.read(dest[0..4]);
- expect(read == 4);
- expect(mem.eql(u8, dest[0..4], bytes[0..4]));
-
- read = try ss.stream.read(dest[0..4]);
- expect(read == 3);
- expect(mem.eql(u8, dest[0..3], bytes[4..7]));
-
- read = try ss.stream.read(dest[0..4]);
- expect(read == 0);
-}
-
-test "PeekStream" {
- const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
- var ss = io.SliceInStream.init(&bytes);
- var ps = io.PeekStream(.{ .Static = 2 }, io.SliceInStream.Error).init(&ss.stream);
-
- var dest: [4]u8 = undefined;
-
- try ps.putBackByte(9);
- try ps.putBackByte(10);
-
- var read = try ps.stream.read(dest[0..4]);
- expect(read == 4);
- expect(dest[0] == 10);
- expect(dest[1] == 9);
- expect(mem.eql(u8, dest[2..4], bytes[0..2]));
-
- read = try ps.stream.read(dest[0..4]);
- expect(read == 4);
- expect(mem.eql(u8, dest[0..4], bytes[2..6]));
-
- read = try ps.stream.read(dest[0..4]);
- expect(read == 2);
- expect(mem.eql(u8, dest[0..2], bytes[6..8]));
-
- try ps.putBackByte(11);
- try ps.putBackByte(12);
-
- read = try ps.stream.read(dest[0..4]);
- expect(read == 2);
- expect(dest[0] == 12);
- expect(dest[1] == 11);
-}
-
-test "SliceOutStream" {
- var buffer: [10]u8 = undefined;
- var ss = io.SliceOutStream.init(buffer[0..]);
-
- try ss.stream.write("Hello");
- expect(mem.eql(u8, ss.getWritten(), "Hello"));
-
- try ss.stream.write("world");
- expect(mem.eql(u8, ss.getWritten(), "Helloworld"));
-
- expectError(error.OutOfMemory, ss.stream.write("!"));
- expect(mem.eql(u8, ss.getWritten(), "Helloworld"));
-
- ss.reset();
- expect(ss.getWritten().len == 0);
-
- expectError(error.OutOfMemory, ss.stream.write("Hello world!"));
- expect(mem.eql(u8, ss.getWritten(), "Hello worl"));
-}
-
-test "BitInStream" {
- const mem_be = [_]u8{ 0b11001101, 0b00001011 };
- const mem_le = [_]u8{ 0b00011101, 0b10010101 };
-
- var mem_in_be = io.SliceInStream.init(mem_be[0..]);
- const InError = io.SliceInStream.Error;
- var bit_stream_be = io.BitInStream(builtin.Endian.Big, InError).init(&mem_in_be.stream);
-
- var out_bits: usize = undefined;
-
- expect(1 == try bit_stream_be.readBits(u2, 1, &out_bits));
- expect(out_bits == 1);
- expect(2 == try bit_stream_be.readBits(u5, 2, &out_bits));
- expect(out_bits == 2);
- expect(3 == try bit_stream_be.readBits(u128, 3, &out_bits));
- expect(out_bits == 3);
- expect(4 == try bit_stream_be.readBits(u8, 4, &out_bits));
- expect(out_bits == 4);
- expect(5 == try bit_stream_be.readBits(u9, 5, &out_bits));
- expect(out_bits == 5);
- expect(1 == try bit_stream_be.readBits(u1, 1, &out_bits));
- expect(out_bits == 1);
-
- mem_in_be.pos = 0;
- bit_stream_be.bit_count = 0;
- expect(0b110011010000101 == try bit_stream_be.readBits(u15, 15, &out_bits));
- expect(out_bits == 15);
-
- mem_in_be.pos = 0;
- bit_stream_be.bit_count = 0;
- expect(0b1100110100001011 == try bit_stream_be.readBits(u16, 16, &out_bits));
- expect(out_bits == 16);
-
- _ = try bit_stream_be.readBits(u0, 0, &out_bits);
-
- expect(0 == try bit_stream_be.readBits(u1, 1, &out_bits));
- expect(out_bits == 0);
- expectError(error.EndOfStream, bit_stream_be.readBitsNoEof(u1, 1));
-
- var mem_in_le = io.SliceInStream.init(mem_le[0..]);
- var bit_stream_le = io.BitInStream(builtin.Endian.Little, InError).init(&mem_in_le.stream);
-
- expect(1 == try bit_stream_le.readBits(u2, 1, &out_bits));
- expect(out_bits == 1);
- expect(2 == try bit_stream_le.readBits(u5, 2, &out_bits));
- expect(out_bits == 2);
- expect(3 == try bit_stream_le.readBits(u128, 3, &out_bits));
- expect(out_bits == 3);
- expect(4 == try bit_stream_le.readBits(u8, 4, &out_bits));
- expect(out_bits == 4);
- expect(5 == try bit_stream_le.readBits(u9, 5, &out_bits));
- expect(out_bits == 5);
- expect(1 == try bit_stream_le.readBits(u1, 1, &out_bits));
- expect(out_bits == 1);
-
- mem_in_le.pos = 0;
- bit_stream_le.bit_count = 0;
- expect(0b001010100011101 == try bit_stream_le.readBits(u15, 15, &out_bits));
- expect(out_bits == 15);
-
- mem_in_le.pos = 0;
- bit_stream_le.bit_count = 0;
- expect(0b1001010100011101 == try bit_stream_le.readBits(u16, 16, &out_bits));
- expect(out_bits == 16);
-
- _ = try bit_stream_le.readBits(u0, 0, &out_bits);
-
- expect(0 == try bit_stream_le.readBits(u1, 1, &out_bits));
- expect(out_bits == 0);
- expectError(error.EndOfStream, bit_stream_le.readBitsNoEof(u1, 1));
-}
-
-test "BitOutStream" {
- var mem_be = [_]u8{0} ** 2;
- var mem_le = [_]u8{0} ** 2;
-
- var mem_out_be = io.SliceOutStream.init(mem_be[0..]);
- const OutError = io.SliceOutStream.Error;
- var bit_stream_be = io.BitOutStream(builtin.Endian.Big, OutError).init(&mem_out_be.stream);
-
- try bit_stream_be.writeBits(@as(u2, 1), 1);
- try bit_stream_be.writeBits(@as(u5, 2), 2);
- try bit_stream_be.writeBits(@as(u128, 3), 3);
- try bit_stream_be.writeBits(@as(u8, 4), 4);
- try bit_stream_be.writeBits(@as(u9, 5), 5);
- try bit_stream_be.writeBits(@as(u1, 1), 1);
-
- expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001011);
-
- mem_out_be.pos = 0;
-
- try bit_stream_be.writeBits(@as(u15, 0b110011010000101), 15);
- try bit_stream_be.flushBits();
- expect(mem_be[0] == 0b11001101 and mem_be[1] == 0b00001010);
-
- mem_out_be.pos = 0;
- try bit_stream_be.writeBits(@as(u32, 0b110011010000101), 16);
- expect(mem_be[0] == 0b01100110 and mem_be[1] == 0b10000101);
-
- try bit_stream_be.writeBits(@as(u0, 0), 0);
-
- var mem_out_le = io.SliceOutStream.init(mem_le[0..]);
- var bit_stream_le = io.BitOutStream(builtin.Endian.Little, OutError).init(&mem_out_le.stream);
-
- try bit_stream_le.writeBits(@as(u2, 1), 1);
- try bit_stream_le.writeBits(@as(u5, 2), 2);
- try bit_stream_le.writeBits(@as(u128, 3), 3);
- try bit_stream_le.writeBits(@as(u8, 4), 4);
- try bit_stream_le.writeBits(@as(u9, 5), 5);
- try bit_stream_le.writeBits(@as(u1, 1), 1);
-
- expect(mem_le[0] == 0b00011101 and mem_le[1] == 0b10010101);
-
- mem_out_le.pos = 0;
- try bit_stream_le.writeBits(@as(u15, 0b110011010000101), 15);
- try bit_stream_le.flushBits();
- expect(mem_le[0] == 0b10000101 and mem_le[1] == 0b01100110);
-
- mem_out_le.pos = 0;
- try bit_stream_le.writeBits(@as(u32, 0b1100110100001011), 16);
- expect(mem_le[0] == 0b00001011 and mem_le[1] == 0b11001101);
-
- try bit_stream_le.writeBits(@as(u0, 0), 0);
-}
-
test "BitStreams with File Stream" {
const tmp_file_name = "temp_test_file.txt";
{
var file = try fs.cwd().createFile(tmp_file_name, .{});
defer file.close();
- var file_out = file.outStream();
- var file_out_stream = &file_out.stream;
- const OutError = File.WriteError;
- var bit_stream = io.BitOutStream(builtin.endian, OutError).init(file_out_stream);
+ var bit_stream = io.bitOutStream(builtin.endian, file.outStream());
try bit_stream.writeBits(@as(u2, 1), 1);
try bit_stream.writeBits(@as(u5, 2), 2);
@@ -292,10 +79,7 @@ test "BitStreams with File Stream" {
var file = try fs.cwd().openFile(tmp_file_name, .{});
defer file.close();
- var file_in = file.inStream();
- var file_in_stream = &file_in.stream;
- const InError = File.ReadError;
- var bit_stream = io.BitInStream(builtin.endian, InError).init(file_in_stream);
+ var bit_stream = io.bitInStream(builtin.endian, file.inStream());
var out_bits: usize = undefined;
@@ -317,298 +101,6 @@ test "BitStreams with File Stream" {
try fs.cwd().deleteFile(tmp_file_name);
}
-fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
- @setEvalBranchQuota(1500);
- //@NOTE: if this test is taking too long, reduce the maximum tested bitsize
- const max_test_bitsize = 128;
-
- const total_bytes = comptime blk: {
- var bytes = 0;
- comptime var i = 0;
- while (i <= max_test_bitsize) : (i += 1) bytes += (i / 8) + @boolToInt(i % 8 > 0);
- break :blk bytes * 2;
- };
-
- var data_mem: [total_bytes]u8 = undefined;
- var out = io.SliceOutStream.init(data_mem[0..]);
- const OutError = io.SliceOutStream.Error;
- var out_stream = &out.stream;
- var serializer = io.Serializer(endian, packing, OutError).init(out_stream);
-
- var in = io.SliceInStream.init(data_mem[0..]);
- const InError = io.SliceInStream.Error;
- var in_stream = &in.stream;
- var deserializer = io.Deserializer(endian, packing, InError).init(in_stream);
-
- comptime var i = 0;
- inline while (i <= max_test_bitsize) : (i += 1) {
- const U = std.meta.IntType(false, i);
- const S = std.meta.IntType(true, i);
- try serializer.serializeInt(@as(U, i));
- if (i != 0) try serializer.serializeInt(@as(S, -1)) else try serializer.serialize(@as(S, 0));
- }
- try serializer.flush();
-
- i = 0;
- inline while (i <= max_test_bitsize) : (i += 1) {
- const U = std.meta.IntType(false, i);
- const S = std.meta.IntType(true, i);
- const x = try deserializer.deserializeInt(U);
- const y = try deserializer.deserializeInt(S);
- expect(x == @as(U, i));
- if (i != 0) expect(y == @as(S, -1)) else expect(y == 0);
- }
-
- const u8_bit_count = comptime meta.bitCount(u8);
- //0 + 1 + 2 + ... n = (n * (n + 1)) / 2
- //and we have each for unsigned and signed, so * 2
- const total_bits = (max_test_bitsize * (max_test_bitsize + 1));
- const extra_packed_byte = @boolToInt(total_bits % u8_bit_count > 0);
- const total_packed_bytes = (total_bits / u8_bit_count) + extra_packed_byte;
-
- expect(in.pos == if (packing == .Bit) total_packed_bytes else total_bytes);
-
- //Verify that empty error set works with serializer.
- //deserializer is covered by SliceInStream
- const NullError = io.NullOutStream.Error;
- var null_out = io.NullOutStream.init();
- var null_out_stream = &null_out.stream;
- var null_serializer = io.Serializer(endian, packing, NullError).init(null_out_stream);
- try null_serializer.serialize(data_mem[0..]);
- try null_serializer.flush();
-}
-
-test "Serializer/Deserializer Int" {
- try testIntSerializerDeserializer(.Big, .Byte);
- try testIntSerializerDeserializer(.Little, .Byte);
- // TODO these tests are disabled due to tripping an LLVM assertion
- // https://github.com/ziglang/zig/issues/2019
- //try testIntSerializerDeserializer(builtin.Endian.Big, true);
- //try testIntSerializerDeserializer(builtin.Endian.Little, true);
-}
-
-fn testIntSerializerDeserializerInfNaN(
- comptime endian: builtin.Endian,
- comptime packing: io.Packing,
-) !void {
- const mem_size = (16 * 2 + 32 * 2 + 64 * 2 + 128 * 2) / comptime meta.bitCount(u8);
- var data_mem: [mem_size]u8 = undefined;
-
- var out = io.SliceOutStream.init(data_mem[0..]);
- const OutError = io.SliceOutStream.Error;
- var out_stream = &out.stream;
- var serializer = io.Serializer(endian, packing, OutError).init(out_stream);
-
- var in = io.SliceInStream.init(data_mem[0..]);
- const InError = io.SliceInStream.Error;
- var in_stream = &in.stream;
- var deserializer = io.Deserializer(endian, packing, InError).init(in_stream);
-
- //@TODO: isInf/isNan not currently implemented for f128.
- try serializer.serialize(std.math.nan(f16));
- try serializer.serialize(std.math.inf(f16));
- try serializer.serialize(std.math.nan(f32));
- try serializer.serialize(std.math.inf(f32));
- try serializer.serialize(std.math.nan(f64));
- try serializer.serialize(std.math.inf(f64));
- //try serializer.serialize(std.math.nan(f128));
- //try serializer.serialize(std.math.inf(f128));
- const nan_check_f16 = try deserializer.deserialize(f16);
- const inf_check_f16 = try deserializer.deserialize(f16);
- const nan_check_f32 = try deserializer.deserialize(f32);
- deserializer.alignToByte();
- const inf_check_f32 = try deserializer.deserialize(f32);
- const nan_check_f64 = try deserializer.deserialize(f64);
- const inf_check_f64 = try deserializer.deserialize(f64);
- //const nan_check_f128 = try deserializer.deserialize(f128);
- //const inf_check_f128 = try deserializer.deserialize(f128);
- expect(std.math.isNan(nan_check_f16));
- expect(std.math.isInf(inf_check_f16));
- expect(std.math.isNan(nan_check_f32));
- expect(std.math.isInf(inf_check_f32));
- expect(std.math.isNan(nan_check_f64));
- expect(std.math.isInf(inf_check_f64));
- //expect(std.math.isNan(nan_check_f128));
- //expect(std.math.isInf(inf_check_f128));
-}
-
-test "Serializer/Deserializer Int: Inf/NaN" {
- try testIntSerializerDeserializerInfNaN(.Big, .Byte);
- try testIntSerializerDeserializerInfNaN(.Little, .Byte);
- try testIntSerializerDeserializerInfNaN(.Big, .Bit);
- try testIntSerializerDeserializerInfNaN(.Little, .Bit);
-}
-
-fn testAlternateSerializer(self: var, serializer: var) !void {
- try serializer.serialize(self.f_f16);
-}
-
-fn testSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
- const ColorType = enum(u4) {
- RGB8 = 1,
- RA16 = 2,
- R32 = 3,
- };
-
- const TagAlign = union(enum(u32)) {
- A: u8,
- B: u8,
- C: u8,
- };
-
- const Color = union(ColorType) {
- RGB8: struct {
- r: u8,
- g: u8,
- b: u8,
- a: u8,
- },
- RA16: struct {
- r: u16,
- a: u16,
- },
- R32: u32,
- };
-
- const PackedStruct = packed struct {
- f_i3: i3,
- f_u2: u2,
- };
-
- //to test custom serialization
- const Custom = struct {
- f_f16: f16,
- f_unused_u32: u32,
-
- pub fn deserialize(self: *@This(), deserializer: var) !void {
- try deserializer.deserializeInto(&self.f_f16);
- self.f_unused_u32 = 47;
- }
-
- pub const serialize = testAlternateSerializer;
- };
-
- const MyStruct = struct {
- f_i3: i3,
- f_u8: u8,
- f_tag_align: TagAlign,
- f_u24: u24,
- f_i19: i19,
- f_void: void,
- f_f32: f32,
- f_f128: f128,
- f_packed_0: PackedStruct,
- f_i7arr: [10]i7,
- f_of64n: ?f64,
- f_of64v: ?f64,
- f_color_type: ColorType,
- f_packed_1: PackedStruct,
- f_custom: Custom,
- f_color: Color,
- };
-
- const my_inst = MyStruct{
- .f_i3 = -1,
- .f_u8 = 8,
- .f_tag_align = TagAlign{ .B = 148 },
- .f_u24 = 24,
- .f_i19 = 19,
- .f_void = {},
- .f_f32 = 32.32,
- .f_f128 = 128.128,
- .f_packed_0 = PackedStruct{ .f_i3 = -1, .f_u2 = 2 },
- .f_i7arr = [10]i7{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
- .f_of64n = null,
- .f_of64v = 64.64,
- .f_color_type = ColorType.R32,
- .f_packed_1 = PackedStruct{ .f_i3 = 1, .f_u2 = 1 },
- .f_custom = Custom{ .f_f16 = 38.63, .f_unused_u32 = 47 },
- .f_color = Color{ .R32 = 123822 },
- };
-
- var data_mem: [@sizeOf(MyStruct)]u8 = undefined;
- var out = io.SliceOutStream.init(data_mem[0..]);
- const OutError = io.SliceOutStream.Error;
- var out_stream = &out.stream;
- var serializer = io.Serializer(endian, packing, OutError).init(out_stream);
-
- var in = io.SliceInStream.init(data_mem[0..]);
- const InError = io.SliceInStream.Error;
- var in_stream = &in.stream;
- var deserializer = io.Deserializer(endian, packing, InError).init(in_stream);
-
- try serializer.serialize(my_inst);
-
- const my_copy = try deserializer.deserialize(MyStruct);
- expect(meta.eql(my_copy, my_inst));
-}
-
-test "Serializer/Deserializer generic" {
- if (std.Target.current.os.tag == .windows) {
- // TODO https://github.com/ziglang/zig/issues/508
- return error.SkipZigTest;
- }
- try testSerializerDeserializer(builtin.Endian.Big, .Byte);
- try testSerializerDeserializer(builtin.Endian.Little, .Byte);
- try testSerializerDeserializer(builtin.Endian.Big, .Bit);
- try testSerializerDeserializer(builtin.Endian.Little, .Bit);
-}
-
-fn testBadData(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
- const E = enum(u14) {
- One = 1,
- Two = 2,
- };
-
- const A = struct {
- e: E,
- };
-
- const C = union(E) {
- One: u14,
- Two: f16,
- };
-
- var data_mem: [4]u8 = undefined;
- var out = io.SliceOutStream.init(data_mem[0..]);
- const OutError = io.SliceOutStream.Error;
- var out_stream = &out.stream;
- var serializer = io.Serializer(endian, packing, OutError).init(out_stream);
-
- var in = io.SliceInStream.init(data_mem[0..]);
- const InError = io.SliceInStream.Error;
- var in_stream = &in.stream;
- var deserializer = io.Deserializer(endian, packing, InError).init(in_stream);
-
- try serializer.serialize(@as(u14, 3));
- expectError(error.InvalidEnumTag, deserializer.deserialize(A));
- out.pos = 0;
- try serializer.serialize(@as(u14, 3));
- try serializer.serialize(@as(u14, 88));
- expectError(error.InvalidEnumTag, deserializer.deserialize(C));
-}
-
-test "Deserializer bad data" {
- try testBadData(.Big, .Byte);
- try testBadData(.Little, .Byte);
- try testBadData(.Big, .Bit);
- try testBadData(.Little, .Bit);
-}
-
-test "c out stream" {
- if (!builtin.link_libc) return error.SkipZigTest;
-
- const filename = "tmp_io_test_file.txt";
- const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
- defer {
- _ = std.c.fclose(out_file);
- fs.cwd().deleteFileC(filename) catch {};
- }
-
- const out_stream = &io.COutStream.init(out_file).stream;
- try out_stream.print("hi: {}\n", .{@as(i32, 123)});
-}
-
test "File seek ops" {
const tmp_file_name = "temp_test_file.txt";
var file = try fs.cwd().createFile(tmp_file_name, .{});
@@ -621,16 +113,16 @@ test "File seek ops" {
// Seek to the end
try file.seekFromEnd(0);
- std.testing.expect((try file.getPos()) == try file.getEndPos());
+ expect((try file.getPos()) == try file.getEndPos());
// Negative delta
try file.seekBy(-4096);
- std.testing.expect((try file.getPos()) == 4096);
+ expect((try file.getPos()) == 4096);
// Positive delta
try file.seekBy(10);
- std.testing.expect((try file.getPos()) == 4106);
+ expect((try file.getPos()) == 4106);
// Absolute position
try file.seekTo(1234);
- std.testing.expect((try file.getPos()) == 1234);
+ expect((try file.getPos()) == 1234);
}
test "updateTimes" {
@@ -647,6 +139,6 @@ test "updateTimes" {
stat_old.mtime - 5 * std.time.ns_per_s,
);
var stat_new = try file.stat();
- std.testing.expect(stat_new.atime < stat_old.atime);
- std.testing.expect(stat_new.mtime < stat_old.mtime);
+ expect(stat_new.atime < stat_old.atime);
+ expect(stat_new.mtime < stat_old.mtime);
}
diff --git a/lib/std/json.zig b/lib/std/json.zig
index f2cf68d7e..4e2440d4e 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -10,6 +10,7 @@ const mem = std.mem;
const maxInt = std.math.maxInt;
pub const WriteStream = @import("json/write_stream.zig").WriteStream;
+pub const writeStream = @import("json/write_stream.zig").writeStream;
const StringEscapes = union(enum) {
None,
@@ -2109,7 +2110,7 @@ test "write json then parse it" {
var fixed_buffer_stream = std.io.fixedBufferStream(&out_buffer);
const out_stream = fixed_buffer_stream.outStream();
- var jw = WriteStream(@TypeOf(out_stream).Child, 4).init(out_stream);
+ var jw = writeStream(out_stream, 4);
try jw.beginObject();
@@ -2140,7 +2141,7 @@ test "write json then parse it" {
var parser = Parser.init(testing.allocator, false);
defer parser.deinit();
- var tree = try parser.parse(slice_out_stream.getWritten());
+ var tree = try parser.parse(fixed_buffer_stream.getWritten());
defer tree.deinit();
testing.expect(tree.root.Object.get("f").?.value.Bool == false);
diff --git a/lib/std/json/write_stream.zig b/lib/std/json/write_stream.zig
index 6d88c8b6d..f4d171011 100644
--- a/lib/std/json/write_stream.zig
+++ b/lib/std/json/write_stream.zig
@@ -249,15 +249,22 @@ pub fn WriteStream(comptime OutStream: type, comptime max_depth: usize) type {
};
}
+pub fn writeStream(
+ out_stream: var,
+ comptime max_depth: usize,
+) WriteStream(@TypeOf(out_stream), max_depth) {
+ return WriteStream(@TypeOf(out_stream), max_depth).init(out_stream);
+}
+
test "json write stream" {
var out_buf: [1024]u8 = undefined;
- var slice_stream = std.io.SliceOutStream.init(&out_buf);
- const out = &slice_stream.stream;
+ var slice_stream = std.io.fixedBufferStream(&out_buf);
+ const out = slice_stream.outStream();
var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
defer arena_allocator.deinit();
- var w = std.json.WriteStream(@TypeOf(out).Child, 10).init(out);
+ var w = std.json.writeStream(out, 10);
try w.emitJson(try getJson(&arena_allocator.allocator));
const result = slice_stream.getWritten();
diff --git a/lib/std/net.zig b/lib/std/net.zig
index 6d0daefdc..de10a1764 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -816,7 +816,7 @@ fn linuxLookupNameFromHosts(
};
defer file.close();
- const stream = &std.io.BufferedInStream(fs.File.ReadError).init(&file.inStream().stream).stream;
+ const stream = std.io.bufferedInStream(file.inStream()).inStream();
var line_buf: [512]u8 = undefined;
while (stream.readUntilDelimiterOrEof(&line_buf, '\n') catch |err| switch (err) {
error.StreamTooLong => blk: {
@@ -1010,7 +1010,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
};
defer file.close();
- const stream = &std.io.BufferedInStream(fs.File.ReadError).init(&file.inStream().stream).stream;
+ const stream = std.io.bufferedInStream(file.inStream()).inStream();
var line_buf: [512]u8 = undefined;
while (stream.readUntilDelimiterOrEof(&line_buf, '\n') catch |err| switch (err) {
error.StreamTooLong => blk: {
diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig
index 5f9759753..75a6d5db9 100644
--- a/lib/std/os/test.zig
+++ b/lib/std/os/test.zig
@@ -354,8 +354,7 @@ test "mmap" {
const file = try fs.cwd().createFile(test_out_file, .{});
defer file.close();
- var out_stream = file.outStream();
- const stream = &out_stream.stream;
+ const stream = file.outStream();
var i: u32 = 0;
while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
@@ -378,8 +377,8 @@ test "mmap" {
);
defer os.munmap(data);
- var mem_stream = io.SliceInStream.init(data);
- const stream = &mem_stream.stream;
+ var mem_stream = io.fixedBufferStream(data);
+ const stream = mem_stream.inStream();
var i: u32 = 0;
while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
@@ -402,8 +401,8 @@ test "mmap" {
);
defer os.munmap(data);
- var mem_stream = io.SliceInStream.init(data);
- const stream = &mem_stream.stream;
+ var mem_stream = io.fixedBufferStream(data);
+ const stream = mem_stream.inStream();
var i: u32 = alloc_size / 2 / @sizeOf(u32);
while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index ddea0fc57..d00568e49 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -2809,7 +2809,7 @@ const maxInt = std.math.maxInt;
var fixed_buffer_mem: [100 * 1024]u8 = undefined;
fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 {
- const stderr = &io.getStdErr().outStream().stream;
+ const stderr = io.getStdErr().outStream();
const tree = try std.zig.parse(allocator, source);
defer tree.deinit();
@@ -2824,17 +2824,17 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
{
var i: usize = 0;
while (i < loc.column) : (i += 1) {
- try stderr.write(" ");
+ try stderr.writeAll(" ");
}
}
{
const caret_count = token.end - token.start;
var i: usize = 0;
while (i < caret_count) : (i += 1) {
- try stderr.write("~");
+ try stderr.writeAll("~");
}
}
- try stderr.write("\n");
+ try stderr.writeAll("\n");
}
if (tree.errors.len != 0) {
return error.ParseError;
@@ -2843,8 +2843,7 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b
var buffer = try std.Buffer.initSize(allocator, 0);
errdefer buffer.deinit();
- var buffer_out_stream = io.BufferOutStream.init(&buffer);
- anything_changed.* = try std.zig.render(allocator, &buffer_out_stream.stream, tree);
+ anything_changed.* = try std.zig.render(allocator, buffer.outStream(), tree);
return buffer.toOwnedSlice();
}
diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig
index 9600de21d..1a221bd5b 100644
--- a/lib/std/zig/render.zig
+++ b/lib/std/zig/render.zig
@@ -903,7 +903,7 @@ fn renderExpression(
var column_widths = widths[widths.len - row_size ..];
// Null stream for counting the printed length of each expression
- var counting_stream = std.io.CountingOutStream(@TypeOf(std.io.null_out_stream)).init(std.io.null_out_stream);
+ var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
var it = exprs.iterator(0);
var i: usize = 0;
From 2f1052a313cb09f87f04cef56805c33be62eb169 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Tue, 10 Mar 2020 23:50:04 +0100
Subject: [PATCH 044/111] std: Fix broken tests
---
lib/std/io.zig | 10 ++++++++--
lib/std/mem.zig | 8 +++++++-
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/lib/std/io.zig b/lib/std/io.zig
index 99e9391f1..f823eb811 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -350,12 +350,18 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type {
switch (endian) {
.Big => {
out_buffer = @as(Buf, self.bit_buffer >> shift);
- self.bit_buffer <<= n;
+ if (n >= u7_bit_count)
+ self.bit_buffer = 0
+ else
+ self.bit_buffer <<= n;
},
.Little => {
const value = (self.bit_buffer << shift) >> shift;
out_buffer = @as(Buf, value);
- self.bit_buffer >>= n;
+ if (n >= u7_bit_count)
+ self.bit_buffer = 0
+ else
+ self.bit_buffer >>= n;
},
}
self.bit_count -= n;
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 4da782957..bee38a30f 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -921,6 +921,9 @@ pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value:
pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
assert(buffer.len >= @divExact(T.bit_count, 8));
+ if (T.bit_count == 0)
+ return set(u8, buffer, 0);
+
// TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough
const uint = std.meta.IntType(false, T.bit_count);
var bits = @truncate(uint, value);
@@ -938,6 +941,9 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
assert(buffer.len >= @divExact(T.bit_count, 8));
+ if (T.bit_count == 0)
+ return set(u8, buffer, 0);
+
// TODO I want to call writeIntBig here but comptime eval facilities aren't good enough
const uint = std.meta.IntType(false, T.bit_count);
var bits = @truncate(uint, value);
@@ -1807,7 +1813,7 @@ test "sliceAsBytes" {
}
test "sliceAsBytes with sentinel slice" {
- const empty_string:[:0]const u8 = "";
+ const empty_string: [:0]const u8 = "";
const bytes = sliceAsBytes(empty_string);
testing.expect(bytes.len == 0);
}
From cd26d3b0bb2b32f1daf1d3d46bb53731dd54afec Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 18:54:24 -0400
Subject: [PATCH 045/111] fix regressions caused earlier in this branch
---
lib/std/debug.zig | 11 +++++++++--
lib/std/io/fixed_buffer_stream.zig | 3 +--
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 5c5649051..b27b1caa6 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -825,8 +825,15 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !M
const shoff = hdr.e_shoff;
const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx);
- const header_strings = mapped_mem[str_section_off..str_section_off + hdr.e_shentsize];
- const shdrs = @ptrCast([*]const elf.Shdr, @alignCast(@alignOf(elf.Shdr), &mapped_mem[shoff]))[0..hdr.e_shnum];
+ const str_shdr = @ptrCast(
+ *const elf.Shdr,
+ @alignCast(@alignOf(elf.Shdr), &mapped_mem[str_section_off]),
+ );
+ const header_strings = mapped_mem[str_shdr.sh_offset .. str_shdr.sh_offset + str_shdr.sh_size];
+ const shdrs = @ptrCast(
+ [*]const elf.Shdr,
+ @alignCast(@alignOf(elf.Shdr), &mapped_mem[shoff]),
+ )[0..hdr.e_shnum];
var opt_debug_info: ?[]const u8 = null;
var opt_debug_abbrev: ?[]const u8 = null;
diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig
index 9cdad7dc5..0f2b54220 100644
--- a/lib/std/io/fixed_buffer_stream.zig
+++ b/lib/std/io/fixed_buffer_stream.zig
@@ -164,6 +164,5 @@ test "FixedBufferStream input" {
testing.expect(read == 3);
testing.expect(mem.eql(u8, dest[0..3], bytes[4..7]));
- read = try fbs.inStream().read(dest[0..4]);
- testing.expect(read == 0);
+ testing.expectError(error.EndOfStream, fbs.inStream().read(dest[0..4]));
}
From 9abee660dce3b43b9ac3b8260fbf269532d6c7f5 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 19:28:05 -0400
Subject: [PATCH 046/111] fix stack trace code not opening files in forced
blocking mode
---
lib/std/debug.zig | 4 +++-
lib/std/event/group.zig | 4 +++-
lib/std/event/lock.zig | 3 +++
lib/std/net/test.zig | 2 +-
4 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index b27b1caa6..e849d72bc 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -964,7 +964,9 @@ fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !M
}
fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
- var f = try fs.cwd().openFile(line_info.file_name, .{});
+ // Need this to always block even in async I/O mode, because this could potentially
+ // be called from e.g. the event loop code crashing.
+ var f = try fs.cwd().openFile(line_info.file_name, .{ .always_blocking = true });
defer f.close();
// TODO fstat and make sure that the file has the correct size
diff --git a/lib/std/event/group.zig b/lib/std/event/group.zig
index ac1bf6824..5eebb7ffb 100644
--- a/lib/std/event/group.zig
+++ b/lib/std/event/group.zig
@@ -120,9 +120,11 @@ test "std.event.Group" {
// https://github.com/ziglang/zig/issues/1908
if (builtin.single_threaded) return error.SkipZigTest;
- // TODO provide a way to run tests in evented I/O mode
if (!std.io.is_async) return error.SkipZigTest;
+ // TODO this file has bit-rotted. repair it
+ if (true) return error.SkipZigTest;
+
const handle = async testGroup(std.heap.page_allocator);
}
diff --git a/lib/std/event/lock.zig b/lib/std/event/lock.zig
index b9cbb5d95..1bb51261d 100644
--- a/lib/std/event/lock.zig
+++ b/lib/std/event/lock.zig
@@ -125,6 +125,9 @@ test "std.event.Lock" {
// TODO https://github.com/ziglang/zig/issues/3251
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
+ // TODO this file has bit-rotted. repair it
+ if (true) return error.SkipZigTest;
+
var lock = Lock.init();
defer lock.deinit();
diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig
index 4f3d955f3..087f965c4 100644
--- a/lib/std/net/test.zig
+++ b/lib/std/net/test.zig
@@ -113,6 +113,6 @@ fn testClient(addr: net.Address) anyerror!void {
fn testServer(server: *net.StreamServer) anyerror!void {
var client = try server.accept();
- const stream = &client.file.outStream().stream;
+ const stream = client.file.outStream();
try stream.print("hello from server\n", .{});
}
From 2bff0dda795cd84e4da59652736b7cfa7e1c964c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 20:22:30 -0400
Subject: [PATCH 047/111] fix regressions found by test suite
---
doc/docgen.zig | 95 +++++++++++++--------------
doc/langref.html.in | 2 +-
lib/std/build.zig | 3 +-
lib/std/build/run.zig | 6 +-
lib/std/coff.zig | 15 ++---
lib/std/debug.zig | 38 +++++------
lib/std/pdb.zig | 14 ++--
lib/std/special/build_runner.zig | 8 +--
test/compare_output.zig | 34 +++++-----
test/standalone/guess_number/main.zig | 2 +-
test/tests.zig | 14 ++--
11 files changed, 103 insertions(+), 128 deletions(-)
diff --git a/doc/docgen.zig b/doc/docgen.zig
index 319d9e003..4d2625f54 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -40,12 +40,9 @@ pub fn main() !void {
var out_file = try fs.cwd().createFile(out_file_name, .{});
defer out_file.close();
- var file_in_stream = in_file.inStream();
+ const input_file_bytes = try in_file.inStream().readAllAlloc(allocator, max_doc_file_size);
- const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);
-
- var file_out_stream = out_file.outStream();
- var buffered_out_stream = io.BufferedOutStream(fs.File.WriteError).init(&file_out_stream.stream);
+ var buffered_out_stream = io.bufferedOutStream(out_file.outStream());
var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
var toc = try genToc(allocator, &tokenizer);
@@ -53,7 +50,7 @@ pub fn main() !void {
try fs.cwd().makePath(tmp_dir_name);
defer fs.deleteTree(tmp_dir_name) catch {};
- try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);
+ try genHtml(allocator, &tokenizer, &toc, buffered_out_stream.outStream(), zig_exe);
try buffered_out_stream.flush();
}
@@ -327,8 +324,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
var toc_buf = try std.Buffer.initSize(allocator, 0);
defer toc_buf.deinit();
- var toc_buf_adapter = io.BufferOutStream.init(&toc_buf);
- var toc = &toc_buf_adapter.stream;
+ var toc = toc_buf.outStream();
var nodes = std.ArrayList(Node).init(allocator);
defer nodes.deinit();
@@ -342,7 +338,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
if (header_stack_size != 0) {
return parseError(tokenizer, token, "unbalanced headers", .{});
}
- try toc.write(" \n");
+ try toc.writeAll(" \n");
break;
},
Token.Id.Content => {
@@ -407,7 +403,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
if (last_columns) |n| {
try toc.print("\n", .{n});
} else {
- try toc.write("\n");
+ try toc.writeAll("\n");
}
} else {
last_action = Action.Open;
@@ -424,9 +420,9 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
if (last_action == Action.Close) {
try toc.writeByteNTimes(' ', 8 + header_stack_size * 4);
- try toc.write("
\n");
+ try toc.writeAll("
\n");
} else {
- try toc.write("\n");
+ try toc.writeAll("\n");
last_action = Action.Close;
}
} else if (mem.eql(u8, tag_name, "see_also")) {
@@ -614,8 +610,7 @@ fn urlize(allocator: *mem.Allocator, input: []const u8) ![]u8 {
var buf = try std.Buffer.initSize(allocator, 0);
defer buf.deinit();
- var buf_adapter = io.BufferOutStream.init(&buf);
- var out = &buf_adapter.stream;
+ const out = buf.outStream();
for (input) |c| {
switch (c) {
'a'...'z', 'A'...'Z', '_', '-', '0'...'9' => {
@@ -634,8 +629,7 @@ fn escapeHtml(allocator: *mem.Allocator, input: []const u8) ![]u8 {
var buf = try std.Buffer.initSize(allocator, 0);
defer buf.deinit();
- var buf_adapter = io.BufferOutStream.init(&buf);
- var out = &buf_adapter.stream;
+ const out = buf.outStream();
try writeEscaped(out, input);
return buf.toOwnedSlice();
}
@@ -643,10 +637,10 @@ fn escapeHtml(allocator: *mem.Allocator, input: []const u8) ![]u8 {
fn writeEscaped(out: var, input: []const u8) !void {
for (input) |c| {
try switch (c) {
- '&' => out.write("&"),
- '<' => out.write("<"),
- '>' => out.write(">"),
- '"' => out.write("""),
+ '&' => out.writeAll("&"),
+ '<' => out.writeAll("<"),
+ '>' => out.writeAll(">"),
+ '"' => out.writeAll("""),
else => out.writeByte(c),
};
}
@@ -681,8 +675,7 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
var buf = try std.Buffer.initSize(allocator, 0);
defer buf.deinit();
- var buf_adapter = io.BufferOutStream.init(&buf);
- var out = &buf_adapter.stream;
+ var out = buf.outStream();
var number_start_index: usize = undefined;
var first_number: usize = undefined;
var second_number: usize = undefined;
@@ -743,7 +736,7 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 {
'm' => {
state = TermState.Start;
while (open_span_count != 0) : (open_span_count -= 1) {
- try out.write("");
+ try out.writeAll("");
}
if (first_number != 0 or second_number != 0) {
try out.print("", .{ first_number, second_number });
@@ -774,7 +767,7 @@ fn isType(name: []const u8) bool {
fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Token, raw_src: []const u8) !void {
const src = mem.trim(u8, raw_src, " \n");
- try out.write("");
+ try out.writeAll("");
var tokenizer = std.zig.Tokenizer.init(src);
var index: usize = 0;
var next_tok_is_fn = false;
@@ -835,15 +828,15 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
.Keyword_allowzero,
.Keyword_while,
=> {
- try out.write("");
+ try out.writeAll("");
try writeEscaped(out, src[token.start..token.end]);
- try out.write("");
+ try out.writeAll("");
},
.Keyword_fn => {
- try out.write("");
+ try out.writeAll("");
try writeEscaped(out, src[token.start..token.end]);
- try out.write("");
+ try out.writeAll("");
next_tok_is_fn = true;
},
@@ -852,24 +845,24 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
.Keyword_true,
.Keyword_false,
=> {
- try out.write("");
+ try out.writeAll("");
try writeEscaped(out, src[token.start..token.end]);
- try out.write("");
+ try out.writeAll("");
},
.StringLiteral,
.MultilineStringLiteralLine,
.CharLiteral,
=> {
- try out.write("");
+ try out.writeAll("");
try writeEscaped(out, src[token.start..token.end]);
- try out.write("");
+ try out.writeAll("");
},
.Builtin => {
- try out.write("");
+ try out.writeAll("");
try writeEscaped(out, src[token.start..token.end]);
- try out.write("");
+ try out.writeAll("");
},
.LineComment,
@@ -877,16 +870,16 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
.ContainerDocComment,
.ShebangLine,
=> {
- try out.write("");
},
.Identifier => {
if (prev_tok_was_fn) {
- try out.write("");
+ try out.writeAll("");
try writeEscaped(out, src[token.start..token.end]);
- try out.write("");
+ try out.writeAll("");
} else {
const is_int = blk: {
if (src[token.start] != 'i' and src[token.start] != 'u')
@@ -901,9 +894,9 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
break :blk true;
};
if (is_int or isType(src[token.start..token.end])) {
- try out.write("");
+ try out.writeAll("");
try writeEscaped(out, src[token.start..token.end]);
- try out.write("");
+ try out.writeAll("");
} else {
try writeEscaped(out, src[token.start..token.end]);
}
@@ -913,9 +906,9 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
.IntegerLiteral,
.FloatLiteral,
=> {
- try out.write("");
+ try out.writeAll("");
try writeEscaped(out, src[token.start..token.end]);
- try out.write("");
+ try out.writeAll("");
},
.Bang,
@@ -983,7 +976,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
}
index = token.end;
}
- try out.write("
");
+ try out.writeAll("
");
}
fn tokenizeAndPrint(docgen_tokenizer: *Tokenizer, out: var, source_token: Token) !void {
@@ -1002,7 +995,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
for (toc.nodes) |node| {
switch (node) {
.Content => |data| {
- try out.write(data);
+ try out.writeAll(data);
},
.Link => |info| {
if (!toc.urls.contains(info.url)) {
@@ -1011,12 +1004,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
try out.print("{}", .{ info.url, info.name });
},
.Nav => {
- try out.write(toc.toc);
+ try out.writeAll(toc.toc);
},
.Builtin => |tok| {
- try out.write("");
+ try out.writeAll("");
try tokenizeAndPrintRaw(tokenizer, out, tok, builtin_code);
- try out.write("
");
+ try out.writeAll("
");
},
.HeaderOpen => |info| {
try out.print(
@@ -1025,7 +1018,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
);
},
.SeeAlso => |items| {
- try out.write("See also:
\n");
+ try out.writeAll("See also:
\n");
for (items) |item| {
const url = try urlize(allocator, item.name);
if (!toc.urls.contains(url)) {
@@ -1033,7 +1026,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
}
try out.print("- {}
\n", .{ url, item.name });
}
- try out.write("
\n");
+ try out.writeAll("
\n");
},
.Syntax => |content_tok| {
try tokenizeAndPrint(tokenizer, out, content_tok);
@@ -1047,9 +1040,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
if (!code.is_inline) {
try out.print("{}.zig
", .{code.name});
}
- try out.write("");
+ try out.writeAll("");
try tokenizeAndPrint(tokenizer, out, code.source_token);
- try out.write("
");
+ try out.writeAll("
");
const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", .{code.name});
const tmp_source_file_name = try fs.path.join(
allocator,
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 447d54597..baba472e8 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -230,7 +230,7 @@
const std = @import("std");
pub fn main() !void {
- const stdout = &std.io.getStdOut().outStream().stream;
+ const stdout = std.io.getStdOut().outStream();
try stdout.print("Hello, {}!\n", .{"world"});
}
{#code_end#}
diff --git a/lib/std/build.zig b/lib/std/build.zig
index bc8b8acba..e8484e9d1 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -926,8 +926,7 @@ pub const Builder = struct {
try child.spawn();
- var stdout_file_in_stream = child.stdout.?.inStream();
- const stdout = try stdout_file_in_stream.stream.readAllAlloc(self.allocator, max_output_size);
+ const stdout = try child.stdout.?.inStream().readAllAlloc(self.allocator, max_output_size);
errdefer self.allocator.free(stdout);
const term = try child.wait();
diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig
index 41417572c..91ecd56c3 100644
--- a/lib/std/build/run.zig
+++ b/lib/std/build/run.zig
@@ -175,8 +175,7 @@ pub const RunStep = struct {
switch (self.stdout_action) {
.expect_exact, .expect_matches => {
- var stdout_file_in_stream = child.stdout.?.inStream();
- stdout = stdout_file_in_stream.stream.readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
+ stdout = child.stdout.?.inStream().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
},
.inherit, .ignore => {},
}
@@ -186,8 +185,7 @@ pub const RunStep = struct {
switch (self.stderr_action) {
.expect_exact, .expect_matches => {
- var stderr_file_in_stream = child.stderr.?.inStream();
- stderr = stderr_file_in_stream.stream.readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
+ stderr = child.stderr.?.inStream().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
},
.inherit, .ignore => {},
}
diff --git a/lib/std/coff.zig b/lib/std/coff.zig
index b1be21c4d..2e17f4645 100644
--- a/lib/std/coff.zig
+++ b/lib/std/coff.zig
@@ -56,8 +56,7 @@ pub const Coff = struct {
pub fn loadHeader(self: *Coff) !void {
const pe_pointer_offset = 0x3C;
- var file_stream = self.in_file.inStream();
- const in = &file_stream.stream;
+ const in = self.in_file.inStream();
var magic: [2]u8 = undefined;
try in.readNoEof(magic[0..]);
@@ -89,11 +88,11 @@ pub const Coff = struct {
else => return error.InvalidMachine,
}
- try self.loadOptionalHeader(&file_stream);
+ try self.loadOptionalHeader();
}
- fn loadOptionalHeader(self: *Coff, file_stream: *File.InStream) !void {
- const in = &file_stream.stream;
+ fn loadOptionalHeader(self: *Coff) !void {
+ const in = self.in_file.inStream();
self.pe_header.magic = try in.readIntLittle(u16);
// For now we're only interested in finding the reference to the .pdb,
// so we'll skip most of this header, which size is different in 32
@@ -136,8 +135,7 @@ pub const Coff = struct {
const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
- var file_stream = self.in_file.inStream();
- const in = &file_stream.stream;
+ const in = self.in_file.inStream();
try self.in_file.seekTo(file_offset);
// Find the correct DebugDirectoryEntry, and where its data is stored.
@@ -188,8 +186,7 @@ pub const Coff = struct {
try self.sections.ensureCapacity(self.coff_header.number_of_sections);
- var file_stream = self.in_file.inStream();
- const in = &file_stream.stream;
+ const in = self.in_file.inStream();
var name: [8]u8 = undefined;
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index e849d72bc..0a7a0dee7 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -475,15 +475,15 @@ fn populateModule(di: *ModuleDebugInfo, mod: *Module) !void {
const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
- const signature = try modi.stream.readIntLittle(u32);
+ const signature = try modi.inStream().readIntLittle(u32);
if (signature != 4)
return error.InvalidDebugInfo;
mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
- try modi.stream.readNoEof(mod.symbols);
+ try modi.inStream().readNoEof(mod.symbols);
mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
- try modi.stream.readNoEof(mod.subsect_info);
+ try modi.inStream().readNoEof(mod.subsect_info);
var sect_offset: usize = 0;
var skip_len: usize = undefined;
@@ -656,11 +656,11 @@ fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !
try di.pdb.openFile(di.coff, path);
var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
- const version = try pdb_stream.stream.readIntLittle(u32);
- const signature = try pdb_stream.stream.readIntLittle(u32);
- const age = try pdb_stream.stream.readIntLittle(u32);
+ const version = try pdb_stream.inStream().readIntLittle(u32);
+ const signature = try pdb_stream.inStream().readIntLittle(u32);
+ const age = try pdb_stream.inStream().readIntLittle(u32);
var guid: [16]u8 = undefined;
- try pdb_stream.stream.readNoEof(&guid);
+ try pdb_stream.inStream().readNoEof(&guid);
if (version != 20000404) // VC70, only value observed by LLVM team
return error.UnknownPDBVersion;
if (!mem.eql(u8, &di.coff.guid, &guid) or di.coff.age != age)
@@ -668,9 +668,9 @@ fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !
// We validated the executable and pdb match.
const string_table_index = str_tab_index: {
- const name_bytes_len = try pdb_stream.stream.readIntLittle(u32);
+ const name_bytes_len = try pdb_stream.inStream().readIntLittle(u32);
const name_bytes = try allocator.alloc(u8, name_bytes_len);
- try pdb_stream.stream.readNoEof(name_bytes);
+ try pdb_stream.inStream().readNoEof(name_bytes);
const HashTableHeader = packed struct {
Size: u32,
@@ -680,17 +680,17 @@ fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !
return cap * 2 / 3 + 1;
}
};
- const hash_tbl_hdr = try pdb_stream.stream.readStruct(HashTableHeader);
+ const hash_tbl_hdr = try pdb_stream.inStream().readStruct(HashTableHeader);
if (hash_tbl_hdr.Capacity == 0)
return error.InvalidDebugInfo;
if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
return error.InvalidDebugInfo;
- const present = try readSparseBitVector(&pdb_stream.stream, allocator);
+ const present = try readSparseBitVector(&pdb_stream.inStream(), allocator);
if (present.len != hash_tbl_hdr.Size)
return error.InvalidDebugInfo;
- const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
+ const deleted = try readSparseBitVector(&pdb_stream.inStream(), allocator);
const Bucket = struct {
first: u32,
@@ -698,8 +698,8 @@ fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !
};
const bucket_list = try allocator.alloc(Bucket, present.len);
for (present) |_| {
- const name_offset = try pdb_stream.stream.readIntLittle(u32);
- const name_index = try pdb_stream.stream.readIntLittle(u32);
+ const name_offset = try pdb_stream.inStream().readIntLittle(u32);
+ const name_index = try pdb_stream.inStream().readIntLittle(u32);
const name = mem.toSlice(u8, @ptrCast([*:0]u8, name_bytes.ptr + name_offset));
if (mem.eql(u8, name, "/names")) {
break :str_tab_index name_index;
@@ -714,7 +714,7 @@ fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !
const dbi = di.pdb.dbi;
// Dbi Header
- const dbi_stream_header = try dbi.stream.readStruct(pdb.DbiStreamHeader);
+ const dbi_stream_header = try dbi.inStream().readStruct(pdb.DbiStreamHeader);
if (dbi_stream_header.VersionHeader != 19990903) // V70, only value observed by LLVM team
return error.UnknownPDBVersion;
if (dbi_stream_header.Age != age)
@@ -728,7 +728,7 @@ fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !
// Module Info Substream
var mod_info_offset: usize = 0;
while (mod_info_offset != mod_info_size) {
- const mod_info = try dbi.stream.readStruct(pdb.ModInfo);
+ const mod_info = try dbi.inStream().readStruct(pdb.ModInfo);
var this_record_len: usize = @sizeOf(pdb.ModInfo);
const module_name = try dbi.readNullTermString(allocator);
@@ -766,14 +766,14 @@ fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !
var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
var sect_cont_offset: usize = 0;
if (section_contrib_size != 0) {
- const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32));
+ const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.inStream().readIntLittle(u32));
if (ver != pdb.SectionContrSubstreamVersion.Ver60)
return error.InvalidDebugInfo;
sect_cont_offset += @sizeOf(u32);
}
while (sect_cont_offset != section_contrib_size) {
const entry = try sect_contribs.addOne();
- entry.* = try dbi.stream.readStruct(pdb.SectionContribEntry);
+ entry.* = try dbi.inStream().readStruct(pdb.SectionContribEntry);
sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
if (sect_cont_offset > section_contrib_size)
@@ -827,7 +827,7 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !M
const str_section_off = shoff + @as(u64, hdr.e_shentsize) * @as(u64, hdr.e_shstrndx);
const str_shdr = @ptrCast(
*const elf.Shdr,
- @alignCast(@alignOf(elf.Shdr), &mapped_mem[str_section_off]),
+ @alignCast(@alignOf(elf.Shdr), &mapped_mem[try math.cast(usize, str_section_off)]),
);
const header_strings = mapped_mem[str_shdr.sh_offset .. str_shdr.sh_offset + str_shdr.sh_size];
const shdrs = @ptrCast(
diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig
index 7c48cf7b7..93fef0b16 100644
--- a/lib/std/pdb.zig
+++ b/lib/std/pdb.zig
@@ -495,8 +495,7 @@ const Msf = struct {
streams: []MsfStream,
fn openFile(self: *Msf, allocator: *mem.Allocator, file: File) !void {
- var file_stream = file.inStream();
- const in = &file_stream.stream;
+ const in = file.inStream();
const superblock = try in.readStruct(SuperBlock);
@@ -529,7 +528,7 @@ const Msf = struct {
);
const begin = self.directory.pos;
- const stream_count = try self.directory.stream.readIntLittle(u32);
+ const stream_count = try self.directory.inStream().readIntLittle(u32);
const stream_sizes = try allocator.alloc(u32, stream_count);
defer allocator.free(stream_sizes);
@@ -538,7 +537,7 @@ const Msf = struct {
// and must be taken into account when resolving stream indices.
const Nil = 0xFFFFFFFF;
for (stream_sizes) |*s, i| {
- const size = try self.directory.stream.readIntLittle(u32);
+ const size = try self.directory.inStream().readIntLittle(u32);
s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.BlockSize);
}
@@ -553,7 +552,7 @@ const Msf = struct {
var blocks = try allocator.alloc(u32, size);
var j: u32 = 0;
while (j < size) : (j += 1) {
- const block_id = try self.directory.stream.readIntLittle(u32);
+ const block_id = try self.directory.inStream().readIntLittle(u32);
const n = (block_id % superblock.BlockSize);
// 0 is for SuperBlock, 1 and 2 for FPMs.
if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > try file.getEndPos())
@@ -648,7 +647,7 @@ const MsfStream = struct {
fn readNullTermString(self: *MsfStream, allocator: *mem.Allocator) ![]u8 {
var list = ArrayList(u8).init(allocator);
while (true) {
- const byte = try self.stream.readByte();
+ const byte = try self.inStream().readByte();
if (byte == 0) {
return list.toSlice();
}
@@ -662,8 +661,7 @@ const MsfStream = struct {
var offset = self.pos % self.block_size;
try self.in_file.seekTo(block * self.block_size + offset);
- var file_stream = self.in_file.inStream();
- const in = &file_stream.stream;
+ const in = self.in_file.inStream();
var size: usize = 0;
var rem_buffer = buffer;
diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig
index baf21570e..974247e2a 100644
--- a/lib/std/special/build_runner.zig
+++ b/lib/std/special/build_runner.zig
@@ -42,8 +42,8 @@ pub fn main() !void {
var targets = ArrayList([]const u8).init(allocator);
- const stderr_stream = &io.getStdErr().outStream().stream;
- const stdout_stream = &io.getStdOut().outStream().stream;
+ const stderr_stream = io.getStdErr().outStream();
+ const stdout_stream = io.getStdOut().outStream();
while (nextArg(args, &arg_idx)) |arg| {
if (mem.startsWith(u8, arg, "-D")) {
@@ -159,7 +159,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
try out_stream.print(" {s:22} {}\n", .{ name, top_level_step.description });
}
- try out_stream.write(
+ try out_stream.writeAll(
\\
\\General Options:
\\ --help Print this help and exit
@@ -184,7 +184,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
}
}
- try out_stream.write(
+ try out_stream.writeAll(
\\
\\Advanced Options:
\\ --build-file [file] Override path to build.zig
diff --git a/test/compare_output.zig b/test/compare_output.zig
index ec89af35f..1a0179c4c 100644
--- a/test/compare_output.zig
+++ b/test/compare_output.zig
@@ -22,7 +22,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn main() void {
\\ privateFunction();
- \\ const stdout = &getStdOut().outStream().stream;
+ \\ const stdout = getStdOut().outStream();
\\ stdout.print("OK 2\n", .{}) catch unreachable;
\\}
\\
@@ -37,7 +37,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\// purposefully conflicting function with main.zig
\\// but it's private so it should be OK
\\fn privateFunction() void {
- \\ const stdout = &getStdOut().outStream().stream;
+ \\ const stdout = getStdOut().outStream();
\\ stdout.print("OK 1\n", .{}) catch unreachable;
\\}
\\
@@ -63,7 +63,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
tc.addSourceFile("foo.zig",
\\usingnamespace @import("std").io;
\\pub fn foo_function() void {
- \\ const stdout = &getStdOut().outStream().stream;
+ \\ const stdout = getStdOut().outStream();
\\ stdout.print("OK\n", .{}) catch unreachable;
\\}
);
@@ -74,7 +74,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn bar_function() void {
\\ if (foo_function()) {
- \\ const stdout = &getStdOut().outStream().stream;
+ \\ const stdout = getStdOut().outStream();
\\ stdout.print("OK\n", .{}) catch unreachable;
\\ }
\\}
@@ -106,7 +106,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\pub const a_text = "OK\n";
\\
\\pub fn ok() void {
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ stdout.print(b_text, .{}) catch unreachable;
\\}
);
@@ -124,7 +124,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\
\\pub fn main() void {
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ stdout.print("Hello, world!\n{d:4} {x:3} {c}\n", .{@as(u32, 12), @as(u16, 0x12), @as(u8, 'a')}) catch unreachable;
\\}
, "Hello, world!\n 12 12 a\n");
@@ -267,7 +267,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ var x_local : i32 = print_ok(x);
\\}
\\fn print_ok(val: @TypeOf(x)) @TypeOf(foo) {
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ stdout.print("OK\n", .{}) catch unreachable;
\\ return 0;
\\}
@@ -349,7 +349,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\pub fn main() void {
\\ const bar = Bar {.field2 = 13,};
\\ const foo = Foo {.field1 = bar,};
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ if (!foo.method()) {
\\ stdout.print("BAD\n", .{}) catch unreachable;
\\ }
@@ -363,7 +363,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
cases.add("defer with only fallthrough",
\\const io = @import("std").io;
\\pub fn main() void {
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ stdout.print("before\n", .{}) catch unreachable;
\\ defer stdout.print("defer1\n", .{}) catch unreachable;
\\ defer stdout.print("defer2\n", .{}) catch unreachable;
@@ -376,7 +376,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\const os = @import("std").os;
\\pub fn main() void {
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ stdout.print("before\n", .{}) catch unreachable;
\\ defer stdout.print("defer1\n", .{}) catch unreachable;
\\ defer stdout.print("defer2\n", .{}) catch unreachable;
@@ -393,7 +393,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ do_test() catch return;
\\}
\\fn do_test() !void {
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ stdout.print("before\n", .{}) catch unreachable;
\\ defer stdout.print("defer1\n", .{}) catch unreachable;
\\ errdefer stdout.print("deferErr\n", .{}) catch unreachable;
@@ -412,7 +412,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\ do_test() catch return;
\\}
\\fn do_test() !void {
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ stdout.print("before\n", .{}) catch unreachable;
\\ defer stdout.print("defer1\n", .{}) catch unreachable;
\\ errdefer stdout.print("deferErr\n", .{}) catch unreachable;
@@ -429,7 +429,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\const io = @import("std").io;
\\
\\pub fn main() void {
- \\ const stdout = &io.getStdOut().outStream().stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ stdout.print(foo_txt, .{}) catch unreachable;
\\}
, "1234\nabcd\n");
@@ -448,9 +448,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn main() !void {
\\ var args_it = std.process.args();
- \\ var stdout_file = io.getStdOut();
- \\ var stdout_adapter = stdout_file.outStream();
- \\ const stdout = &stdout_adapter.stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ var index: usize = 0;
\\ _ = args_it.skip();
\\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) {
@@ -489,9 +487,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\
\\pub fn main() !void {
\\ var args_it = std.process.args();
- \\ var stdout_file = io.getStdOut();
- \\ var stdout_adapter = stdout_file.outStream();
- \\ const stdout = &stdout_adapter.stream;
+ \\ const stdout = io.getStdOut().outStream();
\\ var index: usize = 0;
\\ _ = args_it.skip();
\\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) {
diff --git a/test/standalone/guess_number/main.zig b/test/standalone/guess_number/main.zig
index f5b3b3699..14babcd14 100644
--- a/test/standalone/guess_number/main.zig
+++ b/test/standalone/guess_number/main.zig
@@ -4,7 +4,7 @@ const io = std.io;
const fmt = std.fmt;
pub fn main() !void {
- const stdout = &io.getStdOut().outStream().stream;
+ const stdout = io.getStdOut().outStream();
const stdin = io.getStdIn();
try stdout.print("Welcome to the Guess Number Game in Zig.\n", .{});
diff --git a/test/tests.zig b/test/tests.zig
index e32490257..22dad10e3 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -566,12 +566,9 @@ pub const StackTracesContext = struct {
}
child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", .{ full_exe_path, @errorName(err) });
- var stdout_file_in_stream = child.stdout.?.inStream();
- var stderr_file_in_stream = child.stderr.?.inStream();
-
- const stdout = stdout_file_in_stream.stream.readAllAlloc(b.allocator, max_stdout_size) catch unreachable;
+ const stdout = child.stdout.?.inStream().readAllAlloc(b.allocator, max_stdout_size) catch unreachable;
defer b.allocator.free(stdout);
- const stderr = stderr_file_in_stream.stream.readAllAlloc(b.allocator, max_stdout_size) catch unreachable;
+ const stderr = child.stderr.?.inStream().readAllAlloc(b.allocator, max_stdout_size) catch unreachable;
defer b.allocator.free(stderr);
const term = child.wait() catch |err| {
@@ -798,11 +795,8 @@ pub const CompileErrorContext = struct {
var stdout_buf = Buffer.initNull(b.allocator);
var stderr_buf = Buffer.initNull(b.allocator);
- var stdout_file_in_stream = child.stdout.?.inStream();
- var stderr_file_in_stream = child.stderr.?.inStream();
-
- stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
- stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
+ child.stdout.?.inStream().readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable;
+ child.stderr.?.inStream().readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable;
const term = child.wait() catch |err| {
debug.panic("Unable to spawn {}: {}\n", .{ zig_args.items[0], @errorName(err) });
From d882a305875d5e0ab5d7877c3763b5aaf0ff61ce Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 20:51:30 -0400
Subject: [PATCH 048/111] fix stage2 lib on windows
---
src-self-hosted/libc_installation.zig | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
index 78aafeff2..0f9736456 100644
--- a/src-self-hosted/libc_installation.zig
+++ b/src-self-hosted/libc_installation.zig
@@ -348,7 +348,7 @@ pub const LibCInstallation = struct {
for (searches) |search| {
result_buf.shrink(0);
- const stream = &std.io.BufferOutStream.init(&result_buf).stream;
+ const stream = result_buf.outStream();
try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version });
var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {
@@ -395,7 +395,7 @@ pub const LibCInstallation = struct {
for (searches) |search| {
result_buf.shrink(0);
- const stream = &std.io.BufferOutStream.init(&result_buf).stream;
+ const stream = result_buf.outStream();
try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir });
var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {
@@ -459,7 +459,7 @@ pub const LibCInstallation = struct {
for (searches) |search| {
result_buf.shrink(0);
- const stream = &std.io.BufferOutStream.init(&result_buf).stream;
+ const stream = result_buf.outStream();
try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir });
var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {
From bd14a81e301401b5b2a8b849d17d6ae0750272b8 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 21:09:49 -0400
Subject: [PATCH 049/111] fix std.ChildProcess on Windows
---
lib/std/child_process.zig | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig
index 95619384b..008fc34ff 100644
--- a/lib/std/child_process.zig
+++ b/lib/std/child_process.zig
@@ -217,13 +217,13 @@ pub const ChildProcess = struct {
try child.spawn();
- var stdout_file_in_stream = child.stdout.?.inStream();
- var stderr_file_in_stream = child.stderr.?.inStream();
+ const stdout_in = child.stdout.?.inStream();
+ const stderr_in = child.stderr.?.inStream();
// TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
- const stdout = try stdout_file_in_stream.readAllAlloc(args.allocator, args.max_output_bytes);
+ const stdout = try stdout_in.readAllAlloc(args.allocator, args.max_output_bytes);
errdefer args.allocator.free(stdout);
- const stderr = try stderr_file_in_stream.readAllAlloc(args.allocator, args.max_output_bytes);
+ const stderr = try stderr_in.readAllAlloc(args.allocator, args.max_output_bytes);
errdefer args.allocator.free(stderr);
return ExecResult{
@@ -780,7 +780,7 @@ fn windowsCreateCommandLine(allocator: *mem.Allocator, argv: []const []const u8)
var buf = try Buffer.initSize(allocator, 0);
defer buf.deinit();
- var buf_stream = &io.BufferOutStream.init(&buf).stream;
+ var buf_stream = buf.outStream();
for (argv) |arg, arg_i| {
if (arg_i != 0) try buf.appendByte(' ');
From ed13cffca4c42718cc7239faf7aab642ac67ef77 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 10 Mar 2020 22:01:58 -0400
Subject: [PATCH 050/111] rework some old ELF parsing code and start to fix
emitRaw
---
lib/std/build/emit_raw.zig | 112 +++++---------
lib/std/elf.zig | 292 ++++++++++---------------------------
lib/std/zig/system.zig | 35 ++---
3 files changed, 128 insertions(+), 311 deletions(-)
diff --git a/lib/std/build/emit_raw.zig b/lib/std/build/emit_raw.zig
index 44e0227b6..63c232994 100644
--- a/lib/std/build/emit_raw.zig
+++ b/lib/std/build/emit_raw.zig
@@ -14,11 +14,6 @@ const io = std.io;
const sort = std.sort;
const warn = std.debug.warn;
-const BinOutStream = io.OutStream(anyerror);
-const BinSeekStream = io.SeekableStream(anyerror, anyerror);
-const ElfSeekStream = io.SeekableStream(anyerror, anyerror);
-const ElfInStream = io.InStream(anyerror);
-
const BinaryElfSection = struct {
elfOffset: u64,
binaryOffset: u64,
@@ -41,22 +36,21 @@ const BinaryElfOutput = struct {
const Self = @This();
- pub fn init(allocator: *Allocator) Self {
- return Self{
- .segments = ArrayList(*BinaryElfSegment).init(allocator),
- .sections = ArrayList(*BinaryElfSection).init(allocator),
- };
- }
-
pub fn deinit(self: *Self) void {
self.sections.deinit();
self.segments.deinit();
}
- pub fn parseElf(self: *Self, elfFile: elf.Elf) !void {
- const allocator = self.segments.allocator;
+ pub fn parse(allocator: *Allocator, elf_file: File) !Self {
+ var self: Self = .{
+ .segments = ArrayList(*BinaryElfSegment).init(allocator),
+ .sections = ArrayList(*BinaryElfSection).init(allocator),
+ };
+ const elf_hdrs = try std.elf.readAllHeaders(allocator, elf_file);
- for (elfFile.section_headers) |section, i| {
+ var binaryElfOutput = BinaryElfOutput.init(arena_allocator);
+
+ for (elf_hdrs.section_headers) |section, i| {
if (sectionValidForOutput(section)) {
const newSection = try allocator.create(BinaryElfSection);
@@ -69,19 +63,19 @@ const BinaryElfOutput = struct {
}
}
- for (elfFile.program_headers) |programHeader, i| {
- if (programHeader.p_type == elf.PT_LOAD) {
+ for (elf_hdrs.program_headers) |phdr, i| {
+ if (phdr.p_type == elf.PT_LOAD) {
const newSegment = try allocator.create(BinaryElfSegment);
- newSegment.physicalAddress = if (programHeader.p_paddr != 0) programHeader.p_paddr else programHeader.p_vaddr;
- newSegment.virtualAddress = programHeader.p_vaddr;
- newSegment.fileSize = @intCast(usize, programHeader.p_filesz);
- newSegment.elfOffset = programHeader.p_offset;
+ newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr;
+ newSegment.virtualAddress = phdr.p_vaddr;
+ newSegment.fileSize = @intCast(usize, phdr.p_filesz);
+ newSegment.elfOffset = phdr.p_offset;
newSegment.binaryOffset = 0;
newSegment.firstSection = null;
for (self.sections.toSlice()) |section| {
- if (sectionWithinSegment(section, programHeader)) {
+ if (sectionWithinSegment(section, phdr)) {
if (section.segment) |sectionSegment| {
if (sectionSegment.elfOffset > newSegment.elfOffset) {
section.segment = newSegment;
@@ -126,14 +120,17 @@ const BinaryElfOutput = struct {
}
sort.sort(*BinaryElfSection, self.sections.toSlice(), sectionSortCompare);
+
+ return self;
}
- fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.ProgramHeader) bool {
+ fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool {
return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize);
}
- fn sectionValidForOutput(section: elf.SectionHeader) bool {
- return section.sh_size > 0 and section.sh_type != elf.SHT_NOBITS and ((section.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
+ fn sectionValidForOutput(shdr: var) bool {
+ return shdr.sh_size > 0 and shdr.sh_type != elf.SHT_NOBITS and
+ ((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
}
fn segmentSortCompare(left: *BinaryElfSegment, right: *BinaryElfSegment) bool {
@@ -151,60 +148,27 @@ const BinaryElfOutput = struct {
}
};
-const WriteContext = struct {
- inStream: *ElfInStream,
- inSeekStream: *ElfSeekStream,
- outStream: *BinOutStream,
- outSeekStream: *BinSeekStream,
-};
+fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
+ try out_file.seekTo(section.binaryOffset);
-fn writeBinaryElfSection(allocator: *Allocator, context: WriteContext, section: *BinaryElfSection) !void {
- var readBuffer = try allocator.alloc(u8, section.fileSize);
- defer allocator.free(readBuffer);
-
- try context.inSeekStream.seekTo(section.elfOffset);
- _ = try context.inStream.read(readBuffer);
-
- try context.outSeekStream.seekTo(section.binaryOffset);
- try context.outStream.write(readBuffer);
+ try out_file.writeFileAll(elf_file, .{
+ .in_offset = section.elfOffset,
+ .in_len = section.fileSize,
+ });
}
-fn emit_raw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
- var arenaAlloc = ArenaAllocator.init(allocator);
- errdefer arenaAlloc.deinit();
- var arena_allocator = &arenaAlloc.allocator;
+fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
+ var elf_file = try fs.cwd().openFile(elf_path, .{});
+ defer elf_file.close();
- const currentDir = fs.cwd();
+ var out_file = try fs.cwd().createFile(raw_path, .{});
+ defer out_file.close();
- var file = try currentDir.openFile(elf_path, File.OpenFlags{});
- defer file.close();
+ const binary_elf_output = BinaryElfOutput.parse(allocator, elf_file);
+ defer binary_elf_output.deinit();
- var fileInStream = file.inStream();
- var fileSeekStream = file.seekableStream();
-
- var elfFile = try elf.Elf.openStream(allocator, @ptrCast(*ElfSeekStream, &fileSeekStream.stream), @ptrCast(*ElfInStream, &fileInStream.stream));
- defer elfFile.close();
-
- var outFile = try currentDir.createFile(raw_path, File.CreateFlags{});
- defer outFile.close();
-
- var outFileOutStream = outFile.outStream();
- var outFileSeekStream = outFile.seekableStream();
-
- const writeContext = WriteContext{
- .inStream = @ptrCast(*ElfInStream, &fileInStream.stream),
- .inSeekStream = @ptrCast(*ElfSeekStream, &fileSeekStream.stream),
- .outStream = @ptrCast(*BinOutStream, &outFileOutStream.stream),
- .outSeekStream = @ptrCast(*BinSeekStream, &outFileSeekStream.stream),
- };
-
- var binaryElfOutput = BinaryElfOutput.init(arena_allocator);
- defer binaryElfOutput.deinit();
-
- try binaryElfOutput.parseElf(elfFile);
-
- for (binaryElfOutput.sections.toSlice()) |section| {
- try writeBinaryElfSection(allocator, writeContext, section);
+ for (binary_elf_output.sections.toSlice()) |section| {
+ try writeBinaryElfSection(elf_file, out_file, section);
}
}
@@ -250,6 +214,6 @@ pub const InstallRawStep = struct {
const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);
fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable;
- try emit_raw(builder.allocator, full_src_path, full_dest_path);
+ try emitRaw(builder.allocator, full_src_path, full_dest_path);
}
};
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index efaa4d6f0..3aefd87f0 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -330,9 +330,7 @@ pub const ET = extern enum(u16) {
pub const HIPROC = 0xffff;
};
-pub const SectionHeader = Elf64_Shdr;
-pub const ProgramHeader = Elf64_Phdr;
-
+/// All integers are native endian.
const Header = struct {
endian: builtin.Endian,
is_64: bool,
@@ -346,9 +344,9 @@ const Header = struct {
shstrndx: u16,
};
-pub fn readHeader(in_stream: var) !Header {
+pub fn readHeader(file: File) !Header {
var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
- try in_stream.readAll(&hdr_buf);
+ try in_stream.preadAll(&hdr_buf, 0);
const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
@@ -381,216 +379,86 @@ pub fn readHeader(in_stream: var) !Header {
});
}
-pub const Elf = struct {
- seekable_stream: *io.SeekableStream(anyerror, anyerror),
- in_stream: *io.InStream(anyerror),
- is_64: bool,
- endian: builtin.Endian,
- file_type: ET,
- arch: EM,
- entry_addr: u64,
- program_header_offset: u64,
- section_header_offset: u64,
- string_section_index: usize,
- string_section: *SectionHeader,
- section_headers: []SectionHeader,
- program_headers: []ProgramHeader,
+/// All integers are native endian.
+pub const AllHeaders = struct {
+ header: Header,
+ section_headers: []Elf64_Shdr,
+ program_headers: []Elf64_Phdr,
allocator: *mem.Allocator,
-
- pub fn openStream(
- allocator: *mem.Allocator,
- seekable_stream: *io.SeekableStream(anyerror, anyerror),
- in: *io.InStream(anyerror),
- ) !Elf {
- var elf: Elf = undefined;
- elf.allocator = allocator;
- elf.seekable_stream = seekable_stream;
- elf.in_stream = in;
-
- var magic: [4]u8 = undefined;
- try in.readNoEof(magic[0..]);
- if (!mem.eql(u8, &magic, "\x7fELF")) return error.InvalidFormat;
-
- elf.is_64 = switch (try in.readByte()) {
- 1 => false,
- 2 => true,
- else => return error.InvalidFormat,
- };
-
- elf.endian = switch (try in.readByte()) {
- 1 => .Little,
- 2 => .Big,
- else => return error.InvalidFormat,
- };
-
- const version_byte = try in.readByte();
- if (version_byte != 1) return error.InvalidFormat;
-
- // skip over padding
- try seekable_stream.seekBy(9);
-
- elf.file_type = try in.readEnum(ET, elf.endian);
- elf.arch = try in.readEnum(EM, elf.endian);
-
- const elf_version = try in.readInt(u32, elf.endian);
- if (elf_version != 1) return error.InvalidFormat;
-
- if (elf.is_64) {
- elf.entry_addr = try in.readInt(u64, elf.endian);
- elf.program_header_offset = try in.readInt(u64, elf.endian);
- elf.section_header_offset = try in.readInt(u64, elf.endian);
- } else {
- elf.entry_addr = @as(u64, try in.readInt(u32, elf.endian));
- elf.program_header_offset = @as(u64, try in.readInt(u32, elf.endian));
- elf.section_header_offset = @as(u64, try in.readInt(u32, elf.endian));
- }
-
- // skip over flags
- try seekable_stream.seekBy(4);
-
- const header_size = try in.readInt(u16, elf.endian);
- if ((elf.is_64 and header_size != @sizeOf(Elf64_Ehdr)) or (!elf.is_64 and header_size != @sizeOf(Elf32_Ehdr))) {
- return error.InvalidFormat;
- }
-
- const ph_entry_size = try in.readInt(u16, elf.endian);
- const ph_entry_count = try in.readInt(u16, elf.endian);
-
- if ((elf.is_64 and ph_entry_size != @sizeOf(Elf64_Phdr)) or (!elf.is_64 and ph_entry_size != @sizeOf(Elf32_Phdr))) {
- return error.InvalidFormat;
- }
-
- const sh_entry_size = try in.readInt(u16, elf.endian);
- const sh_entry_count = try in.readInt(u16, elf.endian);
-
- if ((elf.is_64 and sh_entry_size != @sizeOf(Elf64_Shdr)) or (!elf.is_64 and sh_entry_size != @sizeOf(Elf32_Shdr))) {
- return error.InvalidFormat;
- }
-
- elf.string_section_index = @as(usize, try in.readInt(u16, elf.endian));
-
- if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
-
- const sh_byte_count = @as(u64, sh_entry_size) * @as(u64, sh_entry_count);
- const end_sh = try math.add(u64, elf.section_header_offset, sh_byte_count);
- const ph_byte_count = @as(u64, ph_entry_size) * @as(u64, ph_entry_count);
- const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count);
-
- const stream_end = try seekable_stream.getEndPos();
- if (stream_end < end_sh or stream_end < end_ph) {
- return error.InvalidFormat;
- }
-
- try seekable_stream.seekTo(elf.program_header_offset);
-
- elf.program_headers = try elf.allocator.alloc(ProgramHeader, ph_entry_count);
- errdefer elf.allocator.free(elf.program_headers);
-
- if (elf.is_64) {
- for (elf.program_headers) |*elf_program| {
- elf_program.p_type = try in.readInt(Elf64_Word, elf.endian);
- elf_program.p_flags = try in.readInt(Elf64_Word, elf.endian);
- elf_program.p_offset = try in.readInt(Elf64_Off, elf.endian);
- elf_program.p_vaddr = try in.readInt(Elf64_Addr, elf.endian);
- elf_program.p_paddr = try in.readInt(Elf64_Addr, elf.endian);
- elf_program.p_filesz = try in.readInt(Elf64_Xword, elf.endian);
- elf_program.p_memsz = try in.readInt(Elf64_Xword, elf.endian);
- elf_program.p_align = try in.readInt(Elf64_Xword, elf.endian);
- }
- } else {
- for (elf.program_headers) |*elf_program| {
- elf_program.p_type = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
- elf_program.p_offset = @as(Elf64_Off, try in.readInt(Elf32_Off, elf.endian));
- elf_program.p_vaddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian));
- elf_program.p_paddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian));
- elf_program.p_filesz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
- elf_program.p_memsz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
- elf_program.p_flags = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
- elf_program.p_align = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian));
- }
- }
-
- try seekable_stream.seekTo(elf.section_header_offset);
-
- elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count);
- errdefer elf.allocator.free(elf.section_headers);
-
- if (elf.is_64) {
- for (elf.section_headers) |*elf_section| {
- elf_section.sh_name = try in.readInt(u32, elf.endian);
- elf_section.sh_type = try in.readInt(u32, elf.endian);
- elf_section.sh_flags = try in.readInt(u64, elf.endian);
- elf_section.sh_addr = try in.readInt(u64, elf.endian);
- elf_section.sh_offset = try in.readInt(u64, elf.endian);
- elf_section.sh_size = try in.readInt(u64, elf.endian);
- elf_section.sh_link = try in.readInt(u32, elf.endian);
- elf_section.sh_info = try in.readInt(u32, elf.endian);
- elf_section.sh_addralign = try in.readInt(u64, elf.endian);
- elf_section.sh_entsize = try in.readInt(u64, elf.endian);
- }
- } else {
- for (elf.section_headers) |*elf_section| {
- // TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ?
- elf_section.sh_name = try in.readInt(u32, elf.endian);
- elf_section.sh_type = try in.readInt(u32, elf.endian);
- elf_section.sh_flags = @as(u64, try in.readInt(u32, elf.endian));
- elf_section.sh_addr = @as(u64, try in.readInt(u32, elf.endian));
- elf_section.sh_offset = @as(u64, try in.readInt(u32, elf.endian));
- elf_section.sh_size = @as(u64, try in.readInt(u32, elf.endian));
- elf_section.sh_link = try in.readInt(u32, elf.endian);
- elf_section.sh_info = try in.readInt(u32, elf.endian);
- elf_section.sh_addralign = @as(u64, try in.readInt(u32, elf.endian));
- elf_section.sh_entsize = @as(u64, try in.readInt(u32, elf.endian));
- }
- }
-
- for (elf.section_headers) |*elf_section| {
- if (elf_section.sh_type != SHT_NOBITS) {
- const file_end_offset = try math.add(u64, elf_section.sh_offset, elf_section.sh_size);
- if (stream_end < file_end_offset) return error.InvalidFormat;
- }
- }
-
- elf.string_section = &elf.section_headers[elf.string_section_index];
- if (elf.string_section.sh_type != SHT_STRTAB) {
- // not a string table
- return error.InvalidFormat;
- }
-
- return elf;
- }
-
- pub fn close(elf: *Elf) void {
- elf.allocator.free(elf.section_headers);
- elf.allocator.free(elf.program_headers);
- }
-
- pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
- section_loop: for (elf.section_headers) |*elf_section| {
- if (elf_section.sh_type == SHT_NULL) continue;
-
- const name_offset = elf.string_section.sh_offset + elf_section.sh_name;
- try elf.seekable_stream.seekTo(name_offset);
-
- for (name) |expected_c| {
- const target_c = try elf.in_stream.readByte();
- if (target_c == 0 or expected_c != target_c) continue :section_loop;
- }
-
- {
- const null_byte = try elf.in_stream.readByte();
- if (null_byte == 0) return elf_section;
- }
- }
-
- return null;
- }
-
- pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void {
- try elf.seekable_stream.seekTo(elf_section.sh_offset);
- }
};
+pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
+ var hdrs: AllHeaders = .{
+ .allocator = allocator,
+ .header = try readHeader(file),
+ .section_headers = undefined,
+ .program_headers = undefined,
+ };
+ const is_64 = hdrs.header.is_64;
+ const need_bswap = hdrs.header.endian != std.builtin.endian;
+
+ hdrs.section_headers = try allocator.alloc(Elf64_Shdr, hdrs.header.shnum);
+ errdefer hdrs.allocator.free(hdrs.section_headers);
+
+ hdrs.program_headers = try allocator.alloc(Elf64_Phdr, hdrs.header.phnum);
+ errdefer hdrs.allocator.free(hdrs.program_headers);
+
+ // Treat section headers and program headers as byte buffers. For 32-bit ELF and
+ // non-matching endian files, we post-process to correct integer endianness and offsets.
+
+ const shdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum];
+ const phdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
+
+ try file.preadAll(phdr_buf, hdrs.header.phoff);
+ try file.preadAll(shdr_buf, hdrs.header.shoff);
+
+ const shdrs32 = @ptrCast([*]Elf32_Shdr, @alignCast(@alignOf(Elf32_Shdr), shdr_buf.ptr))[0..hdrs.header.shnum];
+ const phdrs32 = @ptrCast([*]Elf32_Phdr, @alignCast(@alignOf(Elf32_Phdr), phdr_buf.ptr))[0..hdrs.header.phnum];
+ for (hdrs.section_headers) |*shdr, i| {
+ shdr.* = .{
+ .sh_name = int(is_64, need_bswap, shdrs32[i].sh_name, shdr.sh_name),
+ .sh_type = int(is_64, need_bswap, shdrs32[i].sh_type, shdr.sh_type),
+ .sh_flags = int(is_64, need_bswap, shdrs32[i].sh_flags, shdr.sh_flags),
+ .sh_addr = int(is_64, need_bswap, shdrs32[i].sh_addr, shdr.sh_addr),
+ .sh_offset = int(is_64, need_bswap, shdrs32[i].sh_offset, shdr.sh_offset),
+ .sh_size = int(is_64, need_bswap, shdrs32[i].sh_size, shdr.sh_size),
+ .sh_link = int(is_64, need_bswap, shdrs32[i].sh_link, shdr.sh_link),
+ .sh_info = int(is_64, need_bswap, shdrs32[i].sh_info, shdr.sh_info),
+ .sh_addralign = int(is_64, need_bswap, shdrs32[i].sh_addralign, shdr.sh_addralign),
+ .sh_entsize = int(is_64, need_bswap, shdrs32[i].sh_entsize, shdr.sh_entsize),
+ };
+ }
+ for (hdrs.program_headers) |*phdr, i| {
+ phdr.* = .{
+ .p_type = int(is_64, need_bswap, phdrs32[i].p_type, shdr.p_type),
+ .p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, shdr.p_offset),
+ .p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, shdr.p_vaddr),
+ .p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, shdr.p_paddr),
+ .p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, shdr.p_filesz),
+ .p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, shdr.p_memsz),
+ .p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, shdr.p_flags),
+ .p_align = int(is_64, need_bswap, phdrs32[i].p_align, shdr.p_align),
+ };
+ }
+ return hdrs;
+}
+
+pub fn int(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
+ if (is_64) {
+ if (need_bswap) {
+ return @byteSwap(@TypeOf(int_64), int_64);
+ } else {
+ return int_64;
+ }
+ } else {
+ if (need_bswap) {
+ return @byteSwap(@TypeOf(int_32), int_32);
+ } else {
+ return int_32;
+ }
+ }
+}
+
pub const EI_NIDENT = 16;
pub const EI_CLASS = 4;
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 336dd0d31..e7953a1a9 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -570,7 +570,7 @@ pub const NativeTargetInfo = struct {
cross_target: CrossTarget,
) AbiAndDynamicLinkerFromFileError!NativeTargetInfo {
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;
- _ = try preadFull(file, &hdr_buf, 0, hdr_buf.len);
+ _ = try preadMin(file, &hdr_buf, 0, hdr_buf.len);
const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
@@ -587,6 +587,7 @@ pub const NativeTargetInfo = struct {
elf.ELFCLASS64 => true,
else => return error.InvalidElfClass,
};
+ const elfInt = elf.int;
var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);
const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);
const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
@@ -610,7 +611,7 @@ pub const NativeTargetInfo = struct {
// Reserve some bytes so that we can deref the 64-bit struct fields
// even when the ELF file is 32-bits.
const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);
- const ph_read_byte_len = try preadFull(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
+ const ph_read_byte_len = try preadMin(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize);
var ph_buf_i: usize = 0;
while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({
ph_i += 1;
@@ -625,7 +626,7 @@ pub const NativeTargetInfo = struct {
const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
- _ = try preadFull(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz);
+ _ = try preadMin(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz);
// PT_INTERP includes a null byte in p_filesz.
const len = p_filesz - 1;
// dynamic_linker.max_byte is "max", not "len".
@@ -656,7 +657,7 @@ pub const NativeTargetInfo = struct {
// Reserve some bytes so that we can deref the 64-bit struct fields
// even when the ELF file is 32-bits.
const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);
- const dyn_read_byte_len = try preadFull(
+ const dyn_read_byte_len = try preadMin(
file,
dyn_buf[0 .. dyn_buf.len - dyn_reserve],
dyn_off,
@@ -701,14 +702,14 @@ pub const NativeTargetInfo = struct {
var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
if (sh_buf.len < shentsize) return error.InvalidElfFile;
- _ = try preadFull(file, &sh_buf, str_section_off, shentsize);
+ _ = try preadMin(file, &sh_buf, str_section_off, shentsize);
const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf));
const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf));
const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
var strtab_buf: [4096:0]u8 = undefined;
const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len);
- const shstrtab_read_len = try preadFull(file, &strtab_buf, shstrtab_off, shstrtab_len);
+ const shstrtab_read_len = try preadMin(file, &strtab_buf, shstrtab_off, shstrtab_len);
const shstrtab = strtab_buf[0..shstrtab_read_len];
const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
@@ -717,7 +718,7 @@ pub const NativeTargetInfo = struct {
// Reserve some bytes so that we can deref the 64-bit struct fields
// even when the ELF file is 32-bits.
const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);
- const sh_read_byte_len = try preadFull(
+ const sh_read_byte_len = try preadMin(
file,
sh_buf[0 .. sh_buf.len - sh_reserve],
shoff,
@@ -751,7 +752,7 @@ pub const NativeTargetInfo = struct {
if (dynstr) |ds| {
const strtab_len = std.math.min(ds.size, strtab_buf.len);
- const strtab_read_len = try preadFull(file, &strtab_buf, ds.offset, shstrtab_len);
+ const strtab_read_len = try preadMin(file, &strtab_buf, ds.offset, shstrtab_len);
const strtab = strtab_buf[0..strtab_read_len];
// TODO this pointer cast should not be necessary
const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));
@@ -813,7 +814,7 @@ pub const NativeTargetInfo = struct {
return result;
}
- fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
+ fn preadMin(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize {
var i: u64 = 0;
while (i < min_read_len) {
const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
@@ -853,22 +854,6 @@ pub const NativeTargetInfo = struct {
abi: Target.Abi,
};
- fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
- if (is_64) {
- if (need_bswap) {
- return @byteSwap(@TypeOf(int_64), int_64);
- } else {
- return int_64;
- }
- } else {
- if (need_bswap) {
- return @byteSwap(@TypeOf(int_32), int_32);
- } else {
- return int_32;
- }
- }
- }
-
fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) ?Target.Cpu {
// Here we switch on a comptime value rather than `cpu_arch`. This is valid because `cpu_arch`,
// although it is a runtime value, is guaranteed to be one of the architectures in the set
From 21809c33001cc53c8fb3b56b25264e8d9076bed9 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 11 Mar 2020 09:24:53 +0200
Subject: [PATCH 051/111] support non power of two integers in atomic ops
---
src/all_types.hpp | 8 +++++
src/codegen.cpp | 45 ++++++++++++------------
src/ir.cpp | 87 +++++++++++++++++++++++------------------------
3 files changed, 73 insertions(+), 67 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 14b99228c..149b7f464 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -3567,6 +3567,8 @@ struct IrInstGenCmpxchg {
IrInstGen *cmp_value;
IrInstGen *new_value;
IrInstGen *result_loc;
+ // non null if operand needs widening and truncating
+ ZigType *actual_type;
bool is_weak;
};
@@ -4199,6 +4201,8 @@ struct IrInstGenAtomicRmw {
IrInstGen *ptr;
IrInstGen *operand;
+ // non null if operand needs widening and truncating
+ ZigType *actual_type;
AtomicRmwOp op;
AtomicOrder ordering;
};
@@ -4215,6 +4219,8 @@ struct IrInstGenAtomicLoad {
IrInstGen base;
IrInstGen *ptr;
+ // non null if operand needs widening and truncating
+ ZigType *actual_type;
AtomicOrder ordering;
};
@@ -4232,6 +4238,8 @@ struct IrInstGenAtomicStore {
IrInstGen *ptr;
IrInstGen *value;
+ // non null if operand needs widening and truncating
+ ZigType *actual_type;
AtomicOrder ordering;
};
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 7238d5041..cfb3de292 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5225,12 +5225,12 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
ZigType *operand_type = instruction->new_value->value->type;
- if (operand_type->id == ZigTypeIdBool) {
- // treat bool as u8
+ if (instruction->actual_type != nullptr) {
+ // operand needs widening and truncating
ptr_val = LLVMBuildBitCast(g->builder, ptr_val,
- LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), "");
- cmp_val = LLVMConstZExt(cmp_val, g->builtin_types.entry_u8->llvm_type);
- new_val = LLVMConstZExt(new_val, g->builtin_types.entry_u8->llvm_type);
+ LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
+ cmp_val = LLVMConstZExt(cmp_val, get_llvm_type(g, instruction->actual_type));
+ new_val = LLVMConstZExt(new_val, get_llvm_type(g, instruction->actual_type));
}
LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
@@ -5245,8 +5245,8 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
if (!handle_is_ptr(g, optional_type)) {
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- if (operand_type->id == ZigTypeIdBool) {
- payload_val = LLVMBuildTrunc(g->builder, payload_val, g->builtin_types.entry_bool->llvm_type, "");
+ if (instruction->actual_type != nullptr) {
+ payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), "");
}
LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, "");
@@ -5262,8 +5262,8 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
ir_assert(type_has_bits(g, child_type), &instruction->base);
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- if (operand_type->id == ZigTypeIdBool) {
- payload_val = LLVMBuildTrunc(g->builder, payload_val, g->builtin_types.entry_bool->llvm_type, "");
+ if (instruction->actual_type != nullptr) {
+ payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), "");
}
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val);
@@ -5842,14 +5842,14 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutableGen *executable
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
- if (operand_type->id == ZigTypeIdBool) {
- // treat bool as u8
+ if (instruction->actual_type != nullptr) {
+ // operand needs widening and truncating
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
- LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), "");
- LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, g->builtin_types.entry_u8->llvm_type, "");
+ LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
+ LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, get_llvm_type(g, instruction->actual_type), "");
LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
g->is_single_threaded);
- return LLVMBuildTrunc(g->builder, uncasted_result, g->builtin_types.entry_bool->llvm_type, "");
+ return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
}
if (get_codegen_ptr_type_bail(g, operand_type) == nullptr) {
@@ -5872,13 +5872,13 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutableGen *executabl
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
ZigType *operand_type = instruction->ptr->value->type->data.pointer.child_type;
- if (operand_type->id == ZigTypeIdBool) {
- // treat bool as u8
+ if (instruction->actual_type != nullptr) {
+ // operand needs widening and truncating
ptr = LLVMBuildBitCast(g->builder, ptr,
- LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), "");
+ LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, "");
LLVMSetOrdering(load_inst, ordering);
- return LLVMBuildTrunc(g->builder, load_inst, g->builtin_types.entry_bool->llvm_type, "");
+ return LLVMBuildTrunc(g->builder, load_inst, get_llvm_type(g, operand_type), "");
}
LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, "");
LLVMSetOrdering(load_inst, ordering);
@@ -5892,12 +5892,11 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutableGen *executab
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
LLVMValueRef value = ir_llvm_value(g, instruction->value);
- ZigType *operand_type = instruction->value->value->type;
- if (operand_type->id == ZigTypeIdBool) {
- // treat bool as u8
+ if (instruction->actual_type != nullptr) {
+ // operand needs widening and truncating
ptr = LLVMBuildBitCast(g->builder, ptr,
- LLVMPointerType(g->builtin_types.entry_u8->llvm_type, 0), "");
- value = LLVMConstZExt(value, g->builtin_types.entry_u8->llvm_type);
+ LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
+ value = LLVMConstZExt(value, get_llvm_type(g, instruction->actual_type));
}
LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value->type);
LLVMSetOrdering(store_inst, ordering);
diff --git a/src/ir.cpp b/src/ir.cpp
index cad1d382e..9465be8b0 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -227,7 +227,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
static void ir_assert(bool ok, IrInst* source_instruction);
static void ir_assert_gen(bool ok, IrInstGen *source_instruction);
static IrInstGen *ir_get_var_ptr(IrAnalyze *ira, IrInst *source_instr, ZigVar *var);
-static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op);
+static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, ZigType **actual_type);
static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, ResultLoc *result_loc);
static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc);
static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align);
@@ -3406,7 +3406,7 @@ static IrInstSrc *ir_build_cmpxchg_src(IrBuilderSrc *irb, Scope *scope, AstNode
static IrInstGen *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type,
IrInstGen *ptr, IrInstGen *cmp_value, IrInstGen *new_value,
- AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstGen *result_loc)
+ AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstGen *result_loc, ZigType *actual_type)
{
IrInstGenCmpxchg *instruction = ir_build_inst_gen(&ira->new_irb,
source_instruction->scope, source_instruction->source_node);
@@ -3418,6 +3418,7 @@ static IrInstGen *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInst *source_instructio
instruction->failure_order = failure_order;
instruction->is_weak = is_weak;
instruction->result_loc = result_loc;
+ instruction->actual_type = actual_type;
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
ir_ref_inst_gen(cmp_value, ira->new_irb.current_basic_block);
@@ -4554,7 +4555,7 @@ static IrInstSrc *ir_build_atomic_rmw_src(IrBuilderSrc *irb, Scope *scope, AstNo
}
static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr,
- IrInstGen *ptr, IrInstGen *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type)
+ IrInstGen *ptr, IrInstGen *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type, ZigType *actual_type)
{
IrInstGenAtomicRmw *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node);
instruction->base.value->type = operand_type;
@@ -4562,6 +4563,7 @@ static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr,
instruction->op = op;
instruction->operand = operand;
instruction->ordering = ordering;
+ instruction->actual_type = actual_type;
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
ir_ref_inst_gen(operand, ira->new_irb.current_basic_block);
@@ -4585,13 +4587,14 @@ static IrInstSrc *ir_build_atomic_load_src(IrBuilderSrc *irb, Scope *scope, AstN
}
static IrInstGen *ir_build_atomic_load_gen(IrAnalyze *ira, IrInst *source_instr,
- IrInstGen *ptr, AtomicOrder ordering, ZigType *operand_type)
+ IrInstGen *ptr, AtomicOrder ordering, ZigType *operand_type, ZigType *actual_type)
{
IrInstGenAtomicLoad *instruction = ir_build_inst_gen(&ira->new_irb,
source_instr->scope, source_instr->source_node);
instruction->base.value->type = operand_type;
instruction->ptr = ptr;
instruction->ordering = ordering;
+ instruction->actual_type = actual_type;
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
@@ -4616,13 +4619,14 @@ static IrInstSrc *ir_build_atomic_store_src(IrBuilderSrc *irb, Scope *scope, Ast
}
static IrInstGen *ir_build_atomic_store_gen(IrAnalyze *ira, IrInst *source_instr,
- IrInstGen *ptr, IrInstGen *value, AtomicOrder ordering)
+ IrInstGen *ptr, IrInstGen *value, AtomicOrder ordering, ZigType *actual_type)
{
IrInstGenAtomicStore *instruction = ir_build_inst_void(&ira->new_irb,
source_instr->scope, source_instr->source_node);
instruction->ptr = ptr;
instruction->value = value;
instruction->ordering = ordering;
+ instruction->actual_type = actual_type;
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
ir_ref_inst_gen(value, ira->new_irb.current_basic_block);
@@ -25121,7 +25125,8 @@ static IrInstGen *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstSrcEmb
}
static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxchg *instruction) {
- ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child);
+ ZigType *actual_type;
+ ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child, &actual_type);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_inst_gen;
@@ -25213,7 +25218,7 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
return ir_build_cmpxchg_gen(ira, &instruction->base.base, result_type,
casted_ptr, casted_cmp_value, casted_new_value,
- success_order, failure_order, instruction->is_weak, result_loc);
+ success_order, failure_order, instruction->is_weak, result_loc, actual_type);
}
static IrInstGen *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstSrcFence *instruction) {
@@ -28305,17 +28310,15 @@ static IrInstGen *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstSrcTagTy
}
}
-static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) {
+static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, ZigType **actual_type) {
ZigType *operand_type = ir_resolve_type(ira, op);
if (type_is_invalid(operand_type))
return ira->codegen->builtin_types.entry_invalid;
- if (operand_type->id == ZigTypeIdInt) {
- if (operand_type->data.integral.bit_count < 8) {
- ir_add_error(ira, &op->base,
- buf_sprintf("expected integer type 8 bits or larger, found %" PRIu32 "-bit integer type",
- operand_type->data.integral.bit_count));
- return ira->codegen->builtin_types.entry_invalid;
+ *actual_type = nullptr;
+ if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) {
+ if (operand_type->id == ZigTypeIdEnum) {
+ operand_type = operand_type->data.enumeration.tag_int_type;
}
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
if (operand_type->data.integral.bit_count > max_atomic_bits) {
@@ -28324,30 +28327,22 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) {
max_atomic_bits, operand_type->data.integral.bit_count));
return ira->codegen->builtin_types.entry_invalid;
}
- if (!is_power_of_2(operand_type->data.integral.bit_count)) {
- ir_add_error(ira, &op->base,
- buf_sprintf("%" PRIu32 "-bit integer type is not a power of 2", operand_type->data.integral.bit_count));
- return ira->codegen->builtin_types.entry_invalid;
- }
- } else if (operand_type->id == ZigTypeIdEnum) {
- ZigType *int_type = operand_type->data.enumeration.tag_int_type;
- if (int_type->data.integral.bit_count < 8) {
- ir_add_error(ira, &op->base,
- buf_sprintf("expected enum tag type 8 bits or larger, found %" PRIu32 "-bit tag type",
- int_type->data.integral.bit_count));
- return ira->codegen->builtin_types.entry_invalid;
- }
- uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
- if (int_type->data.integral.bit_count > max_atomic_bits) {
- ir_add_error(ira, &op->base,
- buf_sprintf("expected %" PRIu32 "-bit enum tag type or smaller, found %" PRIu32 "-bit tag type",
- max_atomic_bits, int_type->data.integral.bit_count));
- return ira->codegen->builtin_types.entry_invalid;
- }
- if (!is_power_of_2(int_type->data.integral.bit_count)) {
- ir_add_error(ira, &op->base,
- buf_sprintf("%" PRIu32 "-bit enum tag type is not a power of 2", int_type->data.integral.bit_count));
- return ira->codegen->builtin_types.entry_invalid;
+ auto bit_count = operand_type->data.integral.bit_count;
+ bool is_signed = operand_type->data.integral.is_signed;
+ if (bit_count < 2 || !is_power_of_2(bit_count)) {
+ if (bit_count < 8) {
+ *actual_type = get_int_type(ira->codegen, is_signed, 8);
+ } else if (bit_count < 16) {
+ *actual_type = get_int_type(ira->codegen, is_signed, 16);
+ } else if (bit_count < 32) {
+ *actual_type = get_int_type(ira->codegen, is_signed, 32);
+ } else if (bit_count < 64) {
+ *actual_type = get_int_type(ira->codegen, is_signed, 64);
+ } else if (bit_count < 128) {
+ *actual_type = get_int_type(ira->codegen, is_signed, 128);
+ } else {
+ zig_unreachable();
+ }
}
} else if (operand_type->id == ZigTypeIdFloat) {
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
@@ -28359,6 +28354,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) {
}
} else if (operand_type->id == ZigTypeIdBool) {
// will be treated as u8
+ *actual_type = ira->codegen->builtin_types.entry_u8;
} else {
Error err;
ZigType *operand_ptr_type;
@@ -28376,7 +28372,8 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) {
}
static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAtomicRmw *instruction) {
- ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child);
+ ZigType *actual_type;
+ ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_inst_gen;
@@ -28434,11 +28431,12 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
}
return ir_build_atomic_rmw_gen(ira, &instruction->base.base, casted_ptr, casted_operand, op,
- ordering, operand_type);
+ ordering, operand_type, actual_type);
}
static IrInstGen *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstSrcAtomicLoad *instruction) {
- ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child);
+ ZigType *actual_type;
+ ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_inst_gen;
@@ -28468,11 +28466,12 @@ static IrInstGen *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstSrcAt
return result;
}
- return ir_build_atomic_load_gen(ira, &instruction->base.base, casted_ptr, ordering, operand_type);
+ return ir_build_atomic_load_gen(ira, &instruction->base.base, casted_ptr, ordering, operand_type, actual_type);
}
static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcAtomicStore *instruction) {
- ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child);
+ ZigType *actual_type;
+ ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_inst_gen;
@@ -28511,7 +28510,7 @@ static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcA
return result;
}
- return ir_build_atomic_store_gen(ira, &instruction->base.base, casted_ptr, casted_value, ordering);
+ return ir_build_atomic_store_gen(ira, &instruction->base.base, casted_ptr, casted_value, ordering, actual_type);
}
static IrInstGen *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstSrcSaveErrRetAddr *instruction) {
From 64e60d8ae2c06689a2e0533eb43a1c6a8ff01259 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 11 Mar 2020 10:29:15 +0200
Subject: [PATCH 052/111] special case atomic operations on zero bit types
---
src/ir.cpp | 37 ++++++++++++++++++++++++++------
test/stage1/behavior/atomics.zig | 27 ++++++++++++++++-------
2 files changed, 50 insertions(+), 14 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 9465be8b0..2e87bd268 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -25199,12 +25199,22 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
return ira->codegen->invalid_inst_gen;
}
+ ZigType *result_type = get_optional_type(ira->codegen, operand_type);
+
+ // special case zero bit types
+ if (type_has_one_possible_value(ira->codegen, operand_type) == OnePossibleValueYes) {
+ ZigValue *val = ira->codegen->pass1_arena->allocate(1);
+ val->special = ConstValSpecialStatic;
+ val->type = result_type;
+ set_optional_value_to_null(val);
+ return ir_const_move(ira, &instruction->base.base, val);
+ }
+
if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar &&
instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) {
zig_panic("TODO compile-time execution of cmpxchg");
}
- ZigType *result_type = get_optional_type(ira->codegen, operand_type);
IrInstGen *result_loc;
if (handle_is_ptr(ira->codegen, result_type)) {
result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
@@ -28317,18 +28327,23 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
*actual_type = nullptr;
if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) {
+ ZigType *int_type;
if (operand_type->id == ZigTypeIdEnum) {
- operand_type = operand_type->data.enumeration.tag_int_type;
+ int_type = operand_type->data.enumeration.tag_int_type;
+ } else {
+ int_type = operand_type;
}
+ auto bit_count = int_type->data.integral.bit_count;
+ bool is_signed = int_type->data.integral.is_signed;
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
- if (operand_type->data.integral.bit_count > max_atomic_bits) {
+
+ if (bit_count > max_atomic_bits) {
ir_add_error(ira, &op->base,
buf_sprintf("expected %" PRIu32 "-bit integer type or smaller, found %" PRIu32 "-bit integer type",
- max_atomic_bits, operand_type->data.integral.bit_count));
+ max_atomic_bits, bit_count));
return ira->codegen->builtin_types.entry_invalid;
}
- auto bit_count = operand_type->data.integral.bit_count;
- bool is_signed = operand_type->data.integral.is_signed;
+
if (bit_count < 2 || !is_power_of_2(bit_count)) {
if (bit_count < 8) {
*actual_type = get_int_type(ira->codegen, is_signed, 8);
@@ -28423,6 +28438,11 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
return ira->codegen->invalid_inst_gen;
}
+ // special case zero bit types
+ if (type_has_one_possible_value(ira->codegen, operand_type) == OnePossibleValueYes) {
+ return ir_const_move(ira, &instruction->base.base, get_the_one_possible_value(ira->codegen, operand_type));
+ }
+
if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar)
{
ir_add_error(ira, &instruction->base.base,
@@ -28504,6 +28524,11 @@ static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcA
return ira->codegen->invalid_inst_gen;
}
+ // special case zero bit types
+ if (type_has_one_possible_value(ira->codegen, operand_type) == OnePossibleValueYes) {
+ return ir_const_void(ira, &instruction->base.base);
+ }
+
if (instr_is_comptime(casted_value) && instr_is_comptime(casted_ptr)) {
IrInstGen *result = ir_analyze_store_ptr(ira, &instruction->base.base, casted_ptr, value, false);
result->value->type = ira->codegen->builtin_types.entry_void;
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index bda0a8469..edc712d85 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -162,12 +162,23 @@ fn testAtomicRmwFloat() void {
expect(x == 4);
}
-test "atomics with bool" {
- var x = false;
- @atomicStore(bool, &x, true, .SeqCst);
- expect(x == true);
- expect(@atomicLoad(bool, &x, .SeqCst) == true);
- expect(@atomicRmw(bool, &x, .Xchg, false, .SeqCst) == true);
- expect(@cmpxchgStrong(bool, &x, false, true, .SeqCst, .SeqCst) == null);
- expect(@cmpxchgStrong(bool, &x, false, true, .SeqCst, .SeqCst).? == true);
+test "atomics with different types" {
+ // testAtomicsWithType(bool, true, false);
+ // inline for (.{ u1, i5, u33 }) |T| {
+ // var x: T = 0;
+ // testAtomicsWithType(T, 0, 1);
+ // }
+ testAtomicsWithType(u0, 0, 0);
+ testAtomicsWithType(i0, 0, 0);
+}
+
+fn testAtomicsWithType(comptime T: type, a: T, b: T) void {
+ var x: T = b;
+ @atomicStore(T, &x, a, .SeqCst);
+ expect(x == a);
+ expect(@atomicLoad(T, &x, .SeqCst) == a);
+ expect(@atomicRmw(T, &x, .Xchg, b, .SeqCst) == a);
+ expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst) == null);
+ if (@sizeOf(T) != 0)
+ expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst).? == a);
}
From 1f66435a6b0c5ccf6e4e96df0ed96732480ab4db Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 11 Mar 2020 12:02:05 +0200
Subject: [PATCH 053/111] support cmpxchg at comptime
---
src/ir.cpp | 32 ++++++++++++------------
test/stage1/behavior/atomics.zig | 42 +++++++++++++++++---------------
2 files changed, 39 insertions(+), 35 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 2e87bd268..338f803bb 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -25212,7 +25212,20 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar &&
instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) {
- zig_panic("TODO compile-time execution of cmpxchg");
+ IrInstGen *result = ir_get_deref(ira, &instruction->base.base, casted_ptr, nullptr);
+ ZigValue *op1_val = ir_resolve_const(ira, result, UndefBad);
+ ZigValue *op2_val = ir_resolve_const(ira, casted_cmp_value, UndefBad);
+ bool eql = const_values_equal(ira->codegen, op1_val, op2_val);
+ ZigValue *val = ira->codegen->pass1_arena->allocate(1);
+ val->special = ConstValSpecialStatic;
+ val->type = result_type;
+ if (eql) {
+ ir_analyze_store_ptr(ira, &instruction->base.base, casted_ptr, casted_new_value, false);
+ set_optional_value_to_null(val);
+ } else {
+ set_optional_payload(val, op1_val);
+ }
+ return ir_const_move(ira, &instruction->base.base, val);
}
IrInstGen *result_loc;
@@ -28334,7 +28347,6 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
int_type = operand_type;
}
auto bit_count = int_type->data.integral.bit_count;
- bool is_signed = int_type->data.integral.is_signed;
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
if (bit_count > max_atomic_bits) {
@@ -28344,20 +28356,8 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
return ira->codegen->builtin_types.entry_invalid;
}
- if (bit_count < 2 || !is_power_of_2(bit_count)) {
- if (bit_count < 8) {
- *actual_type = get_int_type(ira->codegen, is_signed, 8);
- } else if (bit_count < 16) {
- *actual_type = get_int_type(ira->codegen, is_signed, 16);
- } else if (bit_count < 32) {
- *actual_type = get_int_type(ira->codegen, is_signed, 32);
- } else if (bit_count < 64) {
- *actual_type = get_int_type(ira->codegen, is_signed, 64);
- } else if (bit_count < 128) {
- *actual_type = get_int_type(ira->codegen, is_signed, 128);
- } else {
- zig_unreachable();
- }
+ if (bit_count == 1 || !is_power_of_2(bit_count)) {
+ *actual_type = get_int_type(ira->codegen, int_type->data.integral.is_signed, int_type->abi_size * 8);
}
} else if (operand_type->id == ZigTypeIdFloat) {
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index edc712d85..9c75afc36 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -2,29 +2,32 @@ const std = @import("std");
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const builtin = @import("builtin");
-const AtomicRmwOp = builtin.AtomicRmwOp;
-const AtomicOrder = builtin.AtomicOrder;
test "cmpxchg" {
+ testCmpxchg();
+ comptime testCmpxchg();
+}
+
+fn testCmpxchg() void {
var x: i32 = 1234;
- if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+ if (@cmpxchgWeak(i32, &x, 99, 5678, .SeqCst, .SeqCst)) |x1| {
expect(x1 == 1234);
} else {
@panic("cmpxchg should have failed");
}
- while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+ while (@cmpxchgWeak(i32, &x, 1234, 5678, .SeqCst, .SeqCst)) |x1| {
expect(x1 == 1234);
}
expect(x == 5678);
- expect(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+ expect(@cmpxchgStrong(i32, &x, 5678, 42, .SeqCst, .SeqCst) == null);
expect(x == 42);
}
test "fence" {
var x: i32 = 1234;
- @fence(AtomicOrder.SeqCst);
+ @fence(.SeqCst);
x = 5678;
}
@@ -36,18 +39,18 @@ test "atomicrmw and atomicload" {
}
fn testAtomicRmw(ptr: *u8) void {
- const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
+ const prev_value = @atomicRmw(u8, ptr, .Xchg, 42, .SeqCst);
expect(prev_value == 200);
comptime {
var x: i32 = 1234;
const y: i32 = 12345;
- expect(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
- expect(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
+ expect(@atomicLoad(i32, &x, .SeqCst) == 1234);
+ expect(@atomicLoad(i32, &y, .SeqCst) == 12345);
}
}
fn testAtomicLoad(ptr: *u8) void {
- const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
+ const x = @atomicLoad(u8, ptr, .SeqCst);
expect(x == 42);
}
@@ -56,18 +59,18 @@ test "cmpxchg with ptr" {
var data2: i32 = 5678;
var data3: i32 = 9101;
var x: *i32 = &data1;
- if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+ if (@cmpxchgWeak(*i32, &x, &data2, &data3, .SeqCst, .SeqCst)) |x1| {
expect(x1 == &data1);
} else {
@panic("cmpxchg should have failed");
}
- while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
+ while (@cmpxchgWeak(*i32, &x, &data1, &data3, .SeqCst, .SeqCst)) |x1| {
expect(x1 == &data1);
}
expect(x == &data3);
- expect(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+ expect(@cmpxchgStrong(*i32, &x, &data3, &data2, .SeqCst, .SeqCst) == null);
expect(x == &data2);
}
@@ -163,16 +166,17 @@ fn testAtomicRmwFloat() void {
}
test "atomics with different types" {
- // testAtomicsWithType(bool, true, false);
- // inline for (.{ u1, i5, u33 }) |T| {
- // var x: T = 0;
- // testAtomicsWithType(T, 0, 1);
- // }
+ testAtomicsWithType(bool, true, false);
+ inline for (.{ u1, i5, u33 }) |T| {
+ var x: T = 0;
+ testAtomicsWithType(T, 0, 1);
+ }
testAtomicsWithType(u0, 0, 0);
testAtomicsWithType(i0, 0, 0);
}
-fn testAtomicsWithType(comptime T: type, a: T, b: T) void {
+// a and b souldn't need to be comptime
+fn testAtomicsWithType(comptime T: type, comptime a: T, comptime b: T) void {
var x: T = b;
@atomicStore(T, &x, a, .SeqCst);
expect(x == a);
From ec906a97712b329694e8f2e1a35b50b75d052642 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 11 Mar 2020 13:29:17 +0200
Subject: [PATCH 054/111] fix codegen, update docs
---
doc/langref.html.in | 45 +++++++-------------------------
src/codegen.cpp | 10 +++----
test/stage1/behavior/atomics.zig | 5 ++--
3 files changed, 17 insertions(+), 43 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 447d54597..0dedb48b1 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -6728,17 +6728,8 @@ async fn func(y: *i32) void {
This builtin function atomically dereferences a pointer and returns the value.
- {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#}, a float,
- an integer whose bit count meets these requirements:
-
-
- - At least 8
- - At most the same as usize
- - Power of 2
-
or an enum with a valid integer tag type.
-
- TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
- we can remove this restriction
+ {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float,
+ an integer or an enum.
{#header_close#}
{#header_open|@atomicRmw#}
@@ -6747,17 +6738,8 @@ async fn func(y: *i32) void {
This builtin function atomically modifies memory and then returns the previous value.
- {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#},
- or an integer whose bit count meets these requirements:
-
-
- - At least 8
- - At most the same as usize
- - Power of 2
-
-
- TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
- we can remove this restriction
+ {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float,
+ an integer or an enum.
Supported operations:
@@ -6782,17 +6764,8 @@ async fn func(y: *i32) void {
This builtin function atomically stores a value.
- {#syntax#}T{#endsyntax#} must be a pointer type, a {#syntax#}bool{#endsyntax#}, a float,
- an integer whose bit count meets these requirements:
-
-
- - At least 8
- - At most the same as usize
- - Power of 2
-
or an enum with a valid integer tag type.
-
- TODO right now bool is not accepted. Also I think we could make non powers of 2 work fine, maybe
- we can remove this restriction
+ {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float,
+ an integer or an enum.
{#header_close#}
{#header_open|@bitCast#}
@@ -7108,7 +7081,8 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v
more efficiently in machine instructions.
- {#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("builtin").AtomicOrder{#endsyntax#}.
+ {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float,
+ an integer or an enum.
{#syntax#}@TypeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#see_also|Compile Variables|cmpxchgWeak#}
@@ -7136,7 +7110,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
- {#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("builtin").AtomicOrder{#endsyntax#}.
+ {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float,
+ an integer or an enum.
{#syntax#}@TypeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#see_also|Compile Variables|cmpxchgStrong#}
diff --git a/src/codegen.cpp b/src/codegen.cpp
index cfb3de292..66cf919d8 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5229,8 +5229,8 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
// operand needs widening and truncating
ptr_val = LLVMBuildBitCast(g->builder, ptr_val,
LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
- cmp_val = LLVMConstZExt(cmp_val, get_llvm_type(g, instruction->actual_type));
- new_val = LLVMConstZExt(new_val, get_llvm_type(g, instruction->actual_type));
+ cmp_val = LLVMBuildZExt(g->builder, cmp_val, get_llvm_type(g, instruction->actual_type), "");
+ new_val = LLVMBuildZExt(g->builder, new_val, get_llvm_type(g, instruction->actual_type), "");
}
LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
@@ -5846,7 +5846,7 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutableGen *executable
// operand needs widening and truncating
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
- LLVMValueRef casted_operand = LLVMBuildPtrToInt(g->builder, operand, get_llvm_type(g, instruction->actual_type), "");
+ LLVMValueRef casted_operand = LLVMBuildZExt(g->builder, operand, get_llvm_type(g, instruction->actual_type), "");
LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
g->is_single_threaded);
return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
@@ -5893,10 +5893,10 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutableGen *executab
LLVMValueRef value = ir_llvm_value(g, instruction->value);
if (instruction->actual_type != nullptr) {
- // operand needs widening and truncating
+ // operand needs widening
ptr = LLVMBuildBitCast(g->builder, ptr,
LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
- value = LLVMConstZExt(value, get_llvm_type(g, instruction->actual_type));
+ value = LLVMBuildZExt(g->builder, value, get_llvm_type(g, instruction->actual_type), "");
}
LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value->type);
LLVMSetOrdering(store_inst, ordering);
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index 9c75afc36..c655bfe7a 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -167,7 +167,7 @@ fn testAtomicRmwFloat() void {
test "atomics with different types" {
testAtomicsWithType(bool, true, false);
- inline for (.{ u1, i5, u33 }) |T| {
+ inline for (.{ u1, i5, u15 }) |T| {
var x: T = 0;
testAtomicsWithType(T, 0, 1);
}
@@ -175,8 +175,7 @@ test "atomics with different types" {
testAtomicsWithType(i0, 0, 0);
}
-// a and b souldn't need to be comptime
-fn testAtomicsWithType(comptime T: type, comptime a: T, comptime b: T) void {
+fn testAtomicsWithType(comptime T: type, a: T, b: T) void {
var x: T = b;
@atomicStore(T, &x, a, .SeqCst);
expect(x == a);
From 9262f065f50db3ea72454b6c1b9b66fd911aa6ba Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 11 Mar 2020 16:46:12 +0200
Subject: [PATCH 055/111] Move abi size checking to codegen
---
lib/std/atomic/int.zig | 13 +++-----
src/all_types.hpp | 8 -----
src/codegen.cpp | 61 +++++++++++++++++++++++++++--------
src/ir.cpp | 73 ++++++++++++++++++------------------------
4 files changed, 84 insertions(+), 71 deletions(-)
diff --git a/lib/std/atomic/int.zig b/lib/std/atomic/int.zig
index 94985b914..446059e7e 100644
--- a/lib/std/atomic/int.zig
+++ b/lib/std/atomic/int.zig
@@ -1,6 +1,3 @@
-const builtin = @import("builtin");
-const AtomicOrder = builtin.AtomicOrder;
-
/// Thread-safe, lock-free integer
pub fn Int(comptime T: type) type {
return struct {
@@ -14,16 +11,16 @@ pub fn Int(comptime T: type) type {
/// Returns previous value
pub fn incr(self: *Self) T {
- return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
+ return @atomicRmw(T, &self.unprotected_value, .Add, 1, .SeqCst);
}
/// Returns previous value
pub fn decr(self: *Self) T {
- return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
+ return @atomicRmw(T, &self.unprotected_value, .Sub, 1, .SeqCst);
}
pub fn get(self: *Self) T {
- return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst);
+ return @atomicLoad(T, &self.unprotected_value, .SeqCst);
}
pub fn set(self: *Self, new_value: T) void {
@@ -31,11 +28,11 @@ pub fn Int(comptime T: type) type {
}
pub fn xchg(self: *Self, new_value: T) T {
- return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Xchg, new_value, AtomicOrder.SeqCst);
+ return @atomicRmw(T, &self.unprotected_value, .Xchg, new_value, .SeqCst);
}
pub fn fetchAdd(self: *Self, op: T) T {
- return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Add, op, AtomicOrder.SeqCst);
+ return @atomicRmw(T, &self.unprotected_value, .Add, op, .SeqCst);
}
};
}
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 149b7f464..14b99228c 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -3567,8 +3567,6 @@ struct IrInstGenCmpxchg {
IrInstGen *cmp_value;
IrInstGen *new_value;
IrInstGen *result_loc;
- // non null if operand needs widening and truncating
- ZigType *actual_type;
bool is_weak;
};
@@ -4201,8 +4199,6 @@ struct IrInstGenAtomicRmw {
IrInstGen *ptr;
IrInstGen *operand;
- // non null if operand needs widening and truncating
- ZigType *actual_type;
AtomicRmwOp op;
AtomicOrder ordering;
};
@@ -4219,8 +4215,6 @@ struct IrInstGenAtomicLoad {
IrInstGen base;
IrInstGen *ptr;
- // non null if operand needs widening and truncating
- ZigType *actual_type;
AtomicOrder ordering;
};
@@ -4238,8 +4232,6 @@ struct IrInstGenAtomicStore {
IrInstGen *ptr;
IrInstGen *value;
- // non null if operand needs widening and truncating
- ZigType *actual_type;
AtomicOrder ordering;
};
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 66cf919d8..55713c1b8 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5219,18 +5219,48 @@ static enum ZigLLVM_AtomicRMWBinOp to_ZigLLVMAtomicRMWBinOp(AtomicRmwOp op, bool
zig_unreachable();
}
+static LLVMTypeRef get_atomic_abi_type(CodeGen *g, IrInstGen *instruction) {
+ // If the operand type of an atomic operation is not a power of two sized
+ // we need to widen it before using it and then truncate the result.
+
+ ir_assert(instruction->value->type->id == ZigTypeIdPointer, instruction);
+ ZigType *operand_type = instruction->value->type->data.pointer.child_type;
+ if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) {
+ if (operand_type->id == ZigTypeIdEnum) {
+ operand_type = operand_type->data.enumeration.tag_int_type;
+ }
+ auto bit_count = operand_type->data.integral.bit_count;
+ bool is_signed = operand_type->data.integral.is_signed;
+
+ ir_assert(bit_count != 0, instruction);
+ if (bit_count == 1 || !is_power_of_2(bit_count)) {
+ return get_llvm_type(g, get_int_type(g, is_signed, operand_type->abi_size * 8));
+ } else {
+ return nullptr;
+ }
+ } else if (operand_type->id == ZigTypeIdFloat) {
+ return nullptr;
+ } else if (operand_type->id == ZigTypeIdBool) {
+ return g->builtin_types.entry_u8->llvm_type;
+ } else {
+ ir_assert(get_codegen_ptr_type_bail(g, operand_type) != nullptr, instruction);
+ return nullptr;
+ }
+}
+
static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, IrInstGenCmpxchg *instruction) {
LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
ZigType *operand_type = instruction->new_value->value->type;
- if (instruction->actual_type != nullptr) {
+ LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr);
+ if (actual_abi_type != nullptr) {
// operand needs widening and truncating
ptr_val = LLVMBuildBitCast(g->builder, ptr_val,
- LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
- cmp_val = LLVMBuildZExt(g->builder, cmp_val, get_llvm_type(g, instruction->actual_type), "");
- new_val = LLVMBuildZExt(g->builder, new_val, get_llvm_type(g, instruction->actual_type), "");
+ LLVMPointerType(actual_abi_type, 0), "");
+ cmp_val = LLVMBuildZExt(g->builder, cmp_val, actual_abi_type, "");
+ new_val = LLVMBuildZExt(g->builder, new_val, actual_abi_type, "");
}
LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
@@ -5245,7 +5275,7 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
if (!handle_is_ptr(g, optional_type)) {
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- if (instruction->actual_type != nullptr) {
+ if (actual_abi_type != nullptr) {
payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), "");
}
LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
@@ -5262,7 +5292,7 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
ir_assert(type_has_bits(g, child_type), &instruction->base);
LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- if (instruction->actual_type != nullptr) {
+ if (actual_abi_type != nullptr) {
payload_val = LLVMBuildTrunc(g->builder, payload_val, get_llvm_type(g, operand_type), "");
}
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, "");
@@ -5842,11 +5872,12 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutableGen *executable
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
- if (instruction->actual_type != nullptr) {
+ LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr);
+ if (actual_abi_type != nullptr) {
// operand needs widening and truncating
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
- LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
- LLVMValueRef casted_operand = LLVMBuildZExt(g->builder, operand, get_llvm_type(g, instruction->actual_type), "");
+ LLVMPointerType(actual_abi_type, 0), "");
+ LLVMValueRef casted_operand = LLVMBuildZExt(g->builder, operand, actual_abi_type, "");
LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
g->is_single_threaded);
return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
@@ -5872,10 +5903,11 @@ static LLVMValueRef ir_render_atomic_load(CodeGen *g, IrExecutableGen *executabl
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
ZigType *operand_type = instruction->ptr->value->type->data.pointer.child_type;
- if (instruction->actual_type != nullptr) {
+ LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr);
+ if (actual_abi_type != nullptr) {
// operand needs widening and truncating
ptr = LLVMBuildBitCast(g->builder, ptr,
- LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
+ LLVMPointerType(actual_abi_type, 0), "");
LLVMValueRef load_inst = gen_load(g, ptr, instruction->ptr->value->type, "");
LLVMSetOrdering(load_inst, ordering);
return LLVMBuildTrunc(g->builder, load_inst, get_llvm_type(g, operand_type), "");
@@ -5892,11 +5924,12 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutableGen *executab
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
LLVMValueRef value = ir_llvm_value(g, instruction->value);
- if (instruction->actual_type != nullptr) {
+ LLVMTypeRef actual_abi_type = get_atomic_abi_type(g, instruction->ptr);
+ if (actual_abi_type != nullptr) {
// operand needs widening
ptr = LLVMBuildBitCast(g->builder, ptr,
- LLVMPointerType(get_llvm_type(g, instruction->actual_type), 0), "");
- value = LLVMBuildZExt(g->builder, value, get_llvm_type(g, instruction->actual_type), "");
+ LLVMPointerType(actual_abi_type, 0), "");
+ value = LLVMBuildZExt(g->builder, value, actual_abi_type, "");
}
LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value->type);
LLVMSetOrdering(store_inst, ordering);
diff --git a/src/ir.cpp b/src/ir.cpp
index 338f803bb..dc3e7941d 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -227,7 +227,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
static void ir_assert(bool ok, IrInst* source_instruction);
static void ir_assert_gen(bool ok, IrInstGen *source_instruction);
static IrInstGen *ir_get_var_ptr(IrAnalyze *ira, IrInst *source_instr, ZigVar *var);
-static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, ZigType **actual_type);
+static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op);
static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, ResultLoc *result_loc);
static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc);
static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align);
@@ -3406,7 +3406,7 @@ static IrInstSrc *ir_build_cmpxchg_src(IrBuilderSrc *irb, Scope *scope, AstNode
static IrInstGen *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type,
IrInstGen *ptr, IrInstGen *cmp_value, IrInstGen *new_value,
- AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstGen *result_loc, ZigType *actual_type)
+ AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstGen *result_loc)
{
IrInstGenCmpxchg *instruction = ir_build_inst_gen(&ira->new_irb,
source_instruction->scope, source_instruction->source_node);
@@ -3418,7 +3418,6 @@ static IrInstGen *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInst *source_instructio
instruction->failure_order = failure_order;
instruction->is_weak = is_weak;
instruction->result_loc = result_loc;
- instruction->actual_type = actual_type;
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
ir_ref_inst_gen(cmp_value, ira->new_irb.current_basic_block);
@@ -4555,7 +4554,7 @@ static IrInstSrc *ir_build_atomic_rmw_src(IrBuilderSrc *irb, Scope *scope, AstNo
}
static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr,
- IrInstGen *ptr, IrInstGen *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type, ZigType *actual_type)
+ IrInstGen *ptr, IrInstGen *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type)
{
IrInstGenAtomicRmw *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node);
instruction->base.value->type = operand_type;
@@ -4563,7 +4562,6 @@ static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr,
instruction->op = op;
instruction->operand = operand;
instruction->ordering = ordering;
- instruction->actual_type = actual_type;
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
ir_ref_inst_gen(operand, ira->new_irb.current_basic_block);
@@ -4587,14 +4585,13 @@ static IrInstSrc *ir_build_atomic_load_src(IrBuilderSrc *irb, Scope *scope, AstN
}
static IrInstGen *ir_build_atomic_load_gen(IrAnalyze *ira, IrInst *source_instr,
- IrInstGen *ptr, AtomicOrder ordering, ZigType *operand_type, ZigType *actual_type)
+ IrInstGen *ptr, AtomicOrder ordering, ZigType *operand_type)
{
IrInstGenAtomicLoad *instruction = ir_build_inst_gen(&ira->new_irb,
source_instr->scope, source_instr->source_node);
instruction->base.value->type = operand_type;
instruction->ptr = ptr;
instruction->ordering = ordering;
- instruction->actual_type = actual_type;
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
@@ -4619,14 +4616,13 @@ static IrInstSrc *ir_build_atomic_store_src(IrBuilderSrc *irb, Scope *scope, Ast
}
static IrInstGen *ir_build_atomic_store_gen(IrAnalyze *ira, IrInst *source_instr,
- IrInstGen *ptr, IrInstGen *value, AtomicOrder ordering, ZigType *actual_type)
+ IrInstGen *ptr, IrInstGen *value, AtomicOrder ordering)
{
IrInstGenAtomicStore *instruction = ir_build_inst_void(&ira->new_irb,
source_instr->scope, source_instr->source_node);
instruction->ptr = ptr;
instruction->value = value;
instruction->ordering = ordering;
- instruction->actual_type = actual_type;
ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
ir_ref_inst_gen(value, ira->new_irb.current_basic_block);
@@ -25125,8 +25121,7 @@ static IrInstGen *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstSrcEmb
}
static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxchg *instruction) {
- ZigType *actual_type;
- ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child, &actual_type);
+ ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_inst_gen;
@@ -25203,29 +25198,34 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
// special case zero bit types
if (type_has_one_possible_value(ira->codegen, operand_type) == OnePossibleValueYes) {
- ZigValue *val = ira->codegen->pass1_arena->allocate(1);
- val->special = ConstValSpecialStatic;
- val->type = result_type;
- set_optional_value_to_null(val);
- return ir_const_move(ira, &instruction->base.base, val);
+ IrInstGen *result = ir_const(ira, &instruction->base.base, result_type);
+ set_optional_value_to_null(result->value);
+ return result;
}
if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar &&
instr_is_comptime(casted_cmp_value) && instr_is_comptime(casted_new_value)) {
- IrInstGen *result = ir_get_deref(ira, &instruction->base.base, casted_ptr, nullptr);
- ZigValue *op1_val = ir_resolve_const(ira, result, UndefBad);
+ ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ ZigValue *op1_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.base.source_node);
+ if (op1_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
ZigValue *op2_val = ir_resolve_const(ira, casted_cmp_value, UndefBad);
+ if (op2_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
bool eql = const_values_equal(ira->codegen, op1_val, op2_val);
- ZigValue *val = ira->codegen->pass1_arena->allocate(1);
- val->special = ConstValSpecialStatic;
- val->type = result_type;
+ IrInstGen *result = ir_const(ira, &instruction->base.base, result_type);
if (eql) {
ir_analyze_store_ptr(ira, &instruction->base.base, casted_ptr, casted_new_value, false);
- set_optional_value_to_null(val);
+ set_optional_value_to_null(result->value);
} else {
- set_optional_payload(val, op1_val);
+ set_optional_payload(result->value, op1_val);
}
- return ir_const_move(ira, &instruction->base.base, val);
+ return result;
}
IrInstGen *result_loc;
@@ -25241,7 +25241,7 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
return ir_build_cmpxchg_gen(ira, &instruction->base.base, result_type,
casted_ptr, casted_cmp_value, casted_new_value,
- success_order, failure_order, instruction->is_weak, result_loc, actual_type);
+ success_order, failure_order, instruction->is_weak, result_loc);
}
static IrInstGen *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstSrcFence *instruction) {
@@ -28333,12 +28333,11 @@ static IrInstGen *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstSrcTagTy
}
}
-static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, ZigType **actual_type) {
+static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) {
ZigType *operand_type = ir_resolve_type(ira, op);
if (type_is_invalid(operand_type))
return ira->codegen->builtin_types.entry_invalid;
- *actual_type = nullptr;
if (operand_type->id == ZigTypeIdInt || operand_type->id == ZigTypeIdEnum) {
ZigType *int_type;
if (operand_type->id == ZigTypeIdEnum) {
@@ -28355,10 +28354,6 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
max_atomic_bits, bit_count));
return ira->codegen->builtin_types.entry_invalid;
}
-
- if (bit_count == 1 || !is_power_of_2(bit_count)) {
- *actual_type = get_int_type(ira->codegen, int_type->data.integral.is_signed, int_type->abi_size * 8);
- }
} else if (operand_type->id == ZigTypeIdFloat) {
uint32_t max_atomic_bits = target_arch_largest_atomic_bits(ira->codegen->zig_target->arch);
if (operand_type->data.floating.bit_count > max_atomic_bits) {
@@ -28369,7 +28364,6 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
}
} else if (operand_type->id == ZigTypeIdBool) {
// will be treated as u8
- *actual_type = ira->codegen->builtin_types.entry_u8;
} else {
Error err;
ZigType *operand_ptr_type;
@@ -28387,8 +28381,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op, Zi
}
static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAtomicRmw *instruction) {
- ZigType *actual_type;
- ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type);
+ ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_inst_gen;
@@ -28451,12 +28444,11 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
}
return ir_build_atomic_rmw_gen(ira, &instruction->base.base, casted_ptr, casted_operand, op,
- ordering, operand_type, actual_type);
+ ordering, operand_type);
}
static IrInstGen *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstSrcAtomicLoad *instruction) {
- ZigType *actual_type;
- ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type);
+ ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_inst_gen;
@@ -28486,12 +28478,11 @@ static IrInstGen *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstSrcAt
return result;
}
- return ir_build_atomic_load_gen(ira, &instruction->base.base, casted_ptr, ordering, operand_type, actual_type);
+ return ir_build_atomic_load_gen(ira, &instruction->base.base, casted_ptr, ordering, operand_type);
}
static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcAtomicStore *instruction) {
- ZigType *actual_type;
- ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child, &actual_type);
+ ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->operand_type->child);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_inst_gen;
@@ -28535,7 +28526,7 @@ static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcA
return result;
}
- return ir_build_atomic_store_gen(ira, &instruction->base.base, casted_ptr, casted_value, ordering, actual_type);
+ return ir_build_atomic_store_gen(ira, &instruction->base.base, casted_ptr, casted_value, ordering);
}
static IrInstGen *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstSrcSaveErrRetAddr *instruction) {
From 02ba1d8fe14a034e5873a56b4aef9c2801dc52e9 Mon Sep 17 00:00:00 2001
From: Heppokoyuki
Date: Thu, 12 Mar 2020 00:15:22 +0900
Subject: [PATCH 056/111] add file protocols
---
lib/std/os/uefi/protocols.zig | 4 +
lib/std/os/uefi/protocols/file_protocol.zig | 87 +++++++++++++++++++
.../protocols/simple_file_system_protocol.zig | 21 +++++
3 files changed, 112 insertions(+)
create mode 100644 lib/std/os/uefi/protocols/file_protocol.zig
create mode 100644 lib/std/os/uefi/protocols/simple_file_system_protocol.zig
diff --git a/lib/std/os/uefi/protocols.zig b/lib/std/os/uefi/protocols.zig
index 58f342ac2..500a246e2 100644
--- a/lib/std/os/uefi/protocols.zig
+++ b/lib/std/os/uefi/protocols.zig
@@ -2,6 +2,10 @@ pub const LoadedImageProtocol = @import("protocols/loaded_image_protocol.zig").L
pub const DevicePathProtocol = @import("protocols/device_path_protocol.zig").DevicePathProtocol;
+pub const SimpleFileSystemProtocol = @import("protocols/simple_file_system_protocol.zig").SimpleFileSystemProtocol;
+pub const FileProtocol = @import("protocols/file_protocol.zig").FileProtocol;
+pub const FileInfo = @import("protocols/file_protocol.zig").FileInfo;
+
pub const InputKey = @import("protocols/simple_text_input_ex_protocol.zig").InputKey;
pub const KeyData = @import("protocols/simple_text_input_ex_protocol.zig").KeyData;
pub const KeyState = @import("protocols/simple_text_input_ex_protocol.zig").KeyState;
diff --git a/lib/std/os/uefi/protocols/file_protocol.zig b/lib/std/os/uefi/protocols/file_protocol.zig
new file mode 100644
index 000000000..cc6785caf
--- /dev/null
+++ b/lib/std/os/uefi/protocols/file_protocol.zig
@@ -0,0 +1,87 @@
+const uefi = @import("std").os.uefi;
+const Guid = uefi.Guid;
+const Time = uefi.Time;
+
+const FileProtocol = extern struct {
+ revision: u64,
+ _open: extern fn (*const FileProtocol, **const FileProtocol, *u16, u64, u64) usize,
+ _close: extern fn (*const FileProtocol) usize,
+ _delete: extern fn (*const FileProtocol) usize,
+ _read: extern fn (*const FileProtocol, *usize, *c_void) usize,
+ _write: extern fn (*const FileProtocol, *usize, *c_void) usize,
+ _get_info: extern fn (*const FileProtocol, *Guid, *usize, *c_void) usize,
+ _set_info: extern fn (*const FileProtocol, *Guid, usize, *c_void) usize,
+ _flush: extern fn (*const FileProtocol) usize,
+
+ pub fn open(self: *const FileProtocol, new_handle: **const FileProtocol, file_name: *u16, open_mode: u64, attributes: u64) usize {
+ return self._open(self, new_handle, file_name, open_mode, attributes);
+ }
+
+ pub fn close(self: *const FileProtocol) usize {
+ return self._close(self);
+ }
+
+ pub fn delete(self: *const FileProtocol) usize {
+ return self._delete(self);
+ }
+
+ pub fn read(self: *const FileProtocol, buffer_size: *usize, buffer: *c_void) usize {
+ return self._read(self, buffer_size, buffer);
+ }
+
+ pub fn write(self: *const FileProtocol, buffer_size: *usize, buffer: *c_void) usize {
+ return self._write(self, buffer_size, buffer);
+ }
+
+ pub fn get_info(self: *const FileProtocol, information_type: *Guid, buffer_size: *usize, buffer: *c_void) usize {
+ return self._get_info(self, information_type, buffer_size, buffer);
+ }
+
+ pub fn set_info(self: *const FileProtocol, information_type: *Guid, buffer_size: usize, buffer: *c_void) usize {
+ return self._set_info(self, information_type, buffer_size, buffer);
+ }
+
+ pub fn flush(self: *const FileProtocol) usize {
+ return self._flush(self);
+ }
+
+ pub const guid align(8) = Guid{
+ .time_low = 0x09576e92,
+ .time_mid = 0x6d3f,
+ .time_high_and_version = 0x11d2,
+ .clock_seq_high_and_reserved = 0x8e,
+ .clock_seq_low = 0x39,
+ .node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b },
+ };
+
+ pub const efi_file_mode_read: u64 = 0x0000000000000001;
+ pub const efi_file_mode_write: u64 = 0x0000000000000002;
+ pub const efi_file_mode_create: u64 = 0x8000000000000000;
+
+ pub const efi_file_read_only: u64 = 0x0000000000000001;
+ pub const efi_file_hidden: u64 = 0x0000000000000002;
+ pub const efi_file_system: u64 = 0x0000000000000004;
+ pub const efi_file_reserved: u64 = 0x0000000000000008;
+ pub const efi_file_directory: u64 = 0x0000000000000010;
+ pub const efi_file_archive: u64 = 0x0000000000000020;
+ pub const efi_file_valid_attr: u64 = 0x0000000000000037;
+};
+
+const FileInfo = extern struct {
+ size: u64,
+ file_size: u64,
+ physical_size: u64,
+ create_time: Time,
+ last_access_time: Time,
+ modification_time: Time,
+ attribute: u64,
+ file_name: [100:0]u16,
+
+ pub const efi_file_read_only: u64 = 0x0000000000000001;
+ pub const efi_file_hidden: u64 = 0x0000000000000002;
+ pub const efi_file_system: u64 = 0x0000000000000004;
+ pub const efi_file_reserved: u64 = 0x0000000000000008;
+ pub const efi_file_directory: u64 = 0x0000000000000010;
+ pub const efi_file_archive: u64 = 0x0000000000000020;
+ pub const efi_file_valid_attr: u64 = 0x0000000000000037;
+};
diff --git a/lib/std/os/uefi/protocols/simple_file_system_protocol.zig b/lib/std/os/uefi/protocols/simple_file_system_protocol.zig
new file mode 100644
index 000000000..41bfaa18a
--- /dev/null
+++ b/lib/std/os/uefi/protocols/simple_file_system_protocol.zig
@@ -0,0 +1,21 @@
+const uefi = @import("std").os.uefi;
+const Guid = uefi.Guid;
+const FileProtocol = uefi.protocols.FileProtocol;
+
+const SimpleFileSystemProtocol = extern struct {
+ revision: u64,
+ _open_volume: extern fn (*const SimpleFileSystemProtocol, **const FileProtocol) usize,
+
+ pub fn openVolume(self: *const SimpleFileSystemProtocol, root: **const FileProtocol) usize {
+ return self._open_volume(self, root);
+ }
+
+ pub const guid align(8) = Guid{
+ .time_low = 0x0964e5b22,
+ .time_mid = 0x6459,
+ .time_high_and_version = 0x11d2,
+ .clock_seq_high_and_reserved = 0x8e,
+ .clock_seq_low = 0x39,
+ .node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b },
+ };
+};
From 58941927c426f61a6680348e4380f9f4eed3e8a8 Mon Sep 17 00:00:00 2001
From: Heppokoyuki
Date: Thu, 12 Mar 2020 00:16:45 +0900
Subject: [PATCH 057/111] refactor
---
lib/std/os/uefi/protocols/simple_text_input_protocol.zig | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/std/os/uefi/protocols/simple_text_input_protocol.zig b/lib/std/os/uefi/protocols/simple_text_input_protocol.zig
index b56ff728e..a6d5f837a 100644
--- a/lib/std/os/uefi/protocols/simple_text_input_protocol.zig
+++ b/lib/std/os/uefi/protocols/simple_text_input_protocol.zig
@@ -1,11 +1,12 @@
const uefi = @import("std").os.uefi;
const Event = uefi.Event;
const Guid = uefi.Guid;
+const InputKey = uefi.protocols.InputKey;
/// Character input devices, e.g. Keyboard
pub const SimpleTextInputProtocol = extern struct {
_reset: extern fn (*const SimpleTextInputProtocol, bool) usize,
- _read_key_stroke: extern fn (*const SimpleTextInputProtocol, *uefi.protocols.InputKey) usize,
+ _read_key_stroke: extern fn (*const SimpleTextInputProtocol, *InputKey) usize,
wait_for_key: Event,
/// Resets the input device hardware.
@@ -14,7 +15,7 @@ pub const SimpleTextInputProtocol = extern struct {
}
/// Reads the next keystroke from the input device.
- pub fn readKeyStroke(self: *const SimpleTextInputProtocol, input_key: *uefi.protocols.InputKey) usize {
+ pub fn readKeyStroke(self: *const SimpleTextInputProtocol, input_key: *InputKey) usize {
return self._read_key_stroke(self, input_key);
}
From d96b6c0d9f7a4fc6e7e28dd92d18e548f00885de Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 11 Mar 2020 13:06:30 -0400
Subject: [PATCH 058/111] fix footguns in File readAll functions
---
lib/std/fs.zig | 33 ++++++++++++-------------------
lib/std/fs/file.zig | 42 +++++++++++++++++++++++++++++++---------
lib/std/io/in_stream.zig | 5 +----
lib/std/os/test.zig | 32 +++++++++++++++++++++++++++---
4 files changed, 75 insertions(+), 37 deletions(-)
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index 892b97729..de6be91f7 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -96,6 +96,7 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {
/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.
/// Returns the previous status of the file before updating.
/// If any of the directories do not exist for dest_path, they are created.
+/// TODO rework this to integrate with Dir
pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus {
const my_cwd = cwd();
@@ -141,29 +142,25 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil
/// there is a possibility of power loss or application termination leaving temporary files present
/// in the same directory as dest_path.
/// Destination file will have the same mode as the source file.
+/// TODO rework this to integrate with Dir
pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
var in_file = try cwd().openFile(source_path, .{});
defer in_file.close();
- const mode = try in_file.mode();
- const in_stream = &in_file.inStream().stream;
+ const stat = try in_file.stat();
- var atomic_file = try AtomicFile.init(dest_path, mode);
+ var atomic_file = try AtomicFile.init(dest_path, stat.mode);
defer atomic_file.deinit();
- var buf: [mem.page_size]u8 = undefined;
- while (true) {
- const amt = try in_stream.readFull(buf[0..]);
- try atomic_file.file.write(buf[0..amt]);
- if (amt != buf.len) {
- return atomic_file.finish();
- }
- }
+ try atomic_file.file.writeFileAll(in_file, .{ .in_len = stat.size });
+ return atomic_file.finish();
}
-/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
-/// merged and readily available,
+/// Guaranteed to be atomic.
+/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
/// there is a possibility of power loss or application termination leaving temporary files present
+/// in the same directory as dest_path.
+/// TODO rework this to integrate with Dir
pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
var in_file = try cwd().openFile(source_path, .{});
defer in_file.close();
@@ -171,14 +168,8 @@ pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.M
var atomic_file = try AtomicFile.init(dest_path, mode);
defer atomic_file.deinit();
- var buf: [mem.page_size * 6]u8 = undefined;
- while (true) {
- const amt = try in_file.read(buf[0..]);
- try atomic_file.file.write(buf[0..amt]);
- if (amt != buf.len) {
- return atomic_file.finish();
- }
- }
+ try atomic_file.file.writeFileAll(in_file, .{});
+ return atomic_file.finish();
}
/// TODO update this API to avoid a getrandom syscall for every operation. It
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 845e4bc75..8362f94ca 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -250,11 +250,16 @@ pub const File = struct {
}
}
- pub fn readAll(self: File, buffer: []u8) ReadError!void {
+ /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
+ /// means the file reached the end. Reaching the end of a file is not an error condition.
+ pub fn readAll(self: File, buffer: []u8) ReadError!usize {
var index: usize = 0;
- while (index < buffer.len) {
- index += try self.read(buffer[index..]);
+ while (index != buffer.len) {
+ const amt = try self.read(buffer[index..]);
+ if (amt == 0) break;
+ index += amt;
}
+ return index;
}
pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
@@ -265,11 +270,16 @@ pub const File = struct {
}
}
- pub fn preadAll(self: File, buffer: []u8, offset: u64) PReadError!void {
+ /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
+ /// means the file reached the end. Reaching the end of a file is not an error condition.
+ pub fn preadAll(self: File, buffer: []u8, offset: u64) PReadError!usize {
var index: usize = 0;
- while (index < buffer.len) {
- index += try self.pread(buffer[index..], offset + index);
+ while (index != buffer.len) {
+ const amt = try self.pread(buffer[index..], offset + index);
+ if (amt == 0) break;
+ index += amt;
}
+ return index;
}
pub fn readv(self: File, iovecs: []const os.iovec) ReadError!usize {
@@ -280,19 +290,27 @@ pub const File = struct {
}
}
+ /// Returns the number of bytes read. If the number read is smaller than the total bytes
+ /// from all the buffers, it means the file reached the end. Reaching the end of a file
+ /// is not an error condition.
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
/// order to handle partial reads from the underlying OS layer.
- pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!void {
+ pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
if (iovecs.len == 0) return;
var i: usize = 0;
+ var off: usize = 0;
while (true) {
var amt = try self.readv(iovecs[i..]);
+ var eof = amt == 0;
+ off += amt;
while (amt >= iovecs[i].iov_len) {
amt -= iovecs[i].iov_len;
i += 1;
- if (i >= iovecs.len) return;
+ if (i >= iovecs.len) return off;
+ eof = false;
}
+ if (eof) return off;
iovecs[i].iov_base += amt;
iovecs[i].iov_len -= amt;
}
@@ -306,6 +324,9 @@ pub const File = struct {
}
}
+ /// Returns the number of bytes read. If the number read is smaller than the total bytes
+ /// from all the buffers, it means the file reached the end. Reaching the end of a file
+ /// is not an error condition.
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
/// order to handle partial reads from the underlying OS layer.
pub fn preadvAll(self: File, iovecs: []const os.iovec, offset: u64) PReadError!void {
@@ -315,12 +336,15 @@ pub const File = struct {
var off: usize = 0;
while (true) {
var amt = try self.preadv(iovecs[i..], offset + off);
+ var eof = amt == 0;
off += amt;
while (amt >= iovecs[i].iov_len) {
amt -= iovecs[i].iov_len;
i += 1;
- if (i >= iovecs.len) return;
+ if (i >= iovecs.len) return off;
+ eof = false;
}
+ if (eof) return off;
iovecs[i].iov_base += amt;
iovecs[i].iov_len -= amt;
}
diff --git a/lib/std/io/in_stream.zig b/lib/std/io/in_stream.zig
index 283058248..d1d24ab42 100644
--- a/lib/std/io/in_stream.zig
+++ b/lib/std/io/in_stream.zig
@@ -28,10 +28,7 @@ pub fn InStream(
return readFn(self.context, buffer);
}
- /// Deprecated: use `readAll`.
- pub const readFull = readAll;
-
- /// Returns the number of bytes read. If the number read is smaller than buf.len, it
+ /// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it
/// means the stream reached the end. Reaching the end of a stream is not an error
/// condition.
pub fn readAll(self: Self, buffer: []u8) Error!usize {
diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig
index 75a6d5db9..1ef6798b5 100644
--- a/lib/std/os/test.zig
+++ b/lib/std/os/test.zig
@@ -95,15 +95,41 @@ test "sendfile" {
},
};
- var written_buf: [header1.len + header2.len + 10 + trailer1.len + trailer2.len]u8 = undefined;
+ var written_buf: [100]u8 = undefined;
try dest_file.writeFileAll(src_file, .{
.in_offset = 1,
.in_len = 10,
.headers_and_trailers = &hdtr,
.header_count = 2,
});
- try dest_file.preadAll(&written_buf, 0);
- expect(mem.eql(u8, &written_buf, "header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n"));
+ const amt = try dest_file.preadAll(&written_buf, 0);
+ expect(mem.eql(u8, written_buf[0..amt], "header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n"));
+}
+
+test "fs.copyFile" {
+ const data = "u6wj+JmdF3qHsFPE BUlH2g4gJCmEz0PP";
+ const src_file = "tmp_test_copy_file.txt";
+ const dest_file = "tmp_test_copy_file2.txt";
+ const dest_file2 = "tmp_test_copy_file3.txt";
+
+ try fs.cwd().writeFile(src_file, data);
+ defer fs.cwd().deleteFile(src_file) catch {};
+
+ try fs.copyFile(src_file, dest_file);
+ defer fs.cwd().deleteFile(dest_file) catch {};
+
+ try fs.copyFileMode(src_file, dest_file2, File.default_mode);
+ defer fs.cwd().deleteFile(dest_file2) catch {};
+
+ try expectFileContents(dest_file, data);
+ try expectFileContents(dest_file2, data);
+}
+
+fn expectFileContents(file_path: []const u8, data: []const u8) !void {
+ const contents = try fs.cwd().readFileAlloc(testing.allocator, file_path, 1000);
+ defer testing.allocator.free(contents);
+
+ testing.expectEqualSlices(u8, data, contents);
}
test "std.Thread.getCurrentId" {
From c71991c869fc8c997c2714fe1b53caef23449c9c Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 11 Mar 2020 14:34:13 -0400
Subject: [PATCH 059/111] fix compilation errors for emitRaw
---
lib/std/build/emit_raw.zig | 2 +-
lib/std/elf.zig | 33 ++++++++++++++++++++++++++-------
2 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/lib/std/build/emit_raw.zig b/lib/std/build/emit_raw.zig
index 63c232994..b56305403 100644
--- a/lib/std/build/emit_raw.zig
+++ b/lib/std/build/emit_raw.zig
@@ -164,7 +164,7 @@ fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !v
var out_file = try fs.cwd().createFile(raw_path, .{});
defer out_file.close();
- const binary_elf_output = BinaryElfOutput.parse(allocator, elf_file);
+ const binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
defer binary_elf_output.deinit();
for (binary_elf_output.sections.toSlice()) |section| {
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 3aefd87f0..5cb3c566a 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -346,13 +346,13 @@ const Header = struct {
pub fn readHeader(file: File) !Header {
var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
- try in_stream.preadAll(&hdr_buf, 0);
- const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
- const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
+ try preadNoEof(file, &hdr_buf, 0);
+ const hdr32 = @ptrCast(*Elf32_Ehdr, &hdr_buf);
+ const hdr64 = @ptrCast(*Elf64_Ehdr, &hdr_buf);
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
- const endian = switch (hdr32.e_ident[elf.EI_DATA]) {
+ const endian = switch (hdr32.e_ident[EI_DATA]) {
ELFDATA2LSB => .Little,
ELFDATA2MSB => .Big,
else => return error.InvalidElfEndian,
@@ -407,10 +407,10 @@ pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
// non-matching endian files, we post-process to correct integer endianness and offsets.
const shdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum];
- const phdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
+ const phdr_buf = std.mem.sliceToBytes(hdrs.program_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
- try file.preadAll(phdr_buf, hdrs.header.phoff);
- try file.preadAll(shdr_buf, hdrs.header.shoff);
+ try preadNoEof(file, shdr_buf, hdrs.header.shoff);
+ try preadNoEof(file, phdr_buf, hdrs.header.phoff);
const shdrs32 = @ptrCast([*]Elf32_Shdr, @alignCast(@alignOf(Elf32_Shdr), shdr_buf.ptr))[0..hdrs.header.shnum];
const phdrs32 = @ptrCast([*]Elf32_Phdr, @alignCast(@alignOf(Elf32_Phdr), phdr_buf.ptr))[0..hdrs.header.phnum];
@@ -459,6 +459,25 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_
}
}
+fn preadNoEof(file: std.fs.File, buf: []u8, offset: u64) !void {
+ var i: u64 = 0;
+ while (i < buf.len) {
+ const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {
+ error.SystemResources => return error.SystemResources,
+ error.IsDir => return error.UnableToReadElfFile,
+ error.OperationAborted => return error.UnableToReadElfFile,
+ error.BrokenPipe => return error.UnableToReadElfFile,
+ error.Unseekable => return error.UnableToReadElfFile,
+ error.ConnectionResetByPeer => return error.UnableToReadElfFile,
+ error.InputOutput => return error.FileSystem,
+ error.Unexpected => return error.Unexpected,
+ error.WouldBlock => return error.Unexpected,
+ };
+ if (len == 0) return error.UnexpectedEndOfFile;
+ i += len;
+ }
+}
+
pub const EI_NIDENT = 16;
pub const EI_CLASS = 4;
From 431d76c0233271de6a30aa626ccb1553dc241722 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 11 Mar 2020 15:40:34 -0400
Subject: [PATCH 060/111] add std.io.StreamSource and fixes to emitRaw
---
lib/std/build/emit_raw.zig | 4 +-
lib/std/elf.zig | 24 ++++----
lib/std/io.zig | 2 +
lib/std/io/fixed_buffer_stream.zig | 41 +++++++-------
lib/std/io/stream_source.zig | 90 ++++++++++++++++++++++++++++++
5 files changed, 127 insertions(+), 34 deletions(-)
create mode 100644 lib/std/io/stream_source.zig
diff --git a/lib/std/build/emit_raw.zig b/lib/std/build/emit_raw.zig
index b56305403..8b4747e8a 100644
--- a/lib/std/build/emit_raw.zig
+++ b/lib/std/build/emit_raw.zig
@@ -48,8 +48,6 @@ const BinaryElfOutput = struct {
};
const elf_hdrs = try std.elf.readAllHeaders(allocator, elf_file);
- var binaryElfOutput = BinaryElfOutput.init(arena_allocator);
-
for (elf_hdrs.section_headers) |section, i| {
if (sectionValidForOutput(section)) {
const newSection = try allocator.create(BinaryElfSection);
@@ -164,7 +162,7 @@ fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !v
var out_file = try fs.cwd().createFile(raw_path, .{});
defer out_file.close();
- const binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
+ var binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
defer binary_elf_output.deinit();
for (binary_elf_output.sections.toSlice()) |section| {
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 5cb3c566a..127dbe8a3 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -1,5 +1,5 @@
-const builtin = @import("builtin");
const std = @import("std.zig");
+const builtin = std.builtin;
const io = std.io;
const os = std.os;
const math = std.math;
@@ -352,7 +352,7 @@ pub fn readHeader(file: File) !Header {
if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
- const endian = switch (hdr32.e_ident[EI_DATA]) {
+ const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
ELFDATA2LSB => .Little,
ELFDATA2MSB => .Big,
else => return error.InvalidElfEndian,
@@ -406,8 +406,8 @@ pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
// Treat section headers and program headers as byte buffers. For 32-bit ELF and
// non-matching endian files, we post-process to correct integer endianness and offsets.
- const shdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum];
- const phdr_buf = std.mem.sliceToBytes(hdrs.program_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
+ const shdr_buf = std.mem.sliceAsBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum];
+ const phdr_buf = std.mem.sliceAsBytes(hdrs.program_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
try preadNoEof(file, shdr_buf, hdrs.header.shoff);
try preadNoEof(file, phdr_buf, hdrs.header.phoff);
@@ -430,14 +430,14 @@ pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
}
for (hdrs.program_headers) |*phdr, i| {
phdr.* = .{
- .p_type = int(is_64, need_bswap, phdrs32[i].p_type, shdr.p_type),
- .p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, shdr.p_offset),
- .p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, shdr.p_vaddr),
- .p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, shdr.p_paddr),
- .p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, shdr.p_filesz),
- .p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, shdr.p_memsz),
- .p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, shdr.p_flags),
- .p_align = int(is_64, need_bswap, phdrs32[i].p_align, shdr.p_align),
+ .p_type = int(is_64, need_bswap, phdrs32[i].p_type, phdr.p_type),
+ .p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, phdr.p_offset),
+ .p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, phdr.p_vaddr),
+ .p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, phdr.p_paddr),
+ .p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, phdr.p_filesz),
+ .p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, phdr.p_memsz),
+ .p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, phdr.p_flags),
+ .p_align = int(is_64, need_bswap, phdrs32[i].p_align, phdr.p_align),
};
}
return hdrs;
diff --git a/lib/std/io.zig b/lib/std/io.zig
index 22af5c06b..243dd5ca9 100644
--- a/lib/std/io.zig
+++ b/lib/std/io.zig
@@ -126,6 +126,8 @@ pub const deserializer = @import("io/serialization.zig").deserializer;
pub const BufferedAtomicFile = @import("io/buffered_atomic_file.zig").BufferedAtomicFile;
+pub const StreamSource = @import("io/stream_source.zig").StreamSource;
+
/// Deprecated; use `std.fs.Dir.writeFile`.
pub fn writeFile(path: []const u8, data: []const u8) !void {
return fs.cwd().writeFile(path, data);
diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig
index 0f2b54220..cc4b9c019 100644
--- a/lib/std/io/fixed_buffer_stream.zig
+++ b/lib/std/io/fixed_buffer_stream.zig
@@ -12,9 +12,9 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
buffer: Buffer,
pos: usize,
- pub const ReadError = error{EndOfStream};
- pub const WriteError = error{OutOfMemory};
- pub const SeekError = error{EndOfStream};
+ pub const ReadError = error{};
+ pub const WriteError = error{NoSpaceLeft};
+ pub const SeekError = error{};
pub const GetSeekPosError = error{};
pub const InStream = io.InStream(*Self, ReadError, read);
@@ -51,16 +51,16 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
mem.copy(u8, dest[0..size], self.buffer[self.pos..end]);
self.pos = end;
- if (size == 0) return error.EndOfStream;
return size;
}
/// If the returned number of bytes written is less than requested, the
- /// buffer is full. Returns `error.OutOfMemory` when no bytes would be written.
+ /// buffer is full. Returns `error.NoSpaceLeft` when no bytes would be written.
+ /// Note: `error.NoSpaceLeft` matches the corresponding error from
+ /// `std.fs.File.WriteError`.
pub fn write(self: *Self, bytes: []const u8) WriteError!usize {
if (bytes.len == 0) return 0;
-
- assert(self.pos <= self.buffer.len);
+ if (self.pos >= self.buffer.len) return error.NoSpaceLeft;
const n = if (self.pos + bytes.len <= self.buffer.len)
bytes.len
@@ -70,26 +70,27 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
mem.copy(u8, self.buffer[self.pos .. self.pos + n], bytes[0..n]);
self.pos += n;
- if (n == 0) return error.OutOfMemory;
+ if (n == 0) return error.NoSpaceLeft;
return n;
}
pub fn seekTo(self: *Self, pos: u64) SeekError!void {
- const usize_pos = std.math.cast(usize, pos) catch return error.EndOfStream;
- if (usize_pos > self.buffer.len) return error.EndOfStream;
+ const usize_pos = std.math.cast(usize, pos) catch std.math.maxInt(usize);
self.pos = usize_pos;
}
pub fn seekBy(self: *Self, amt: i64) SeekError!void {
if (amt < 0) {
- const abs_amt = std.math.cast(usize, -amt) catch return error.EndOfStream;
- if (abs_amt > self.pos) return error.EndOfStream;
- self.pos -= abs_amt;
+ const abs_amt = std.math.cast(usize, -amt) catch std.math.maxInt(usize);
+ if (abs_amt > self.pos) {
+ self.pos = 0;
+ } else {
+ self.pos -= abs_amt;
+ }
} else {
- const usize_amt = std.math.cast(usize, amt) catch return error.EndOfStream;
- if (self.pos + usize_amt > self.buffer.len) return error.EndOfStream;
- self.pos += usize_amt;
+ const usize_amt = std.math.cast(usize, amt) catch std.math.maxInt(usize);
+ self.pos = std.math.add(usize, self.pos, usize_amt) catch std.math.maxInt(usize);
}
}
@@ -101,6 +102,7 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
return self.pos;
}
+ /// Asserts that the seek pos is within the buffer range.
pub fn getWritten(self: Self) []const u8 {
return self.buffer[0..self.pos];
}
@@ -140,13 +142,13 @@ test "FixedBufferStream output 2" {
try fbs.outStream().writeAll("world");
testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
- testing.expectError(error.OutOfMemory, fbs.outStream().writeAll("!"));
+ testing.expectError(error.NoSpaceLeft, fbs.outStream().writeAll("!"));
testing.expect(mem.eql(u8, fbs.getWritten(), "Helloworld"));
fbs.reset();
testing.expect(fbs.getWritten().len == 0);
- testing.expectError(error.OutOfMemory, fbs.outStream().writeAll("Hello world!"));
+ testing.expectError(error.NoSpaceLeft, fbs.outStream().writeAll("Hello world!"));
testing.expect(mem.eql(u8, fbs.getWritten(), "Hello worl"));
}
@@ -164,5 +166,6 @@ test "FixedBufferStream input" {
testing.expect(read == 3);
testing.expect(mem.eql(u8, dest[0..3], bytes[4..7]));
- testing.expectError(error.EndOfStream, fbs.inStream().read(dest[0..4]));
+ read = try fbs.inStream().read(dest[0..4]);
+ testing.expect(read == 0);
}
diff --git a/lib/std/io/stream_source.zig b/lib/std/io/stream_source.zig
new file mode 100644
index 000000000..7e3955433
--- /dev/null
+++ b/lib/std/io/stream_source.zig
@@ -0,0 +1,90 @@
+const std = @import("../std.zig");
+const io = std.io;
+const testing = std.testing;
+
+/// Provides `io.InStream`, `io.OutStream`, and `io.SeekableStream` for in-memory buffers as
+/// well as files.
+/// For memory sources, if the supplied byte buffer is const, then `io.OutStream` is not available.
+/// The error set of the stream functions is the error set of the corresponding file functions.
+pub const StreamSource = union(enum) {
+ buffer: io.FixedBufferStream([]u8),
+ const_buffer: io.FixedBufferStream([]const u8),
+ file: std.fs.File,
+
+ pub const ReadError = std.fs.File.ReadError;
+ pub const WriteError = std.fs.File.WriteError;
+ pub const SeekError = std.fs.File.SeekError;
+ pub const GetSeekPosError = std.fs.File.GetPosError;
+
+ pub const InStream = io.InStream(*StreamSource, ReadError, read);
+ pub const OutStream = io.OutStream(*StreamSource, WriteError, write);
+ pub const SeekableStream = io.SeekableStream(
+ *StreamSource,
+ SeekError,
+ GetSeekPosError,
+ seekTo,
+ seekBy,
+ getPos,
+ getEndPos,
+ );
+
+ pub fn read(self: *StreamSource, dest: []u8) ReadError!usize {
+ switch (self.*) {
+ .buffer => |*x| return x.read(dest),
+ .const_buffer => |*x| return x.read(dest),
+ .file => |x| return x.read(dest),
+ }
+ }
+
+ pub fn write(self: *StreamSource, bytes: []const u8) WriteError!usize {
+ switch (self.*) {
+ .buffer => |*x| return x.write(bytes),
+ .const_buffer => |*x| return x.write(bytes),
+ .file => |x| return x.write(bytes),
+ }
+ }
+
+ pub fn seekTo(self: *StreamSource, pos: u64) SeekError!void {
+ switch (self.*) {
+ .buffer => |*x| return x.seekTo(pos),
+ .const_buffer => |*x| return x.seekTo(pos),
+ .file => |x| return x.seekTo(pos),
+ }
+ }
+
+ pub fn seekBy(self: *StreamSource, amt: i64) SeekError!void {
+ switch (self.*) {
+ .buffer => |*x| return x.seekBy(amt),
+ .const_buffer => |*x| return x.seekBy(amt),
+ .file => |x| return x.seekBy(amt),
+ }
+ }
+
+ pub fn getEndPos(self: *StreamSource) GetSeekPosError!u64 {
+ switch (self.*) {
+ .buffer => |*x| return x.getEndPos(),
+ .const_buffer => |*x| return x.getEndPos(),
+ .file => |x| return x.getEndPos(),
+ }
+ }
+
+ pub fn getPos(self: *StreamSource) GetSeekPosError!u64 {
+ switch (self.*) {
+ .buffer => |*x| return x.getPos(),
+ .const_buffer => |*x| return x.getPos(),
+ .file => |x| return x.getPos(),
+ }
+ }
+
+ pub fn inStream(self: *StreamSource) InStream {
+ return .{ .context = self };
+ }
+
+ pub fn outStream(self: *StreamSource) OutStream {
+ return .{ .context = self };
+ }
+
+ pub fn seekableStream(self: *StreamSource) SeekableStream {
+ return .{ .context = self };
+ }
+};
From 6892865ba72ea220a12a8238ce78aedab1237cce Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 11 Mar 2020 16:14:12 -0400
Subject: [PATCH 061/111] FixedBufferStream: match file semantics more by
clamping pos
---
lib/std/io/fixed_buffer_stream.zig | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig
index cc4b9c019..0d091eea7 100644
--- a/lib/std/io/fixed_buffer_stream.zig
+++ b/lib/std/io/fixed_buffer_stream.zig
@@ -76,21 +76,22 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
}
pub fn seekTo(self: *Self, pos: u64) SeekError!void {
- const usize_pos = std.math.cast(usize, pos) catch std.math.maxInt(usize);
- self.pos = usize_pos;
+ self.pos = if (std.math.cast(usize, pos)) |x| x else |_| self.buffer.len;
}
pub fn seekBy(self: *Self, amt: i64) SeekError!void {
if (amt < 0) {
- const abs_amt = std.math.cast(usize, -amt) catch std.math.maxInt(usize);
- if (abs_amt > self.pos) {
+ const abs_amt = std.math.absCast(amt);
+ const abs_amt_usize = std.math.cast(usize, abs_amt) catch std.math.maxInt(usize);
+ if (abs_amt_usize > self.pos) {
self.pos = 0;
} else {
- self.pos -= abs_amt;
+ self.pos -= abs_amt_usize;
}
} else {
- const usize_amt = std.math.cast(usize, amt) catch std.math.maxInt(usize);
- self.pos = std.math.add(usize, self.pos, usize_amt) catch std.math.maxInt(usize);
+ const amt_usize = std.math.cast(usize, amt) catch std.math.maxInt(usize);
+ const new_pos = std.math.add(usize, self.pos, amt_usize) catch std.math.maxInt(usize);
+ self.pos = std.math.min(self.buffer.len, new_pos);
}
}
@@ -102,7 +103,6 @@ pub fn FixedBufferStream(comptime Buffer: type) type {
return self.pos;
}
- /// Asserts that the seek pos is within the buffer range.
pub fn getWritten(self: Self) []const u8 {
return self.buffer[0..self.pos];
}
From 3657a54618dafa110fd1d16e02c48e04871c9370 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 11 Mar 2020 17:34:12 -0400
Subject: [PATCH 062/111] fix regressions in elf parsing code
---
lib/std/elf.zig | 155 +++++++++++++++++++++++++++++++----------
lib/std/zig/system.zig | 17 ++++-
2 files changed, 133 insertions(+), 39 deletions(-)
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 127dbe8a3..7b415f675 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -398,48 +398,123 @@ pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
const need_bswap = hdrs.header.endian != std.builtin.endian;
hdrs.section_headers = try allocator.alloc(Elf64_Shdr, hdrs.header.shnum);
- errdefer hdrs.allocator.free(hdrs.section_headers);
+ errdefer allocator.free(hdrs.section_headers);
hdrs.program_headers = try allocator.alloc(Elf64_Phdr, hdrs.header.phnum);
- errdefer hdrs.allocator.free(hdrs.program_headers);
+ errdefer allocator.free(hdrs.program_headers);
- // Treat section headers and program headers as byte buffers. For 32-bit ELF and
- // non-matching endian files, we post-process to correct integer endianness and offsets.
+ // If the ELF file is 64-bit and same-endianness, then all we have to do is
+ // yeet the bytes into memory.
+ // If only the endianness is different, they can be simply byte swapped.
+ if (is_64) {
+ const shdr_buf = std.mem.sliceAsBytes(hdrs.section_headers);
+ const phdr_buf = std.mem.sliceAsBytes(hdrs.program_headers);
+ try preadNoEof(file, shdr_buf, hdrs.header.shoff);
+ try preadNoEof(file, phdr_buf, hdrs.header.phoff);
- const shdr_buf = std.mem.sliceAsBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum];
- const phdr_buf = std.mem.sliceAsBytes(hdrs.program_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum];
+ if (need_bswap) {
+ for (hdrs.section_headers) |*shdr| {
+ shdr.* = .{
+ .sh_name = @byteSwap(@TypeOf(shdr.sh_name), shdr.sh_name),
+ .sh_type = @byteSwap(@TypeOf(shdr.sh_type), shdr.sh_type),
+ .sh_flags = @byteSwap(@TypeOf(shdr.sh_flags), shdr.sh_flags),
+ .sh_addr = @byteSwap(@TypeOf(shdr.sh_addr), shdr.sh_addr),
+ .sh_offset = @byteSwap(@TypeOf(shdr.sh_offset), shdr.sh_offset),
+ .sh_size = @byteSwap(@TypeOf(shdr.sh_size), shdr.sh_size),
+ .sh_link = @byteSwap(@TypeOf(shdr.sh_link), shdr.sh_link),
+ .sh_info = @byteSwap(@TypeOf(shdr.sh_info), shdr.sh_info),
+ .sh_addralign = @byteSwap(@TypeOf(shdr.sh_addralign), shdr.sh_addralign),
+ .sh_entsize = @byteSwap(@TypeOf(shdr.sh_entsize), shdr.sh_entsize),
+ };
+ }
+ for (hdrs.program_headers) |*phdr| {
+ phdr.* = .{
+ .p_type = @byteSwap(@TypeOf(phdr.p_type), phdr.p_type),
+ .p_offset = @byteSwap(@TypeOf(phdr.p_offset), phdr.p_offset),
+ .p_vaddr = @byteSwap(@TypeOf(phdr.p_vaddr), phdr.p_vaddr),
+ .p_paddr = @byteSwap(@TypeOf(phdr.p_paddr), phdr.p_paddr),
+ .p_filesz = @byteSwap(@TypeOf(phdr.p_filesz), phdr.p_filesz),
+ .p_memsz = @byteSwap(@TypeOf(phdr.p_memsz), phdr.p_memsz),
+ .p_flags = @byteSwap(@TypeOf(phdr.p_flags), phdr.p_flags),
+ .p_align = @byteSwap(@TypeOf(phdr.p_align), phdr.p_align),
+ };
+ }
+ }
+ return hdrs;
+ }
+
+ const shdrs_32 = try allocator.alloc(Elf32_Shdr, hdrs.header.shnum);
+ defer allocator.free(shdrs_32);
+
+ const phdrs_32 = try allocator.alloc(Elf32_Phdr, hdrs.header.phnum);
+ defer allocator.free(phdrs_32);
+
+ const shdr_buf = std.mem.sliceAsBytes(shdrs_32);
+ const phdr_buf = std.mem.sliceAsBytes(phdrs_32);
try preadNoEof(file, shdr_buf, hdrs.header.shoff);
try preadNoEof(file, phdr_buf, hdrs.header.phoff);
- const shdrs32 = @ptrCast([*]Elf32_Shdr, @alignCast(@alignOf(Elf32_Shdr), shdr_buf.ptr))[0..hdrs.header.shnum];
- const phdrs32 = @ptrCast([*]Elf32_Phdr, @alignCast(@alignOf(Elf32_Phdr), phdr_buf.ptr))[0..hdrs.header.phnum];
- for (hdrs.section_headers) |*shdr, i| {
- shdr.* = .{
- .sh_name = int(is_64, need_bswap, shdrs32[i].sh_name, shdr.sh_name),
- .sh_type = int(is_64, need_bswap, shdrs32[i].sh_type, shdr.sh_type),
- .sh_flags = int(is_64, need_bswap, shdrs32[i].sh_flags, shdr.sh_flags),
- .sh_addr = int(is_64, need_bswap, shdrs32[i].sh_addr, shdr.sh_addr),
- .sh_offset = int(is_64, need_bswap, shdrs32[i].sh_offset, shdr.sh_offset),
- .sh_size = int(is_64, need_bswap, shdrs32[i].sh_size, shdr.sh_size),
- .sh_link = int(is_64, need_bswap, shdrs32[i].sh_link, shdr.sh_link),
- .sh_info = int(is_64, need_bswap, shdrs32[i].sh_info, shdr.sh_info),
- .sh_addralign = int(is_64, need_bswap, shdrs32[i].sh_addralign, shdr.sh_addralign),
- .sh_entsize = int(is_64, need_bswap, shdrs32[i].sh_entsize, shdr.sh_entsize),
- };
- }
- for (hdrs.program_headers) |*phdr, i| {
- phdr.* = .{
- .p_type = int(is_64, need_bswap, phdrs32[i].p_type, phdr.p_type),
- .p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, phdr.p_offset),
- .p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, phdr.p_vaddr),
- .p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, phdr.p_paddr),
- .p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, phdr.p_filesz),
- .p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, phdr.p_memsz),
- .p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, phdr.p_flags),
- .p_align = int(is_64, need_bswap, phdrs32[i].p_align, phdr.p_align),
- };
+ if (need_bswap) {
+ for (hdrs.section_headers) |*shdr, i| {
+ const o = shdrs_32[i];
+ shdr.* = .{
+ .sh_name = @byteSwap(@TypeOf(o.sh_name), o.sh_name),
+ .sh_type = @byteSwap(@TypeOf(o.sh_type), o.sh_type),
+ .sh_flags = @byteSwap(@TypeOf(o.sh_flags), o.sh_flags),
+ .sh_addr = @byteSwap(@TypeOf(o.sh_addr), o.sh_addr),
+ .sh_offset = @byteSwap(@TypeOf(o.sh_offset), o.sh_offset),
+ .sh_size = @byteSwap(@TypeOf(o.sh_size), o.sh_size),
+ .sh_link = @byteSwap(@TypeOf(o.sh_link), o.sh_link),
+ .sh_info = @byteSwap(@TypeOf(o.sh_info), o.sh_info),
+ .sh_addralign = @byteSwap(@TypeOf(o.sh_addralign), o.sh_addralign),
+ .sh_entsize = @byteSwap(@TypeOf(o.sh_entsize), o.sh_entsize),
+ };
+ }
+ for (hdrs.program_headers) |*phdr, i| {
+ const o = phdrs_32[i];
+ phdr.* = .{
+ .p_type = @byteSwap(@TypeOf(o.p_type), o.p_type),
+ .p_offset = @byteSwap(@TypeOf(o.p_offset), o.p_offset),
+ .p_vaddr = @byteSwap(@TypeOf(o.p_vaddr), o.p_vaddr),
+ .p_paddr = @byteSwap(@TypeOf(o.p_paddr), o.p_paddr),
+ .p_filesz = @byteSwap(@TypeOf(o.p_filesz), o.p_filesz),
+ .p_memsz = @byteSwap(@TypeOf(o.p_memsz), o.p_memsz),
+ .p_flags = @byteSwap(@TypeOf(o.p_flags), o.p_flags),
+ .p_align = @byteSwap(@TypeOf(o.p_align), o.p_align),
+ };
+ }
+ } else {
+ for (hdrs.section_headers) |*shdr, i| {
+ const o = shdrs_32[i];
+ shdr.* = .{
+ .sh_name = o.sh_name,
+ .sh_type = o.sh_type,
+ .sh_flags = o.sh_flags,
+ .sh_addr = o.sh_addr,
+ .sh_offset = o.sh_offset,
+ .sh_size = o.sh_size,
+ .sh_link = o.sh_link,
+ .sh_info = o.sh_info,
+ .sh_addralign = o.sh_addralign,
+ .sh_entsize = o.sh_entsize,
+ };
+ }
+ for (hdrs.program_headers) |*phdr, i| {
+ const o = phdrs_32[i];
+ phdr.* = .{
+ .p_type = o.p_type,
+ .p_offset = o.p_offset,
+ .p_vaddr = o.p_vaddr,
+ .p_paddr = o.p_paddr,
+ .p_filesz = o.p_filesz,
+ .p_memsz = o.p_memsz,
+ .p_flags = o.p_flags,
+ .p_align = o.p_align,
+ };
+ }
}
+
return hdrs;
}
@@ -451,11 +526,15 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_
return int_64;
}
} else {
- if (need_bswap) {
- return @byteSwap(@TypeOf(int_32), int_32);
- } else {
- return int_32;
- }
+ return int32(need_bswap, int_32, @TypeOf(int_64));
+ }
+}
+
+pub fn int32(need_bswap: bool, int_32: var, comptime Int64: var) Int64 {
+ if (need_bswap) {
+ return @byteSwap(@TypeOf(int_32), int_32);
+ } else {
+ return int_32;
}
}
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index e7953a1a9..558b50b5b 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -587,7 +587,6 @@ pub const NativeTargetInfo = struct {
elf.ELFCLASS64 => true,
else => return error.InvalidElfClass,
};
- const elfInt = elf.int;
var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);
const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);
const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
@@ -854,6 +853,22 @@ pub const NativeTargetInfo = struct {
abi: Target.Abi,
};
+ pub fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
+ if (is_64) {
+ if (need_bswap) {
+ return @byteSwap(@TypeOf(int_64), int_64);
+ } else {
+ return int_64;
+ }
+ } else {
+ if (need_bswap) {
+ return @byteSwap(@TypeOf(int_32), int_32);
+ } else {
+ return int_32;
+ }
+ }
+ }
+
fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) ?Target.Cpu {
// Here we switch on a comptime value rather than `cpu_arch`. This is valid because `cpu_arch`,
// although it is a runtime value, is guaranteed to be one of the architectures in the set
From 06d2f53ece7328e6beedd5c846a5b25798ba74e3 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 11 Mar 2020 17:39:53 -0400
Subject: [PATCH 063/111] windows: detect HANDLE_EOF in ReadFile
---
lib/std/os/windows.zig | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index d1201108d..6c9a1f24b 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -407,6 +407,7 @@ pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64) ReadFileError!usiz
switch (kernel32.GetLastError()) {
.OPERATION_ABORTED => continue,
.BROKEN_PIPE => return index,
+ .HANDLE_EOF => return index,
else => |err| return unexpectedError(err),
}
}
From 571f3ed161455074be5f296b39b24cba554da8e0 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 11 Mar 2020 18:45:09 -0400
Subject: [PATCH 064/111] fix stray warn() in runtime safety test
---
test/runtime_safety.zig | 1 -
1 file changed, 1 deletion(-)
diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig
index 9855aae16..5047bfd0d 100644
--- a/test/runtime_safety.zig
+++ b/test/runtime_safety.zig
@@ -4,7 +4,6 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
cases.addRuntimeSafety("shift left by huge amount",
\\const std = @import("std");
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
- \\ std.debug.warn("{}\n", .{message});
\\ if (std.mem.eql(u8, message, "shift amount is greater than the type size")) {
\\ std.process.exit(126); // good
\\ }
From e0fe0f7f1e26c7cc0266b3f0168363135ec75ff4 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Wed, 11 Mar 2020 19:33:10 -0400
Subject: [PATCH 065/111] parse CPU features when --target is null
- fixes case where features are not parsed when `-target` is null
- `zig builtin -mcpu native+bogus` should return error/list of valid features
---
src-self-hosted/stage2.zig | 74 +++++++++++++++++++-------------------
1 file changed, 36 insertions(+), 38 deletions(-)
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 8f2656de4..bdd68925e 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -679,44 +679,42 @@ fn stage2TargetParse(
mcpu_oz: ?[*:0]const u8,
dynamic_linker_oz: ?[*:0]const u8,
) !void {
- const target: CrossTarget = if (zig_triple_oz) |zig_triple_z| blk: {
- const zig_triple = mem.toSliceConst(u8, zig_triple_z);
- const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else null;
- const dynamic_linker = if (dynamic_linker_oz) |dl_z| mem.toSliceConst(u8, dl_z) else null;
- var diags: CrossTarget.ParseOptions.Diagnostics = .{};
- break :blk CrossTarget.parse(.{
- .arch_os_abi = zig_triple,
- .cpu_features = mcpu,
- .dynamic_linker = dynamic_linker,
- .diagnostics = &diags,
- }) catch |err| switch (err) {
- error.UnknownCpuModel => {
- std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
- diags.cpu_name.?,
- @tagName(diags.arch.?),
- });
- for (diags.arch.?.allCpuModels()) |cpu| {
- std.debug.warn(" {}\n", .{cpu.name});
- }
- process.exit(1);
- },
- error.UnknownCpuFeature => {
- std.debug.warn(
- \\Unknown CPU feature: '{}'
- \\Available CPU features for architecture '{}':
- \\
- , .{
- diags.unknown_feature_name,
- @tagName(diags.arch.?),
- });
- for (diags.arch.?.allFeaturesList()) |feature| {
- std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
- }
- process.exit(1);
- },
- else => |e| return e,
- };
- } else .{};
+ const zig_triple = if (zig_triple_oz) |zig_triple_z| mem.toSliceConst(u8, zig_triple_z) else "native";
+ const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else null;
+ const dynamic_linker = if (dynamic_linker_oz) |dl_z| mem.toSliceConst(u8, dl_z) else null;
+ var diags: CrossTarget.ParseOptions.Diagnostics = .{};
+ const target: CrossTarget = CrossTarget.parse(.{
+ .arch_os_abi = zig_triple,
+ .cpu_features = mcpu,
+ .dynamic_linker = dynamic_linker,
+ .diagnostics = &diags,
+ }) catch |err| switch (err) {
+ error.UnknownCpuModel => {
+ std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
+ diags.cpu_name.?,
+ @tagName(diags.arch.?),
+ });
+ for (diags.arch.?.allCpuModels()) |cpu| {
+ std.debug.warn(" {}\n", .{cpu.name});
+ }
+ process.exit(1);
+ },
+ error.UnknownCpuFeature => {
+ std.debug.warn(
+ \\Unknown CPU feature: '{}'
+ \\Available CPU features for architecture '{}':
+ \\
+ , .{
+ diags.unknown_feature_name,
+ @tagName(diags.arch.?),
+ });
+ for (diags.arch.?.allFeaturesList()) |feature| {
+ std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
+ }
+ process.exit(1);
+ },
+ else => |e| return e,
+ };
try stage1_target.fromTarget(target);
}
From c988167377c92359fed42f12ad32b5f349f9ffb8 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Wed, 11 Mar 2020 19:33:11 -0400
Subject: [PATCH 066/111] update/apply CPU features when -mcpu native
- fix: features were not applied if cpu is specified as native
---
lib/std/zig/system.zig | 21 ++++++---------------
1 file changed, 6 insertions(+), 15 deletions(-)
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 558b50b5b..88b3022bb 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -325,22 +325,19 @@ pub const NativeTargetInfo = struct {
// native CPU architecture as being different than the current target), we use this:
const cpu_arch = cross_target.getCpuArch();
- const cpu = switch (cross_target.cpu_model) {
+ var cpu = switch (cross_target.cpu_model) {
.native => detectNativeCpuAndFeatures(cpu_arch, os, cross_target),
- .baseline => baselineCpuAndFeatures(cpu_arch, cross_target),
+ .baseline => Target.Cpu.baseline(cpu_arch),
.determined_by_cpu_arch => if (cross_target.cpu_arch == null)
detectNativeCpuAndFeatures(cpu_arch, os, cross_target)
else
- baselineCpuAndFeatures(cpu_arch, cross_target),
- .explicit => |model| blk: {
- var adjusted_model = model.toCpu(cpu_arch);
- cross_target.updateCpuFeatures(&adjusted_model.features);
- break :blk adjusted_model;
- },
+ Target.Cpu.baseline(cpu_arch),
+ .explicit => |model| model.toCpu(cpu_arch),
} orelse backup_cpu_detection: {
cpu_detection_unimplemented = true;
- break :backup_cpu_detection baselineCpuAndFeatures(cpu_arch, cross_target);
+ break :backup_cpu_detection Target.Cpu.baseline(cpu_arch);
};
+ cross_target.updateCpuFeatures(&cpu.features);
var target = try detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);
target.cpu_detection_unimplemented = cpu_detection_unimplemented;
@@ -884,10 +881,4 @@ pub const NativeTargetInfo = struct {
},
}
}
-
- fn baselineCpuAndFeatures(cpu_arch: Target.Cpu.Arch, cross_target: CrossTarget) Target.Cpu {
- var adjusted_baseline = Target.Cpu.baseline(cpu_arch);
- cross_target.updateCpuFeatures(&adjusted_baseline.features);
- return adjusted_baseline;
- }
};
From bfebc11d0633e3f4a3fe86d1a9d6f90ffdb1fbb6 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Wed, 11 Mar 2020 19:33:12 -0400
Subject: [PATCH 067/111] fix zig-cache to treat cpu-features as raw-bytes
- add Stage2Target.cache_hash_len
- add cache_mem(ch, ptr, len)
- update call sites to use { ptr, len }
---
src-self-hosted/stage2.zig | 5 ++++-
src/cache_hash.cpp | 8 ++++++--
src/cache_hash.hpp | 1 +
src/codegen.cpp | 4 ++--
src/stage2.cpp | 3 +++
src/stage2.h | 1 +
6 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index bdd68925e..83a70c29e 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -900,6 +900,7 @@ const Stage2Target = extern struct {
llvm_cpu_features: ?[*:0]const u8,
cpu_builtin_str: ?[*:0]const u8,
cache_hash: ?[*:0]const u8,
+ cache_hash_len: usize,
os_builtin_str: ?[*:0]const u8,
dynamic_linker: ?[*:0]const u8,
@@ -1129,6 +1130,7 @@ const Stage2Target = extern struct {
}
};
+ const cache_hash_slice = cache_hash.toOwnedSlice();
self.* = .{
.arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
.vendor = 0,
@@ -1138,7 +1140,8 @@ const Stage2Target = extern struct {
.llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr,
.cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
.os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
- .cache_hash = cache_hash.toOwnedSlice().ptr,
+ .cache_hash = cache_hash_slice.ptr,
+ .cache_hash_len = cache_hash_slice.len,
.is_native = cross_target.isNative(),
.glibc_or_darwin_version = glibc_or_darwin_version,
.dynamic_linker = dynamic_linker,
diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp
index 35b05a1dd..3cff34ea5 100644
--- a/src/cache_hash.cpp
+++ b/src/cache_hash.cpp
@@ -24,11 +24,15 @@ void cache_init(CacheHash *ch, Buf *manifest_dir) {
ch->b64_digest = BUF_INIT;
}
-void cache_str(CacheHash *ch, const char *ptr) {
+void cache_mem(CacheHash *ch, const char *ptr, size_t len) {
assert(ch->manifest_file_path == nullptr);
assert(ptr != nullptr);
// + 1 to include the null byte
- blake2b_update(&ch->blake, ptr, strlen(ptr) + 1);
+ blake2b_update(&ch->blake, ptr, len);
+}
+
+void cache_str(CacheHash *ch, const char *ptr) {
+ cache_mem(ch, ptr, strlen(ptr) + 1);
}
void cache_int(CacheHash *ch, int x) {
diff --git a/src/cache_hash.hpp b/src/cache_hash.hpp
index e2a10270f..9e4c41b1e 100644
--- a/src/cache_hash.hpp
+++ b/src/cache_hash.hpp
@@ -35,6 +35,7 @@ struct CacheHash {
void cache_init(CacheHash *ch, Buf *manifest_dir);
// Next, use the hash population functions to add the initial parameters.
+void cache_mem(CacheHash *ch, const char *ptr, size_t len);
void cache_str(CacheHash *ch, const char *ptr);
void cache_int(CacheHash *ch, int x);
void cache_bool(CacheHash *ch, bool x);
diff --git a/src/codegen.cpp b/src/codegen.cpp
index d659e27d8..e692c7b80 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -8664,7 +8664,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
cache_int(&cache_hash, g->zig_target->os);
cache_int(&cache_hash, g->zig_target->abi);
if (g->zig_target->cache_hash != nullptr) {
- cache_str(&cache_hash, g->zig_target->cache_hash);
+ cache_mem(&cache_hash, g->zig_target->cache_hash, g->zig_target->cache_hash_len);
}
if (g->zig_target->glibc_or_darwin_version != nullptr) {
cache_int(&cache_hash, g->zig_target->glibc_or_darwin_version->major);
@@ -10309,7 +10309,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_int(ch, g->zig_target->os);
cache_int(ch, g->zig_target->abi);
if (g->zig_target->cache_hash != nullptr) {
- cache_str(ch, g->zig_target->cache_hash);
+ cache_mem(ch, g->zig_target->cache_hash, g->zig_target->cache_hash_len);
}
if (g->zig_target->glibc_or_darwin_version != nullptr) {
cache_int(ch, g->zig_target->glibc_or_darwin_version->major);
diff --git a/src/stage2.cpp b/src/stage2.cpp
index 1f6cb2d6a..afb7ebb54 100644
--- a/src/stage2.cpp
+++ b/src/stage2.cpp
@@ -251,9 +251,12 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
target->cache_hash = "\n\n";
}
+ target->cache_hash_len = strlen(target->cache_hash);
+
if (dynamic_linker != nullptr) {
target->dynamic_linker = dynamic_linker;
}
+
return ErrorNone;
}
diff --git a/src/stage2.h b/src/stage2.h
index b73269f4e..1ff0b5e82 100644
--- a/src/stage2.h
+++ b/src/stage2.h
@@ -293,6 +293,7 @@ struct ZigTarget {
const char *llvm_cpu_features;
const char *cpu_builtin_str;
const char *cache_hash;
+ size_t cache_hash_len;
const char *os_builtin_str;
const char *dynamic_linker;
};
From 3f1c8e3d58f31dabd22fd6d1fa408512e5cbbb07 Mon Sep 17 00:00:00 2001
From: Heppokoyuki
Date: Thu, 12 Mar 2020 13:26:00 +0900
Subject: [PATCH 068/111] fix bug
---
lib/std/os/uefi/protocols/file_protocol.zig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/std/os/uefi/protocols/file_protocol.zig b/lib/std/os/uefi/protocols/file_protocol.zig
index cc6785caf..6202231cf 100644
--- a/lib/std/os/uefi/protocols/file_protocol.zig
+++ b/lib/std/os/uefi/protocols/file_protocol.zig
@@ -2,7 +2,7 @@ const uefi = @import("std").os.uefi;
const Guid = uefi.Guid;
const Time = uefi.Time;
-const FileProtocol = extern struct {
+pub const FileProtocol = extern struct {
revision: u64,
_open: extern fn (*const FileProtocol, **const FileProtocol, *u16, u64, u64) usize,
_close: extern fn (*const FileProtocol) usize,
@@ -67,7 +67,7 @@ const FileProtocol = extern struct {
pub const efi_file_valid_attr: u64 = 0x0000000000000037;
};
-const FileInfo = extern struct {
+pub const FileInfo = extern struct {
size: u64,
file_size: u64,
physical_size: u64,
From f58705b4a623b39ad10fe25a9a41507fdfc0b089 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 12 Mar 2020 00:32:50 -0400
Subject: [PATCH 069/111] fix `zig targets` not reporting native info
---
src-self-hosted/stage2.zig | 47 +++++++++++++++++++-------------------
src/main.cpp | 2 +-
src/stage2.cpp | 2 +-
src/stage2.h | 6 ++---
4 files changed, 29 insertions(+), 28 deletions(-)
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 83a70c29e..36941cc3a 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -626,16 +626,24 @@ fn detectNativeCpuWithLLVM(
}
// ABI warning
-export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int {
- cmdTargets(zig_triple) catch |err| {
+export fn stage2_cmd_targets(
+ zig_triple: ?[*:0]const u8,
+ mcpu: ?[*:0]const u8,
+ dynamic_linker: ?[*:0]const u8,
+) c_int {
+ cmdTargets(zig_triple, mcpu, dynamic_linker) catch |err| {
std.debug.warn("unable to list targets: {}\n", .{@errorName(err)});
return -1;
};
return 0;
}
-fn cmdTargets(zig_triple: [*:0]const u8) !void {
- var cross_target = try CrossTarget.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) });
+fn cmdTargets(
+ zig_triple_oz: ?[*:0]const u8,
+ mcpu_oz: ?[*:0]const u8,
+ dynamic_linker_oz: ?[*:0]const u8,
+) !void {
+ const cross_target = try stage2CrossTarget(zig_triple_oz, mcpu_oz, dynamic_linker_oz);
var dynamic_linker: ?[*:0]u8 = null;
const target = try crossTargetToTarget(cross_target, &dynamic_linker);
return @import("print_targets.zig").cmdTargets(
@@ -673,12 +681,11 @@ export fn stage2_target_parse(
return .None;
}
-fn stage2TargetParse(
- stage1_target: *Stage2Target,
+fn stage2CrossTarget(
zig_triple_oz: ?[*:0]const u8,
mcpu_oz: ?[*:0]const u8,
dynamic_linker_oz: ?[*:0]const u8,
-) !void {
+) !CrossTarget {
const zig_triple = if (zig_triple_oz) |zig_triple_z| mem.toSliceConst(u8, zig_triple_z) else "native";
const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else null;
const dynamic_linker = if (dynamic_linker_oz) |dl_z| mem.toSliceConst(u8, dl_z) else null;
@@ -716,6 +723,16 @@ fn stage2TargetParse(
else => |e| return e,
};
+ return target;
+}
+
+fn stage2TargetParse(
+ stage1_target: *Stage2Target,
+ zig_triple_oz: ?[*:0]const u8,
+ mcpu_oz: ?[*:0]const u8,
+ dynamic_linker_oz: ?[*:0]const u8,
+) !void {
+ const target = try stage2CrossTarget(zig_triple_oz, mcpu_oz, dynamic_linker_oz);
try stage1_target.fromTarget(target);
}
@@ -905,22 +922,6 @@ const Stage2Target = extern struct {
dynamic_linker: ?[*:0]const u8,
- fn toTarget(in_target: Stage2Target) CrossTarget {
- if (in_target.is_native) return .{};
-
- const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch
- const in_os = in_target.os;
- const in_abi = in_target.abi;
-
- return .{
- .Cross = .{
- .cpu = Target.Cpu.baseline(enumInt(Target.Cpu.Arch, in_arch)),
- .os = Target.Os.defaultVersionRange(enumInt(Target.Os.Tag, in_os)),
- .abi = enumInt(Target.Abi, in_abi),
- },
- };
- }
-
fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
const allocator = std.heap.c_allocator;
diff --git a/src/main.cpp b/src/main.cpp
index 92d08bed4..1939606b0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1391,7 +1391,7 @@ static int main0(int argc, char **argv) {
return main_exit(root_progress_node, EXIT_SUCCESS);
}
case CmdTargets:
- return stage2_cmd_targets(buf_ptr(&zig_triple_buf));
+ return stage2_cmd_targets(target_string, mcpu, dynamic_linker);
case CmdNone:
return print_full_usage(arg0, stderr, EXIT_FAILURE);
}
diff --git a/src/stage2.cpp b/src/stage2.cpp
index afb7ebb54..7495ffddb 100644
--- a/src/stage2.cpp
+++ b/src/stage2.cpp
@@ -260,7 +260,7 @@ Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, cons
return ErrorNone;
}
-int stage2_cmd_targets(const char *zig_triple) {
+int stage2_cmd_targets(const char *zig_triple, const char *mcpu, const char *dynamic_linker) {
const char *msg = "stage0 called stage2_cmd_targets";
stage2_panic(msg, strlen(msg));
}
diff --git a/src/stage2.h b/src/stage2.h
index 1ff0b5e82..50f891dca 100644
--- a/src/stage2.h
+++ b/src/stage2.h
@@ -201,9 +201,6 @@ ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node);
ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node,
size_t completed_count, size_t estimated_total_items);
-// ABI warning
-ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple);
-
// ABI warning
struct Stage2LibCInstallation {
const char *include_dir;
@@ -302,6 +299,9 @@ struct ZigTarget {
ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu,
const char *dynamic_linker);
+// ABI warning
+ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple, const char *mcpu, const char *dynamic_linker);
+
// ABI warning
struct Stage2NativePaths {
From 89d7fc773d66609a8d93106f9a6d84d479771690 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Wed, 11 Mar 2020 20:03:36 +0100
Subject: [PATCH 070/111] std: Fix pwrite invocation on 32bit architectures
---
lib/std/os/linux.zig | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index 719e54184..79f9ba9c9 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -350,7 +350,13 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
);
}
} else {
- return syscall4(SYS_pread, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count, offset);
+ return syscall4(
+ SYS_pread,
+ @bitCast(usize, @as(isize, fd)),
+ @ptrToInt(buf),
+ count,
+ offset,
+ );
}
}
@@ -385,7 +391,36 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
}
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
- return syscall4(SYS_pwrite, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count, offset);
+ if (@hasDecl(@This(), "SYS_pwrite64")) {
+ if (require_aligned_register_pair) {
+ return syscall6(
+ SYS_pwrite64,
+ @bitCast(usize, @as(isize, fd)),
+ @ptrToInt(buf),
+ count,
+ 0,
+ @truncate(usize, offset),
+ @truncate(usize, offset >> 32),
+ );
+ } else {
+ return syscall5(
+ SYS_pwrite64,
+ @bitCast(usize, @as(isize, fd)),
+ @ptrToInt(buf),
+ count,
+ @truncate(usize, offset),
+ @truncate(usize, offset >> 32),
+ );
+ }
+ } else {
+ return syscall4(
+ SYS_pwrite,
+ @bitCast(usize, @as(isize, fd)),
+ @ptrToInt(buf),
+ count,
+ offset,
+ );
+ }
}
pub fn rename(old: [*:0]const u8, new: [*:0]const u8) usize {
From 11df0d0cf8c786d5b502c21a42d47631657a42f4 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Wed, 11 Mar 2020 20:56:43 +0100
Subject: [PATCH 071/111] std: Add setEndPos to fs.file
Allow the user to shrink/grow the file size as needed.
---
lib/std/c.zig | 1 +
lib/std/c/linux.zig | 2 ++
lib/std/fs/file.zig | 8 ++++++++
lib/std/io/test.zig | 17 +++++++++++++++++
lib/std/os.zig | 33 +++++++++++++++++++++++++++++++++
lib/std/os/linux.zig | 27 +++++++++++++++++++++++++++
lib/std/os/windows/kernel32.zig | 1 +
7 files changed, 89 insertions(+)
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 7c0190854..39a865ebb 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -79,6 +79,7 @@ pub extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, fla
pub extern "c" fn lseek(fd: fd_t, offset: off_t, whence: c_int) off_t;
pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int;
pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
+pub extern "c" fn ftruncate(fd: c_int, length: off_t) c_int;
pub extern "c" fn raise(sig: c_int) c_int;
pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;
pub extern "c" fn readv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint) isize;
diff --git a/lib/std/c/linux.zig b/lib/std/c/linux.zig
index 7ac5ecd3f..1da0db57d 100644
--- a/lib/std/c/linux.zig
+++ b/lib/std/c/linux.zig
@@ -82,6 +82,8 @@ pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
+pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
+
pub extern "c" fn sendfile(
out_fd: fd_t,
in_fd: fd_t,
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 8362f94ca..8bb377c99 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -99,6 +99,14 @@ pub const File = struct {
return false;
}
+ pub const SetEndPosError = os.TruncateError;
+
+ /// Shrinks or expands the file.
+ /// The file offset after this call is undefined.
+ pub fn setEndPos(self: File, length: u64) SetEndPosError!void {
+ try os.truncate(self.handle, length);
+ }
+
pub const SeekError = os.SeekError;
/// Repositions read/write file offset relative to the current offset.
diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig
index 38dd2bb67..961537707 100644
--- a/lib/std/io/test.zig
+++ b/lib/std/io/test.zig
@@ -125,6 +125,23 @@ test "File seek ops" {
expect((try file.getPos()) == 1234);
}
+test "setEndPos" {
+ const tmp_file_name = "temp_test_file.txt";
+ var file = try fs.cwd().createFile(tmp_file_name, .{});
+ defer {
+ file.close();
+ fs.cwd().deleteFile(tmp_file_name) catch {};
+ }
+
+ std.testing.expect((try file.getEndPos()) == 0);
+ try file.setEndPos(8192);
+ std.testing.expect((try file.getEndPos()) == 8192);
+ try file.setEndPos(4096);
+ std.testing.expect((try file.getEndPos()) == 4096);
+ try file.setEndPos(0);
+ std.testing.expect((try file.getEndPos()) == 0);
+}
+
test "updateTimes" {
const tmp_file_name = "just_a_temporary_file.txt";
var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true });
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 76a5dc2be..62347c2ee 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -438,6 +438,39 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
return index;
}
+pub const TruncateError = error{
+ /// The file descriptor is not open for writing.
+ NotFile,
+} || UnexpectedError;
+
+pub fn truncate(fd: fd_t, length: u64) TruncateError!void {
+ if (std.Target.current.os.tag == .windows) {
+ try windows.SetFilePointerEx_BEGIN(fd, length);
+
+ if (windows.kernel32.SetEndOfFile(fd) == 0)
+ return TruncateError.Unexpected;
+
+ return;
+ }
+
+ while (true) {
+ const rc = if (builtin.link_libc) blk: {
+ if (std.Target.current.os.tag == .linux)
+ break :blk system.ftruncate64(fd, @bitCast(off_t, length))
+ else
+ break :blk system.ftruncate(fd, @bitCast(off_t, length));
+ } else
+ system.ftruncate(fd, length);
+
+ switch (errno(rc)) {
+ 0 => return,
+ EINTR => continue,
+ EBADF, EINVAL => return error.NotFile,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+}
+
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
///
/// Retries when interrupted by a signal.
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index 79f9ba9c9..ba7356d62 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -390,6 +390,33 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
return syscall3(SYS_write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
}
+pub fn ftruncate(fd: i32, length: u64) usize {
+ if (@hasDecl(@This(), "SYS_ftruncate64")) {
+ if (require_aligned_register_pair) {
+ return syscall4(
+ SYS_ftruncate64,
+ @bitCast(usize, @as(isize, fd)),
+ 0,
+ @truncate(usize, length),
+ @truncate(usize, length >> 32),
+ );
+ } else {
+ return syscall3(
+ SYS_ftruncate64,
+ @bitCast(usize, @as(isize, fd)),
+ @truncate(usize, length),
+ @truncate(usize, length >> 32),
+ );
+ }
+ } else {
+ return syscall2(
+ SYS_ftruncate,
+ @bitCast(usize, @as(isize, fd)),
+ @truncate(usize, length),
+ );
+ }
+}
+
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
if (@hasDecl(@This(), "SYS_pwrite64")) {
if (require_aligned_register_pair) {
diff --git a/lib/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig
index 05a7a8f6a..2e5214eb2 100644
--- a/lib/std/os/windows/kernel32.zig
+++ b/lib/std/os/windows/kernel32.zig
@@ -8,6 +8,7 @@ pub extern "kernel32" fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) c
pub extern "kernel32" fn CloseHandle(hObject: HANDLE) callconv(.Stdcall) BOOL;
pub extern "kernel32" fn CreateDirectoryW(lpPathName: [*:0]const u16, lpSecurityAttributes: ?*SECURITY_ATTRIBUTES) callconv(.Stdcall) BOOL;
+pub extern "kernel32" fn SetEndOfFile(hFile: HANDLE) callconv(.Stdcall) BOOL;
pub extern "kernel32" fn CreateEventExW(
lpEventAttributes: ?*SECURITY_ATTRIBUTES,
From dda711ba0d650b921108c6d13bd9b7d37c47a96e Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 12 Mar 2020 14:18:41 +0200
Subject: [PATCH 072/111] translate-c treat c bools as ints
---
src-self-hosted/translate_c.zig | 65 ++++++++++++++++++++++++++++++---
test/translate_c.zig | 11 ++++++
2 files changed, 71 insertions(+), 5 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index f14ebe330..934ed3634 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -560,7 +560,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{var_name, c.getMangle()}) else var_name;
+ const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ var_name, c.getMangle() }) else var_name;
const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
@@ -677,7 +677,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{typedef_name, c.getMangle()}) else typedef_name;
+ const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ typedef_name, c.getMangle() }) else typedef_name;
if (mem.eql(u8, checked_name, "uint8_t"))
return transTypeDefAsBuiltin(c, typedef_decl, "u8")
@@ -4871,7 +4871,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
const name = try c.str(raw_name);
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{name, c.getMangle()}) else name;
+ const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }) else name;
if (scope.containsNow(mangled_name)) {
continue;
}
@@ -5560,12 +5560,63 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
}
}
+fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
+ if (!isBoolRes(node)) {
+ if (node.id != .InfixOp) return node;
+
+ const group_node = try c.a().create(ast.Node.GroupedExpression);
+ group_node.* = .{
+ .lparen = try appendToken(c, .LParen, "("),
+ .expr = node,
+ .rparen = try appendToken(c, .RParen, ")"),
+ };
+ return &group_node.base;
+ }
+
+ const builtin_node = try transCreateNodeBuiltinFnCall(c, "@boolToInt");
+ try builtin_node.params.push(node);
+ builtin_node.rparen_token = try appendToken(c, .RParen, ")");
+ return &builtin_node.base;
+}
+
+fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
+ if (isBoolRes(node)) {
+ if (node.id != .InfixOp) return node;
+
+ const group_node = try c.a().create(ast.Node.GroupedExpression);
+ group_node.* = .{
+ .lparen = try appendToken(c, .LParen, "("),
+ .expr = node,
+ .rparen = try appendToken(c, .RParen, ")"),
+ };
+ return &group_node.base;
+ }
+
+ const op_token = try appendToken(c, .BangEqual, "!=");
+ const zero = try transCreateNodeInt(c, 0);
+ const res = try c.a().create(ast.Node.InfixOp);
+ res.* = .{
+ .op_token = op_token,
+ .lhs = node,
+ .op = .BangEqual,
+ .rhs = zero,
+ };
+ const group_node = try c.a().create(ast.Node.GroupedExpression);
+ group_node.* = .{
+ .lparen = try appendToken(c, .LParen, "("),
+ .expr = &res.base,
+ .rparen = try appendToken(c, .RParen, ")"),
+ };
+ return &group_node.base;
+}
+
fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_loc: ZigClangSourceLocation, scope: *Scope) ParseError!*ast.Node {
var node = try parseCPrimaryExpr(c, it, source, source_loc, scope);
while (true) {
const tok = it.next().?;
var op_token: ast.TokenIndex = undefined;
var op_id: ast.Node.InfixOp.Op = undefined;
+ var bool_op = false;
switch (tok.id) {
.Period => {
const name_tok = it.next().?;
@@ -5654,10 +5705,12 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
.AmpersandAmpersand => {
op_token = try appendToken(c, .Keyword_and, "and");
op_id = .BoolAnd;
+ bool_op = true;
},
.PipePipe => {
op_token = try appendToken(c, .Keyword_or, "or");
op_id = .BoolOr;
+ bool_op = true;
},
.AngleBracketRight => {
op_token = try appendToken(c, .AngleBracketRight, ">");
@@ -5740,12 +5793,14 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
return node;
},
}
+ const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
const op_node = try c.a().create(ast.Node.InfixOp);
+ const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
op_node.* = .{
.op_token = op_token,
- .lhs = node,
+ .lhs = try cast_fn(c, node),
.op = op_id,
- .rhs = try parseCPrefixOpExpr(c, it, source, source_loc, scope),
+ .rhs = try cast_fn(c, rhs_node),
};
node = &op_node.base;
}
diff --git a/test/translate_c.zig b/test/translate_c.zig
index e21c3c49a..29b07b86a 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -3,6 +3,17 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void {
+ cases.add("c booleans are just ints",
+ \\#define FOO(x) ((x >= 0) + (x >= 0))
+ \\#define BAR 1 && 2 > 4
+ , &[_][]const u8{
+ \\pub inline fn FOO(x: var) @TypeOf(@boolToInt(x >= 0) + @boolToInt(x >= 0)) {
+ \\ return @boolToInt(x >= 0) + @boolToInt(x >= 0);
+ \\}
+ ,
+ \\pub const BAR = (1 != 0) and (2 > 4);
+ });
+
cases.add("struct with aligned fields",
\\struct foo {
\\ __attribute__((aligned(1))) short bar;
From ae3fb6df007807a37fe448fdef2b8ee669b29a5a Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 11:56:21 -0600
Subject: [PATCH 073/111] Copy fmtstream
---
lib/std/fmtstream.zig | 1754 +++++++++++++++++++++++++++++++++++++++++
lib/std/std.zig | 1 +
2 files changed, 1755 insertions(+)
create mode 100644 lib/std/fmtstream.zig
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
new file mode 100644
index 000000000..a7525ba79
--- /dev/null
+++ b/lib/std/fmtstream.zig
@@ -0,0 +1,1754 @@
+const std = @import("std.zig");
+const math = std.math;
+const assert = std.debug.assert;
+const mem = std.mem;
+const builtin = @import("builtin");
+const errol = @import("fmt/errol.zig");
+const lossyCast = std.math.lossyCast;
+
+pub const default_max_depth = 3;
+
+pub const Alignment = enum {
+ Left,
+ Center,
+ Right,
+};
+
+pub const FormatOptions = struct {
+ precision: ?usize = null,
+ width: ?usize = null,
+ alignment: ?Alignment = null,
+ fill: u8 = ' ',
+};
+
+fn peekIsAlign(comptime fmt: []const u8) bool {
+ // Should only be called during a state transition to the format segment.
+ comptime assert(fmt[0] == ':');
+
+ inline for (([_]u8{ 1, 2 })[0..]) |i| {
+ if (fmt.len > i and (fmt[i] == '<' or fmt[i] == '^' or fmt[i] == '>')) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/// Renders fmt string with args, calling output with slices of bytes.
+/// If `output` returns an error, the error is returned from `format` and
+/// `output` is not called again.
+///
+/// The format string must be comptime known and may contain placeholders following
+/// this format:
+/// `{[position][specifier]:[fill][alignment][width].[precision]}`
+///
+/// Each word between `[` and `]` is a parameter you have to replace with something:
+///
+/// - *position* is the index of the argument that should be inserted
+/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
+/// - *fill* is a single character which is used to pad the formatted text
+/// - *alignment* is one of the three characters `<`, `^` or `>`. they define if the text is *left*, *center*, or *right* aligned
+/// - *width* is the total width of the field in characters
+/// - *precision* specifies how many decimals a formatted number should have
+///
+/// Note that most of the parameters are optional and may be omitted. Also you can leave out separators like `:` and `.` when
+/// all parameters after the separator are omitted.
+/// Only exception is the *fill* parameter. If *fill* is required, one has to specify *alignment* as well, as otherwise
+/// the digits after `:` is interpreted as *width*, not *fill*.
+///
+/// The *specifier* has several options for types:
+/// - `x` and `X`:
+/// - format the non-numeric value as a string of bytes in hexadecimal notation ("binary dump") in either lower case or upper case
+/// - output numeric value in hexadecimal notation
+/// - `s`: print a pointer-to-many as a c-string, use zero-termination
+/// - `B` and `Bi`: output a memory size in either metric (1000) or power-of-two (1024) based notation. works for both float and integer values.
+/// - `e`: output floating point value in scientific notation
+/// - `d`: output numeric value in decimal notation
+/// - `b`: output integer value in binary notation
+/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
+/// - `*`: output the address of the value instead of the value itself.
+///
+/// If a formatted user type contains a function of the type
+/// ```
+/// fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, context: var, comptime Errors: type, comptime output: fn (@TypeOf(context), []const u8) Errors!void) Errors!void
+/// ```
+/// with `?` being the type formatted, this function will be called instead of the default implementation.
+/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
+///
+/// A user type may be a `struct`, `vector`, `union` or `enum` type.
+pub fn format(
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ comptime fmt: []const u8,
+ args: var,
+) Errors!void {
+ const ArgSetType = u32;
+ if (@typeInfo(@TypeOf(args)) != .Struct) {
+ @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
+ }
+ if (args.len > ArgSetType.bit_count) {
+ @compileError("32 arguments max are supported per format call");
+ }
+
+ const State = enum {
+ Start,
+ Positional,
+ CloseBrace,
+ Specifier,
+ FormatFillAndAlign,
+ FormatWidth,
+ FormatPrecision,
+ };
+
+ comptime var start_index = 0;
+ comptime var state = State.Start;
+ comptime var maybe_pos_arg: ?comptime_int = null;
+ comptime var specifier_start = 0;
+ comptime var specifier_end = 0;
+ comptime var options = FormatOptions{};
+ comptime var arg_state: struct {
+ next_arg: usize = 0,
+ used_args: ArgSetType = 0,
+ args_len: usize = args.len,
+
+ fn hasUnusedArgs(comptime self: *@This()) bool {
+ return (@popCount(ArgSetType, self.used_args) != self.args_len);
+ }
+
+ fn nextArg(comptime self: *@This(), comptime pos_arg: ?comptime_int) comptime_int {
+ const next_idx = pos_arg orelse blk: {
+ const arg = self.next_arg;
+ self.next_arg += 1;
+ break :blk arg;
+ };
+
+ if (next_idx >= self.args_len) {
+ @compileError("Too few arguments");
+ }
+
+ // Mark this argument as used
+ self.used_args |= 1 << next_idx;
+
+ return next_idx;
+ }
+ } = .{};
+
+ inline for (fmt) |c, i| {
+ switch (state) {
+ .Start => switch (c) {
+ '{' => {
+ if (start_index < i) {
+ try output(context, fmt[start_index..i]);
+ }
+
+ start_index = i;
+ specifier_start = i + 1;
+ specifier_end = i + 1;
+ maybe_pos_arg = null;
+ state = .Positional;
+ options = FormatOptions{};
+ },
+ '}' => {
+ if (start_index < i) {
+ try output(context, fmt[start_index..i]);
+ }
+ state = .CloseBrace;
+ },
+ else => {},
+ },
+ .Positional => switch (c) {
+ '{' => {
+ state = .Start;
+ start_index = i;
+ },
+ ':' => {
+ state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
+ specifier_end = i;
+ },
+ '0'...'9' => {
+ if (maybe_pos_arg == null) {
+ maybe_pos_arg = 0;
+ }
+
+ maybe_pos_arg.? *= 10;
+ maybe_pos_arg.? += c - '0';
+ specifier_start = i + 1;
+
+ if (maybe_pos_arg.? >= args.len) {
+ @compileError("Positional value refers to non-existent argument");
+ }
+ },
+ '}' => {
+ const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
+
+ try formatType(
+ args[arg_to_print],
+ fmt[0..0],
+ options,
+ context,
+ Errors,
+ output,
+ default_max_depth,
+ );
+
+ state = .Start;
+ start_index = i + 1;
+ },
+ else => {
+ state = .Specifier;
+ specifier_start = i;
+ },
+ },
+ .CloseBrace => switch (c) {
+ '}' => {
+ state = .Start;
+ start_index = i;
+ },
+ else => @compileError("Single '}' encountered in format string"),
+ },
+ .Specifier => switch (c) {
+ ':' => {
+ specifier_end = i;
+ state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
+ },
+ '}' => {
+ const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
+
+ try formatType(
+ args[arg_to_print],
+ fmt[specifier_start..i],
+ options,
+ context,
+ Errors,
+ output,
+ default_max_depth,
+ );
+ state = .Start;
+ start_index = i + 1;
+ },
+ else => {},
+ },
+ // Only entered if the format string contains a fill/align segment.
+ .FormatFillAndAlign => switch (c) {
+ '<' => {
+ options.alignment = Alignment.Left;
+ state = .FormatWidth;
+ },
+ '^' => {
+ options.alignment = Alignment.Center;
+ state = .FormatWidth;
+ },
+ '>' => {
+ options.alignment = Alignment.Right;
+ state = .FormatWidth;
+ },
+ else => {
+ options.fill = c;
+ },
+ },
+ .FormatWidth => switch (c) {
+ '0'...'9' => {
+ if (options.width == null) {
+ options.width = 0;
+ }
+
+ options.width.? *= 10;
+ options.width.? += c - '0';
+ },
+ '.' => {
+ state = .FormatPrecision;
+ },
+ '}' => {
+ const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
+
+ try formatType(
+ args[arg_to_print],
+ fmt[specifier_start..specifier_end],
+ options,
+ context,
+ Errors,
+ output,
+ default_max_depth,
+ );
+ state = .Start;
+ start_index = i + 1;
+ },
+ else => {
+ @compileError("Unexpected character in width value: " ++ [_]u8{c});
+ },
+ },
+ .FormatPrecision => switch (c) {
+ '0'...'9' => {
+ if (options.precision == null) {
+ options.precision = 0;
+ }
+
+ options.precision.? *= 10;
+ options.precision.? += c - '0';
+ },
+ '}' => {
+ const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
+
+ try formatType(
+ args[arg_to_print],
+ fmt[specifier_start..specifier_end],
+ options,
+ context,
+ Errors,
+ output,
+ default_max_depth,
+ );
+ state = .Start;
+ start_index = i + 1;
+ },
+ else => {
+ @compileError("Unexpected character in precision value: " ++ [_]u8{c});
+ },
+ },
+ }
+ }
+ comptime {
+ if (comptime arg_state.hasUnusedArgs()) {
+ @compileError("Unused arguments");
+ }
+ if (state != State.Start) {
+ @compileError("Incomplete format string: " ++ fmt);
+ }
+ }
+ if (start_index < fmt.len) {
+ try output(context, fmt[start_index..]);
+ }
+}
+
+pub fn formatType(
+ value: var,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ max_depth: usize,
+) Errors!void {
+ if (comptime std.mem.eql(u8, fmt, "*")) {
+ try output(context, @typeName(@TypeOf(value).Child));
+ try output(context, "@");
+ try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, context, Errors, output);
+ return;
+ }
+
+ const T = @TypeOf(value);
+ switch (@typeInfo(T)) {
+ .ComptimeInt, .Int, .Float => {
+ return formatValue(value, fmt, options, context, Errors, output);
+ },
+ .Void => {
+ return output(context, "void");
+ },
+ .Bool => {
+ return output(context, if (value) "true" else "false");
+ },
+ .Optional => {
+ if (value) |payload| {
+ return formatType(payload, fmt, options, context, Errors, output, max_depth);
+ } else {
+ return output(context, "null");
+ }
+ },
+ .ErrorUnion => {
+ if (value) |payload| {
+ return formatType(payload, fmt, options, context, Errors, output, max_depth);
+ } else |err| {
+ return formatType(err, fmt, options, context, Errors, output, max_depth);
+ }
+ },
+ .ErrorSet => {
+ try output(context, "error.");
+ return output(context, @errorName(value));
+ },
+ .Enum => |enumInfo| {
+ if (comptime std.meta.trait.hasFn("format")(T)) {
+ return value.format(fmt, options, context, Errors, output);
+ }
+
+ try output(context, @typeName(T));
+ if (enumInfo.is_exhaustive) {
+ try output(context, ".");
+ try output(context, @tagName(value));
+ } else {
+ // TODO: when @tagName works on exhaustive enums print known enum strings
+ try output(context, "(");
+ try formatType(@enumToInt(value), fmt, options, context, Errors, output, max_depth);
+ try output(context, ")");
+ }
+ },
+ .Union => {
+ if (comptime std.meta.trait.hasFn("format")(T)) {
+ return value.format(fmt, options, context, Errors, output);
+ }
+
+ try output(context, @typeName(T));
+ if (max_depth == 0) {
+ return output(context, "{ ... }");
+ }
+ const info = @typeInfo(T).Union;
+ if (info.tag_type) |UnionTagType| {
+ try output(context, "{ .");
+ try output(context, @tagName(@as(UnionTagType, value)));
+ try output(context, " = ");
+ inline for (info.fields) |u_field| {
+ if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
+ try formatType(@field(value, u_field.name), fmt, options, context, Errors, output, max_depth - 1);
+ }
+ }
+ try output(context, " }");
+ } else {
+ try format(context, Errors, output, "@{x}", .{@ptrToInt(&value)});
+ }
+ },
+ .Struct => |StructT| {
+ if (comptime std.meta.trait.hasFn("format")(T)) {
+ return value.format(fmt, options, context, Errors, output);
+ }
+
+ try output(context, @typeName(T));
+ if (max_depth == 0) {
+ return output(context, "{ ... }");
+ }
+ try output(context, "{");
+ inline for (StructT.fields) |f, i| {
+ if (i == 0) {
+ try output(context, " .");
+ } else {
+ try output(context, ", .");
+ }
+ try output(context, f.name);
+ try output(context, " = ");
+ try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);
+ }
+ try output(context, " }");
+ },
+ .Pointer => |ptr_info| switch (ptr_info.size) {
+ .One => switch (@typeInfo(ptr_info.child)) {
+ .Array => |info| {
+ if (info.child == u8) {
+ return formatText(value, fmt, options, context, Errors, output);
+ }
+ return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
+ },
+ .Enum, .Union, .Struct => {
+ return formatType(value.*, fmt, options, context, Errors, output, max_depth);
+ },
+ else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
+ },
+ .Many, .C => {
+ if (ptr_info.sentinel) |sentinel| {
+ return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
+ }
+ if (ptr_info.child == u8) {
+ if (fmt.len > 0 and fmt[0] == 's') {
+ return formatText(mem.span(value), fmt, options, context, Errors, output);
+ }
+ }
+ return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
+ },
+ .Slice => {
+ if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
+ return formatText(value, fmt, options, context, Errors, output);
+ }
+ if (ptr_info.child == u8) {
+ return formatText(value, fmt, options, context, Errors, output);
+ }
+ return format(context, Errors, output, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
+ },
+ },
+ .Array => |info| {
+ const Slice = @Type(builtin.TypeInfo{
+ .Pointer = .{
+ .size = .Slice,
+ .is_const = true,
+ .is_volatile = false,
+ .is_allowzero = false,
+ .alignment = @alignOf(info.child),
+ .child = info.child,
+ .sentinel = null,
+ },
+ });
+ return formatType(@as(Slice, &value), fmt, options, context, Errors, output, max_depth);
+ },
+ .Vector => {
+ const len = @typeInfo(T).Vector.len;
+ try output(context, "{ ");
+ var i: usize = 0;
+ while (i < len) : (i += 1) {
+ try formatValue(value[i], fmt, options, context, Errors, output);
+ if (i < len - 1) {
+ try output(context, ", ");
+ }
+ }
+ try output(context, " }");
+ },
+ .Fn => {
+ return format(context, Errors, output, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
+ },
+ .Type => return output(context, @typeName(T)),
+ .EnumLiteral => {
+ const buffer = [_]u8{'.'} ++ @tagName(value);
+ return formatType(buffer, fmt, options, context, Errors, output, max_depth);
+ },
+ else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
+ }
+}
+
+fn formatValue(
+ value: var,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ if (comptime std.mem.eql(u8, fmt, "B")) {
+ return formatBytes(value, options, 1000, context, Errors, output);
+ } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
+ return formatBytes(value, options, 1024, context, Errors, output);
+ }
+
+ const T = @TypeOf(value);
+ switch (@typeInfo(T)) {
+ .Float => return formatFloatValue(value, fmt, options, context, Errors, output),
+ .Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output),
+ .Bool => return output(context, if (value) "true" else "false"),
+ else => comptime unreachable,
+ }
+}
+
+pub fn formatIntValue(
+ value: var,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ comptime var radix = 10;
+ comptime var uppercase = false;
+
+ const int_value = if (@TypeOf(value) == comptime_int) blk: {
+ const Int = math.IntFittingRange(value, value);
+ break :blk @as(Int, value);
+ } else
+ value;
+
+ if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
+ radix = 10;
+ uppercase = false;
+ } else if (comptime std.mem.eql(u8, fmt, "c")) {
+ if (@TypeOf(int_value).bit_count <= 8) {
+ return formatAsciiChar(@as(u8, int_value), options, context, Errors, output);
+ } else {
+ @compileError("Cannot print integer that is larger than 8 bits as a ascii");
+ }
+ } else if (comptime std.mem.eql(u8, fmt, "b")) {
+ radix = 2;
+ uppercase = false;
+ } else if (comptime std.mem.eql(u8, fmt, "x")) {
+ radix = 16;
+ uppercase = false;
+ } else if (comptime std.mem.eql(u8, fmt, "X")) {
+ radix = 16;
+ uppercase = true;
+ } else {
+ @compileError("Unknown format string: '" ++ fmt ++ "'");
+ }
+
+ return formatInt(int_value, radix, uppercase, options, context, Errors, output);
+}
+
+fn formatFloatValue(
+ value: var,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
+ return formatFloatScientific(value, options, context, Errors, output);
+ } else if (comptime std.mem.eql(u8, fmt, "d")) {
+ return formatFloatDecimal(value, options, context, Errors, output);
+ } else {
+ @compileError("Unknown format string: '" ++ fmt ++ "'");
+ }
+}
+
+pub fn formatText(
+ bytes: []const u8,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ if (fmt.len == 0) {
+ return output(context, bytes);
+ } else if (comptime std.mem.eql(u8, fmt, "s")) {
+ return formatBuf(bytes, options, context, Errors, output);
+ } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
+ for (bytes) |c| {
+ try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, context, Errors, output);
+ }
+ return;
+ } else {
+ @compileError("Unknown format string: '" ++ fmt ++ "'");
+ }
+}
+
+pub fn formatAsciiChar(
+ c: u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ return output(context, @as(*const [1]u8, &c)[0..]);
+}
+
+pub fn formatBuf(
+ buf: []const u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ try output(context, buf);
+
+ const width = options.width orelse 0;
+ var leftover_padding = if (width > buf.len) (width - buf.len) else return;
+ const pad_byte: u8 = options.fill;
+ while (leftover_padding > 0) : (leftover_padding -= 1) {
+ try output(context, @as(*const [1]u8, &pad_byte)[0..1]);
+ }
+}
+
+// Print a float in scientific notation to the specified precision. Null uses full precision.
+// It should be the case that every full precision, printed value can be re-parsed back to the
+// same type unambiguously.
+pub fn formatFloatScientific(
+ value: var,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ var x = @floatCast(f64, value);
+
+ // Errol doesn't handle these special cases.
+ if (math.signbit(x)) {
+ try output(context, "-");
+ x = -x;
+ }
+
+ if (math.isNan(x)) {
+ return output(context, "nan");
+ }
+ if (math.isPositiveInf(x)) {
+ return output(context, "inf");
+ }
+ if (x == 0.0) {
+ try output(context, "0");
+
+ if (options.precision) |precision| {
+ if (precision != 0) {
+ try output(context, ".");
+ var i: usize = 0;
+ while (i < precision) : (i += 1) {
+ try output(context, "0");
+ }
+ }
+ } else {
+ try output(context, ".0");
+ }
+
+ try output(context, "e+00");
+ return;
+ }
+
+ var buffer: [32]u8 = undefined;
+ var float_decimal = errol.errol3(x, buffer[0..]);
+
+ if (options.precision) |precision| {
+ errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
+
+ try output(context, float_decimal.digits[0..1]);
+
+ // {e0} case prints no `.`
+ if (precision != 0) {
+ try output(context, ".");
+
+ var printed: usize = 0;
+ if (float_decimal.digits.len > 1) {
+ const num_digits = math.min(float_decimal.digits.len, precision + 1);
+ try output(context, float_decimal.digits[1..num_digits]);
+ printed += num_digits - 1;
+ }
+
+ while (printed < precision) : (printed += 1) {
+ try output(context, "0");
+ }
+ }
+ } else {
+ try output(context, float_decimal.digits[0..1]);
+ try output(context, ".");
+ if (float_decimal.digits.len > 1) {
+ const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;
+
+ try output(context, float_decimal.digits[1..num_digits]);
+ } else {
+ try output(context, "0");
+ }
+ }
+
+ try output(context, "e");
+ const exp = float_decimal.exp - 1;
+
+ if (exp >= 0) {
+ try output(context, "+");
+ if (exp > -10 and exp < 10) {
+ try output(context, "0");
+ }
+ try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
+ } else {
+ try output(context, "-");
+ if (exp > -10 and exp < 10) {
+ try output(context, "0");
+ }
+ try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
+ }
+}
+
+// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
+// By default floats are printed at full precision (no rounding).
+pub fn formatFloatDecimal(
+ value: var,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ var x = @as(f64, value);
+
+ // Errol doesn't handle these special cases.
+ if (math.signbit(x)) {
+ try output(context, "-");
+ x = -x;
+ }
+
+ if (math.isNan(x)) {
+ return output(context, "nan");
+ }
+ if (math.isPositiveInf(x)) {
+ return output(context, "inf");
+ }
+ if (x == 0.0) {
+ try output(context, "0");
+
+ if (options.precision) |precision| {
+ if (precision != 0) {
+ try output(context, ".");
+ var i: usize = 0;
+ while (i < precision) : (i += 1) {
+ try output(context, "0");
+ }
+ } else {
+ try output(context, ".0");
+ }
+ }
+
+ return;
+ }
+
+ // non-special case, use errol3
+ var buffer: [32]u8 = undefined;
+ var float_decimal = errol.errol3(x, buffer[0..]);
+
+ if (options.precision) |precision| {
+ errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Decimal);
+
+ // exp < 0 means the leading is always 0 as errol result is normalized.
+ var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
+
+ // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
+ var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
+
+ if (num_digits_whole > 0) {
+ // We may have to zero pad, for instance 1e4 requires zero padding.
+ try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
+
+ var i = num_digits_whole_no_pad;
+ while (i < num_digits_whole) : (i += 1) {
+ try output(context, "0");
+ }
+ } else {
+ try output(context, "0");
+ }
+
+ // {.0} special case doesn't want a trailing '.'
+ if (precision == 0) {
+ return;
+ }
+
+ try output(context, ".");
+
+ // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
+ var printed: usize = 0;
+
+ // Zero-fill until we reach significant digits or run out of precision.
+ if (float_decimal.exp <= 0) {
+ const zero_digit_count = @intCast(usize, -float_decimal.exp);
+ const zeros_to_print = math.min(zero_digit_count, precision);
+
+ var i: usize = 0;
+ while (i < zeros_to_print) : (i += 1) {
+ try output(context, "0");
+ printed += 1;
+ }
+
+ if (printed >= precision) {
+ return;
+ }
+ }
+
+ // Remaining fractional portion, zero-padding if insufficient.
+ assert(precision >= printed);
+ if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
+ try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
+ return;
+ } else {
+ try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
+ printed += float_decimal.digits.len - num_digits_whole_no_pad;
+
+ while (printed < precision) : (printed += 1) {
+ try output(context, "0");
+ }
+ }
+ } else {
+ // exp < 0 means the leading is always 0 as errol result is normalized.
+ var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
+
+ // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
+ var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
+
+ if (num_digits_whole > 0) {
+ // We may have to zero pad, for instance 1e4 requires zero padding.
+ try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
+
+ var i = num_digits_whole_no_pad;
+ while (i < num_digits_whole) : (i += 1) {
+ try output(context, "0");
+ }
+ } else {
+ try output(context, "0");
+ }
+
+ // Omit `.` if no fractional portion
+ if (float_decimal.exp >= 0 and num_digits_whole_no_pad == float_decimal.digits.len) {
+ return;
+ }
+
+ try output(context, ".");
+
+ // Zero-fill until we reach significant digits or run out of precision.
+ if (float_decimal.exp < 0) {
+ const zero_digit_count = @intCast(usize, -float_decimal.exp);
+
+ var i: usize = 0;
+ while (i < zero_digit_count) : (i += 1) {
+ try output(context, "0");
+ }
+ }
+
+ try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
+ }
+}
+
+pub fn formatBytes(
+ value: var,
+ options: FormatOptions,
+ comptime radix: usize,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ if (value == 0) {
+ return output(context, "0B");
+ }
+
+ const mags_si = " kMGTPEZY";
+ const mags_iec = " KMGTPEZY";
+ const magnitude = switch (radix) {
+ 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
+ 1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
+ else => unreachable,
+ };
+ const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
+ const suffix = switch (radix) {
+ 1000 => mags_si[magnitude],
+ 1024 => mags_iec[magnitude],
+ else => unreachable,
+ };
+
+ try formatFloatDecimal(new_value, options, context, Errors, output);
+
+ if (suffix == ' ') {
+ return output(context, "B");
+ }
+
+ const buf = switch (radix) {
+ 1000 => &[_]u8{ suffix, 'B' },
+ 1024 => &[_]u8{ suffix, 'i', 'B' },
+ else => unreachable,
+ };
+ return output(context, buf);
+}
+
+pub fn formatInt(
+ value: var,
+ base: u8,
+ uppercase: bool,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ const int_value = if (@TypeOf(value) == comptime_int) blk: {
+ const Int = math.IntFittingRange(value, value);
+ break :blk @as(Int, value);
+ } else
+ value;
+
+ if (@TypeOf(int_value).is_signed) {
+ return formatIntSigned(int_value, base, uppercase, options, context, Errors, output);
+ } else {
+ return formatIntUnsigned(int_value, base, uppercase, options, context, Errors, output);
+ }
+}
+
+fn formatIntSigned(
+ value: var,
+ base: u8,
+ uppercase: bool,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ const new_options = FormatOptions{
+ .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
+ .precision = options.precision,
+ .fill = options.fill,
+ };
+ const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
+ const Uint = std.meta.IntType(false, bit_count);
+ if (value < 0) {
+ try output(context, "-");
+ const new_value = math.absCast(value);
+ return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
+ } else if (options.width == null or options.width.? == 0) {
+ return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, context, Errors, output);
+ } else {
+ try output(context, "+");
+ const new_value = @intCast(Uint, value);
+ return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
+ }
+}
+
+fn formatIntUnsigned(
+ value: var,
+ base: u8,
+ uppercase: bool,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+) Errors!void {
+ assert(base >= 2);
+ var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
+ const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count);
+ const MinInt = std.meta.IntType(@TypeOf(value).is_signed, min_int_bits);
+ var a: MinInt = value;
+ var index: usize = buf.len;
+
+ while (true) {
+ const digit = a % base;
+ index -= 1;
+ buf[index] = digitToChar(@intCast(u8, digit), uppercase);
+ a /= base;
+ if (a == 0) break;
+ }
+
+ const digits_buf = buf[index..];
+ const width = options.width orelse 0;
+ const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
+
+ if (padding > index) {
+ const zero_byte: u8 = options.fill;
+ var leftover_padding = padding - index;
+ while (true) {
+ try output(context, @as(*const [1]u8, &zero_byte)[0..]);
+ leftover_padding -= 1;
+ if (leftover_padding == 0) break;
+ }
+ mem.set(u8, buf[0..index], options.fill);
+ return output(context, &buf);
+ } else {
+ const padded_buf = buf[index - padding ..];
+ mem.set(u8, padded_buf[0..padding], options.fill);
+ return output(context, padded_buf);
+ }
+}
+
+pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
+ var context = FormatIntBuf{
+ .out_buf = out_buf,
+ .index = 0,
+ };
+ formatInt(value, base, uppercase, options, &context, error{}, formatIntCallback) catch unreachable;
+ return context.index;
+}
+const FormatIntBuf = struct {
+ out_buf: []u8,
+ index: usize,
+};
+fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
+ mem.copy(u8, context.out_buf[context.index..], bytes);
+ context.index += bytes.len;
+}
+
+pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
+ if (!T.is_signed) return parseUnsigned(T, buf, radix);
+ if (buf.len == 0) return @as(T, 0);
+ if (buf[0] == '-') {
+ return math.negate(try parseUnsigned(T, buf[1..], radix));
+ } else if (buf[0] == '+') {
+ return parseUnsigned(T, buf[1..], radix);
+ } else {
+ return parseUnsigned(T, buf, radix);
+ }
+}
+
+test "parseInt" {
+ std.testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
+ std.testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
+ std.testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
+ std.testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
+ std.testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
+ std.testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
+ std.testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
+}
+
+pub const ParseUnsignedError = error{
+ /// The result cannot fit in the type specified
+ Overflow,
+
+ /// The input had a byte that was not a digit
+ InvalidCharacter,
+};
+
+pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
+ var x: T = 0;
+
+ for (buf) |c| {
+ const digit = try charToDigit(c, radix);
+
+ if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
+ x = try math.add(T, x, try math.cast(T, digit));
+ }
+
+ return x;
+}
+
+test "parseUnsigned" {
+ std.testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
+ std.testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
+ std.testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
+
+ std.testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
+ std.testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
+
+ std.testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
+
+ std.testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
+ std.testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
+
+ std.testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
+ std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
+
+ std.testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
+
+ // these numbers should fit even though the radix itself doesn't fit in the destination type
+ std.testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
+ std.testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
+ std.testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
+ std.testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
+ std.testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
+ std.testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
+}
+
+pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
+
+test "parseFloat" {
+ _ = @import("fmt/parse_float.zig");
+}
+
+pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
+ const value = switch (c) {
+ '0'...'9' => c - '0',
+ 'A'...'Z' => c - 'A' + 10,
+ 'a'...'z' => c - 'a' + 10,
+ else => return error.InvalidCharacter,
+ };
+
+ if (value >= radix) return error.InvalidCharacter;
+
+ return value;
+}
+
+fn digitToChar(digit: u8, uppercase: bool) u8 {
+ return switch (digit) {
+ 0...9 => digit + '0',
+ 10...35 => digit + ((if (uppercase) @as(u8, 'A') else @as(u8, 'a')) - 10),
+ else => unreachable,
+ };
+}
+
+const BufPrintContext = struct {
+ remaining: []u8,
+};
+
+fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
+ if (context.remaining.len < bytes.len) {
+ mem.copy(u8, context.remaining, bytes[0..context.remaining.len]);
+ return error.BufferTooSmall;
+ }
+ mem.copy(u8, context.remaining, bytes);
+ context.remaining = context.remaining[bytes.len..];
+}
+
+pub const BufPrintError = error{
+ /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
+ BufferTooSmall,
+};
+pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
+ var context = BufPrintContext{ .remaining = buf };
+ try format(&context, BufPrintError, bufPrintWrite, fmt, args);
+ return buf[0 .. buf.len - context.remaining.len];
+}
+
+pub const AllocPrintError = error{OutOfMemory};
+
+pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
+ var size: usize = 0;
+ format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
+ const buf = try allocator.alloc(u8, size);
+ return bufPrint(buf, fmt, args) catch |err| switch (err) {
+ error.BufferTooSmall => unreachable, // we just counted the size above
+ };
+}
+
+fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
+ size.* += bytes.len;
+}
+
+pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
+ const result = try allocPrint(allocator, fmt ++ "\x00", args);
+ return result[0 .. result.len - 1 :0];
+}
+
+test "bufPrintInt" {
+ var buffer: [100]u8 = undefined;
+ const buf = buffer[0..];
+
+ std.testing.expectEqualSlices(u8, "-1", bufPrintIntToSlice(buf, @as(i1, -1), 10, false, FormatOptions{}));
+
+ std.testing.expectEqualSlices(u8, "-101111000110000101001110", bufPrintIntToSlice(buf, @as(i32, -12345678), 2, false, FormatOptions{}));
+ std.testing.expectEqualSlices(u8, "-12345678", bufPrintIntToSlice(buf, @as(i32, -12345678), 10, false, FormatOptions{}));
+ std.testing.expectEqualSlices(u8, "-bc614e", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, false, FormatOptions{}));
+ std.testing.expectEqualSlices(u8, "-BC614E", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, true, FormatOptions{}));
+
+ std.testing.expectEqualSlices(u8, "12345678", bufPrintIntToSlice(buf, @as(u32, 12345678), 10, true, FormatOptions{}));
+
+ std.testing.expectEqualSlices(u8, " 666", bufPrintIntToSlice(buf, @as(u32, 666), 10, false, FormatOptions{ .width = 6 }));
+ std.testing.expectEqualSlices(u8, " 1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 6 }));
+ std.testing.expectEqualSlices(u8, "1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 1 }));
+
+ std.testing.expectEqualSlices(u8, "+42", bufPrintIntToSlice(buf, @as(i32, 42), 10, false, FormatOptions{ .width = 3 }));
+ std.testing.expectEqualSlices(u8, "-42", bufPrintIntToSlice(buf, @as(i32, -42), 10, false, FormatOptions{ .width = 3 }));
+}
+
+fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) []u8 {
+ return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
+}
+
+test "parse u64 digit too big" {
+ _ = parseUnsigned(u64, "123a", 10) catch |err| {
+ if (err == error.InvalidCharacter) return;
+ unreachable;
+ };
+ unreachable;
+}
+
+test "parse unsigned comptime" {
+ comptime {
+ std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
+ }
+}
+
+test "optional" {
+ {
+ const value: ?i32 = 1234;
+ try testFmt("optional: 1234\n", "optional: {}\n", .{value});
+ }
+ {
+ const value: ?i32 = null;
+ try testFmt("optional: null\n", "optional: {}\n", .{value});
+ }
+}
+
+test "error" {
+ {
+ const value: anyerror!i32 = 1234;
+ try testFmt("error union: 1234\n", "error union: {}\n", .{value});
+ }
+ {
+ const value: anyerror!i32 = error.InvalidChar;
+ try testFmt("error union: error.InvalidChar\n", "error union: {}\n", .{value});
+ }
+}
+
+test "int.small" {
+ {
+ const value: u3 = 0b101;
+ try testFmt("u3: 5\n", "u3: {}\n", .{value});
+ }
+}
+
+test "int.specifier" {
+ {
+ const value: u8 = 'a';
+ try testFmt("u8: a\n", "u8: {c}\n", .{value});
+ }
+ {
+ const value: u8 = 0b1100;
+ try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", .{value});
+ }
+}
+
+test "int.padded" {
+ try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
+ try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
+}
+
+test "buffer" {
+ {
+ var buf1: [32]u8 = undefined;
+ var context = BufPrintContext{ .remaining = buf1[0..] };
+ try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
+ var res = buf1[0 .. buf1.len - context.remaining.len];
+ std.testing.expect(mem.eql(u8, res, "1234"));
+
+ context = BufPrintContext{ .remaining = buf1[0..] };
+ try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
+ res = buf1[0 .. buf1.len - context.remaining.len];
+ std.testing.expect(mem.eql(u8, res, "a"));
+
+ context = BufPrintContext{ .remaining = buf1[0..] };
+ try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
+ res = buf1[0 .. buf1.len - context.remaining.len];
+ std.testing.expect(mem.eql(u8, res, "1100"));
+ }
+}
+
+test "array" {
+ {
+ const value: [3]u8 = "abc".*;
+ try testFmt("array: abc\n", "array: {}\n", .{value});
+ try testFmt("array: abc\n", "array: {}\n", .{&value});
+
+ var buf: [100]u8 = undefined;
+ try testFmt(
+ try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@ptrToInt(&value)}),
+ "array: {*}\n",
+ .{&value},
+ );
+ }
+}
+
+test "slice" {
+ {
+ const value: []const u8 = "abc";
+ try testFmt("slice: abc\n", "slice: {}\n", .{value});
+ }
+ {
+ const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
+ try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
+ }
+
+ try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
+ try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
+}
+
+test "pointer" {
+ {
+ const value = @intToPtr(*align(1) i32, 0xdeadbeef);
+ try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", .{value});
+ try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", .{value});
+ }
+ {
+ const value = @intToPtr(fn () void, 0xdeadbeef);
+ try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
+ }
+ {
+ const value = @intToPtr(fn () void, 0xdeadbeef);
+ try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
+ }
+}
+
+test "cstr" {
+ try testFmt(
+ "cstr: Test C\n",
+ "cstr: {s}\n",
+ .{@ptrCast([*c]const u8, "Test C")},
+ );
+ try testFmt(
+ "cstr: Test C \n",
+ "cstr: {s:10}\n",
+ .{@ptrCast([*c]const u8, "Test C")},
+ );
+}
+
+test "filesize" {
+ try testFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
+ try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
+}
+
+test "struct" {
+ {
+ const Struct = struct {
+ field: u8,
+ };
+ const value = Struct{ .field = 42 };
+ try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{value});
+ try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
+ }
+ {
+ const Struct = struct {
+ a: u0,
+ b: u1,
+ };
+ const value = Struct{ .a = 0, .b = 1 };
+ try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
+ }
+}
+
+test "enum" {
+ const Enum = enum {
+ One,
+ Two,
+ };
+ const value = Enum.Two;
+ try testFmt("enum: Enum.Two\n", "enum: {}\n", .{value});
+ try testFmt("enum: Enum.Two\n", "enum: {}\n", .{&value});
+}
+
+test "non-exhaustive enum" {
+ const Enum = enum(u16) {
+ One = 0x000f,
+ Two = 0xbeef,
+ _,
+ };
+ try testFmt("enum: Enum(15)\n", "enum: {}\n", .{Enum.One});
+ try testFmt("enum: Enum(48879)\n", "enum: {}\n", .{Enum.Two});
+ try testFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
+ try testFmt("enum: Enum(f)\n", "enum: {x}\n", .{Enum.One});
+ try testFmt("enum: Enum(beef)\n", "enum: {x}\n", .{Enum.Two});
+ try testFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
+}
+
+test "float.scientific" {
+ try testFmt("f32: 1.34000003e+00", "f32: {e}", .{@as(f32, 1.34)});
+ try testFmt("f32: 1.23400001e+01", "f32: {e}", .{@as(f32, 12.34)});
+ try testFmt("f64: -1.234e+11", "f64: {e}", .{@as(f64, -12.34e10)});
+ try testFmt("f64: 9.99996e-40", "f64: {e}", .{@as(f64, 9.999960e-40)});
+}
+
+test "float.scientific.precision" {
+ try testFmt("f64: 1.40971e-42", "f64: {e:.5}", .{@as(f64, 1.409706e-42)});
+ try testFmt("f64: 1.00000e-09", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 814313563)))});
+ try testFmt("f64: 7.81250e-03", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1006632960)))});
+ // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
+ // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
+ try testFmt("f64: 1.00001e+05", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1203982400)))});
+}
+
+test "float.special" {
+ try testFmt("f64: nan", "f64: {}", .{math.nan_f64});
+ // negative nan is not defined by IEE 754,
+ // and ARM thus normalizes it to positive nan
+ if (builtin.arch != builtin.Arch.arm) {
+ try testFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
+ }
+ try testFmt("f64: inf", "f64: {}", .{math.inf_f64});
+ try testFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
+}
+
+test "float.decimal" {
+ try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
+ try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
+ try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)});
+ try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)});
+ // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
+ // -11.12339... is rounded back up to -11.1234
+ try testFmt("f32: -11.1234", "f32: {d:.4}", .{@as(f32, -11.1234)});
+ try testFmt("f32: 91.12345", "f32: {d:.5}", .{@as(f32, 91.12345)});
+ try testFmt("f64: 91.1234567890", "f64: {d:.10}", .{@as(f64, 91.12345678901235)});
+ try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 0.0)});
+ try testFmt("f64: 6", "f64: {d:.0}", .{@as(f64, 5.700)});
+ try testFmt("f64: 10.0", "f64: {d:.1}", .{@as(f64, 9.999)});
+ try testFmt("f64: 1.000", "f64: {d:.3}", .{@as(f64, 1.0)});
+ try testFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)});
+ try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
+ try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
+}
+
+test "float.libc.sanity" {
+ try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 916964781)))});
+ try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 925353389)))});
+ try testFmt("f64: 0.10000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1036831278)))});
+ try testFmt("f64: 1.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1065353133)))});
+ try testFmt("f64: 10.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1092616192)))});
+
+ // libc differences
+ //
+ // This is 0.015625 exactly according to gdb. We thus round down,
+ // however glibc rounds up for some reason. This occurs for all
+ // floats of the form x.yyyy25 on a precision point.
+ try testFmt("f64: 0.01563", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1015021568)))});
+ // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
+ // also rounds to 630 so I'm inclined to believe libc is not
+ // optimal here.
+ try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1518338049)))});
+}
+
+test "custom" {
+ const Vec2 = struct {
+ const SelfType = @This();
+ x: f32,
+ y: f32,
+
+ pub fn format(
+ self: SelfType,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ ) Errors!void {
+ if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
+ return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });
+ } else if (comptime std.mem.eql(u8, fmt, "d")) {
+ return std.fmt.format(context, Errors, output, "{d:.3}x{d:.3}", .{ self.x, self.y });
+ } else {
+ @compileError("Unknown format character: '" ++ fmt ++ "'");
+ }
+ }
+ };
+
+ var buf1: [32]u8 = undefined;
+ var value = Vec2{
+ .x = 10.2,
+ .y = 2.22,
+ };
+ try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
+ try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
+
+ // same thing but not passing a pointer
+ try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
+ try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
+}
+
+test "struct" {
+ const S = struct {
+ a: u32,
+ b: anyerror,
+ };
+
+ const inst = S{
+ .a = 456,
+ .b = error.Unused,
+ };
+
+ try testFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
+}
+
+test "union" {
+ const TU = union(enum) {
+ float: f32,
+ int: u32,
+ };
+
+ const UU = union {
+ float: f32,
+ int: u32,
+ };
+
+ const EU = extern union {
+ float: f32,
+ int: u32,
+ };
+
+ const tu_inst = TU{ .int = 123 };
+ const uu_inst = UU{ .int = 456 };
+ const eu_inst = EU{ .float = 321.123 };
+
+ try testFmt("TU{ .int = 123 }", "{}", .{tu_inst});
+
+ var buf: [100]u8 = undefined;
+ const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
+ std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
+
+ const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
+ std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
+}
+
+test "enum" {
+ const E = enum {
+ One,
+ Two,
+ Three,
+ };
+
+ const inst = E.Two;
+
+ try testFmt("E.Two", "{}", .{inst});
+}
+
+test "struct.self-referential" {
+ const S = struct {
+ const SelfType = @This();
+ a: ?*SelfType,
+ };
+
+ var inst = S{
+ .a = null,
+ };
+ inst.a = &inst;
+
+ try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
+}
+
+test "struct.zero-size" {
+ const A = struct {
+ fn foo() void {}
+ };
+ const B = struct {
+ a: A,
+ c: i32,
+ };
+
+ const a = A{};
+ const b = B{ .a = a, .c = 0 };
+
+ try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
+}
+
+test "bytes.hex" {
+ const some_bytes = "\xCA\xFE\xBA\xBE";
+ try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
+ try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
+ //Test Slices
+ try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
+ try testFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
+ const bytes_with_zeros = "\x00\x0E\xBA\xBE";
+ try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
+}
+
+fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void {
+ var buf: [100]u8 = undefined;
+ const result = try bufPrint(buf[0..], template, args);
+ if (mem.eql(u8, result, expected)) return;
+
+ std.debug.warn("\n====== expected this output: =========\n", .{});
+ std.debug.warn("{}", .{expected});
+ std.debug.warn("\n======== instead found this: =========\n", .{});
+ std.debug.warn("{}", .{result});
+ std.debug.warn("\n======================================\n", .{});
+ return error.TestFailed;
+}
+
+pub fn trim(buf: []const u8) []const u8 {
+ var start: usize = 0;
+ while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
+
+ var end: usize = buf.len;
+ while (true) {
+ if (end > start) {
+ const new_end = end - 1;
+ if (isWhiteSpace(buf[new_end])) {
+ end = new_end;
+ continue;
+ }
+ }
+ break;
+ }
+ return buf[start..end];
+}
+
+test "trim" {
+ std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
+ std.testing.expect(mem.eql(u8, "", trim(" ")));
+ std.testing.expect(mem.eql(u8, "", trim("")));
+ std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
+ std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
+}
+
+pub fn isWhiteSpace(byte: u8) bool {
+ return switch (byte) {
+ ' ', '\t', '\n', '\r' => true,
+ else => false,
+ };
+}
+
+pub fn hexToBytes(out: []u8, input: []const u8) !void {
+ if (out.len * 2 < input.len)
+ return error.InvalidLength;
+
+ var in_i: usize = 0;
+ while (in_i != input.len) : (in_i += 2) {
+ const hi = try charToDigit(input[in_i], 16);
+ const lo = try charToDigit(input[in_i + 1], 16);
+ out[in_i / 2] = (hi << 4) | lo;
+ }
+}
+
+test "hexToBytes" {
+ const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
+ var pb: [32]u8 = undefined;
+ try hexToBytes(pb[0..], test_hex_str);
+ try testFmt(test_hex_str, "{X}", .{pb});
+}
+
+test "formatIntValue with comptime_int" {
+ const value: comptime_int = 123456789123456789;
+
+ var buf = std.ArrayList(u8).init(std.testing.allocator);
+ defer buf.deinit();
+ try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
+ std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
+}
+
+test "formatType max_depth" {
+ const Vec2 = struct {
+ const SelfType = @This();
+ x: f32,
+ y: f32,
+
+ pub fn format(
+ self: SelfType,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ context: var,
+ comptime Errors: type,
+ comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ ) Errors!void {
+ if (fmt.len == 0) {
+ return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });
+ } else {
+ @compileError("Unknown format string: '" ++ fmt ++ "'");
+ }
+ }
+ };
+ const E = enum {
+ One,
+ Two,
+ Three,
+ };
+ const TU = union(enum) {
+ const SelfType = @This();
+ float: f32,
+ int: u32,
+ ptr: ?*SelfType,
+ };
+ const S = struct {
+ const SelfType = @This();
+ a: ?*SelfType,
+ tu: TU,
+ e: E,
+ vec: Vec2,
+ };
+
+ var inst = S{
+ .a = null,
+ .tu = TU{ .ptr = null },
+ .e = E.Two,
+ .vec = Vec2{ .x = 10.2, .y = 2.22 },
+ };
+ inst.a = &inst;
+ inst.tu.ptr = &inst.tu;
+
+ var buf0 = std.ArrayList(u8).init(std.testing.allocator);
+ defer buf0.deinit();
+ try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
+ std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
+
+ var buf1 = std.ArrayList(u8).init(std.testing.allocator);
+ defer buf1.deinit();
+ try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
+ std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
+
+ var buf2 = std.ArrayList(u8).init(std.testing.allocator);
+ defer buf2.deinit();
+ try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
+ std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
+
+ var buf3 = std.ArrayList(u8).init(std.testing.allocator);
+ defer buf3.deinit();
+ try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
+ std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
+}
+
+test "positional" {
+ try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
+ try testFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
+ try testFmt("0 0", "{0} {0}", .{@as(usize, 0)});
+ try testFmt("0 1", "{} {1}", .{ @as(usize, 0), @as(usize, 1) });
+ try testFmt("1 0 0 1", "{1} {} {0} {}", .{ @as(usize, 0), @as(usize, 1) });
+}
+
+test "positional with specifier" {
+ try testFmt("10.0", "{0d:.1}", .{@as(f64, 9.999)});
+}
+
+test "positional/alignment/width/precision" {
+ try testFmt("10.0", "{0d: >3.1}", .{@as(f64, 9.999)});
+}
+
+test "vector" {
+ // https://github.com/ziglang/zig/issues/3317
+ if (builtin.arch == .mipsel) return error.SkipZigTest;
+
+ const vbool: @Vector(4, bool) = [_]bool{ true, false, true, false };
+ const vi64: @Vector(4, i64) = [_]i64{ -2, -1, 0, 1 };
+ const vu64: @Vector(4, u64) = [_]u64{ 1000, 2000, 3000, 4000 };
+
+ try testFmt("{ true, false, true, false }", "{}", .{vbool});
+ try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
+ try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
+ try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
+ try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
+ try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
+ try testFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
+}
+
+test "enum-literal" {
+ try testFmt(".hello_world", "{}", .{.hello_world});
+}
diff --git a/lib/std/std.zig b/lib/std/std.zig
index 9277370ca..b7fe709c7 100644
--- a/lib/std/std.zig
+++ b/lib/std/std.zig
@@ -38,6 +38,7 @@ pub const elf = @import("elf.zig");
pub const event = @import("event.zig");
pub const fifo = @import("fifo.zig");
pub const fmt = @import("fmt.zig");
+pub const fmtstream = @import("fmtstream.zig");
pub const fs = @import("fs.zig");
pub const hash = @import("hash.zig");
pub const hash_map = @import("hash_map.zig");
From 278b9ec1aaabb8bcfbbf9c964012dc5bd2ad154a Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 11:59:37 -0600
Subject: [PATCH 074/111] Blind translation
---
lib/std/fmtstream.zig | 376 +++++++++++++++++++-----------------------
1 file changed, 170 insertions(+), 206 deletions(-)
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index a7525ba79..bb8d52d74 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -69,19 +69,17 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
///
/// If a formatted user type contains a function of the type
/// ```
-/// fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, context: var, comptime Errors: type, comptime output: fn (@TypeOf(context), []const u8) Errors!void) Errors!void
+/// fn format(value: ?, comptime fmt: []const u8, options: std.fmtstream.FormatOptions, out_stream: var) !void
/// ```
/// with `?` being the type formatted, this function will be called instead of the default implementation.
/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
///
/// A user type may be a `struct`, `vector`, `union` or `enum` type.
pub fn format(
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ out_stream: var,
comptime fmt: []const u8,
args: var,
-) Errors!void {
+) !void {
const ArgSetType = u32;
if (@typeInfo(@TypeOf(args)) != .Struct) {
@compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
@@ -138,7 +136,7 @@ pub fn format(
.Start => switch (c) {
'{' => {
if (start_index < i) {
- try output(context, fmt[start_index..i]);
+ try out_stream.writeAll(fmt[start_index..i]);
}
start_index = i;
@@ -150,7 +148,7 @@ pub fn format(
},
'}' => {
if (start_index < i) {
- try output(context, fmt[start_index..i]);
+ try out_stream.writeAll(fmt[start_index..i]);
}
state = .CloseBrace;
},
@@ -185,9 +183,7 @@ pub fn format(
args[arg_to_print],
fmt[0..0],
options,
- context,
- Errors,
- output,
+ out_stream,
default_max_depth,
);
@@ -218,9 +214,7 @@ pub fn format(
args[arg_to_print],
fmt[specifier_start..i],
options,
- context,
- Errors,
- output,
+ out_stream,
default_max_depth,
);
state = .Start;
@@ -265,9 +259,7 @@ pub fn format(
args[arg_to_print],
fmt[specifier_start..specifier_end],
options,
- context,
- Errors,
- output,
+ out_stream,
default_max_depth,
);
state = .Start;
@@ -293,9 +285,7 @@ pub fn format(
args[arg_to_print],
fmt[specifier_start..specifier_end],
options,
- context,
- Errors,
- output,
+ out_stream,
default_max_depth,
);
state = .Start;
@@ -316,7 +306,7 @@ pub fn format(
}
}
if (start_index < fmt.len) {
- try output(context, fmt[start_index..]);
+ try out_stream.writeAll(fmt[start_index..]);
}
}
@@ -324,121 +314,119 @@ pub fn formatType(
value: var,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ out_stream: var,
max_depth: usize,
-) Errors!void {
+) !void {
if (comptime std.mem.eql(u8, fmt, "*")) {
- try output(context, @typeName(@TypeOf(value).Child));
- try output(context, "@");
- try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, context, Errors, output);
+ try out_stream.writeAll(@typeName(@TypeOf(value).Child));
+ try out_stream.writeAll("@");
+ try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, out_stream);
return;
}
const T = @TypeOf(value);
switch (@typeInfo(T)) {
.ComptimeInt, .Int, .Float => {
- return formatValue(value, fmt, options, context, Errors, output);
+ return formatValue(value, fmt, options, out_stream);
},
.Void => {
- return output(context, "void");
+ return out_stream.writeAll("void");
},
.Bool => {
- return output(context, if (value) "true" else "false");
+ return out_stream.writeAll(if (value) "true" else "false");
},
.Optional => {
if (value) |payload| {
- return formatType(payload, fmt, options, context, Errors, output, max_depth);
+ return formatType(payload, fmt, options, out_stream, max_depth);
} else {
- return output(context, "null");
+ return out_stream.writeAll("null");
}
},
.ErrorUnion => {
if (value) |payload| {
- return formatType(payload, fmt, options, context, Errors, output, max_depth);
+ return formatType(payload, fmt, options, out_stream, max_depth);
} else |err| {
- return formatType(err, fmt, options, context, Errors, output, max_depth);
+ return formatType(err, fmt, options, out_stream, max_depth);
}
},
.ErrorSet => {
- try output(context, "error.");
- return output(context, @errorName(value));
+ try out_stream.writeAll("error.");
+ return out_stream.writeAll(@errorName(value));
},
.Enum => |enumInfo| {
if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, context, Errors, output);
+ return value.format(fmt, options, out_stream);
}
- try output(context, @typeName(T));
+ try out_stream.writeAll(@typeName(T));
if (enumInfo.is_exhaustive) {
- try output(context, ".");
- try output(context, @tagName(value));
+ try out_stream.writeAll(".");
+ try out_stream.writeAll(@tagName(value));
} else {
// TODO: when @tagName works on exhaustive enums print known enum strings
- try output(context, "(");
- try formatType(@enumToInt(value), fmt, options, context, Errors, output, max_depth);
- try output(context, ")");
+ try out_stream.writeAll("(");
+ try formatType(@enumToInt(value), fmt, options, out_stream, max_depth);
+ try out_stream.writeAll(")");
}
},
.Union => {
if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, context, Errors, output);
+ return value.format(fmt, options, out_stream);
}
- try output(context, @typeName(T));
+ try out_stream.writeAll(@typeName(T));
if (max_depth == 0) {
- return output(context, "{ ... }");
+ return out_stream.writeAll("{ ... }");
}
const info = @typeInfo(T).Union;
if (info.tag_type) |UnionTagType| {
- try output(context, "{ .");
- try output(context, @tagName(@as(UnionTagType, value)));
- try output(context, " = ");
+ try out_stream.writeAll("{ .");
+ try out_stream.writeAll(@tagName(@as(UnionTagType, value)));
+ try out_stream.writeAll(" = ");
inline for (info.fields) |u_field| {
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
- try formatType(@field(value, u_field.name), fmt, options, context, Errors, output, max_depth - 1);
+ try formatType(@field(value, u_field.name), fmt, options, out_stream, max_depth - 1);
}
}
- try output(context, " }");
+ try out_stream.writeAll(" }");
} else {
- try format(context, Errors, output, "@{x}", .{@ptrToInt(&value)});
+ try format(out_stream, "@{x}", .{@ptrToInt(&value)});
}
},
.Struct => |StructT| {
if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, context, Errors, output);
+ return value.format(fmt, options, out_stream);
}
- try output(context, @typeName(T));
+ try out_stream.writeAll(@typeName(T));
if (max_depth == 0) {
- return output(context, "{ ... }");
+ return out_stream.writeAll("{ ... }");
}
- try output(context, "{");
+ try out_stream.writeAll("{");
inline for (StructT.fields) |f, i| {
if (i == 0) {
- try output(context, " .");
+ try out_stream.writeAll(" .");
} else {
- try output(context, ", .");
+ try out_stream.writeAll(", .");
}
- try output(context, f.name);
- try output(context, " = ");
- try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);
+ try out_stream.writeAll(f.name);
+ try out_stream.writeAll(" = ");
+ try formatType(@field(value, f.name), fmt, options, out_stream, max_depth - 1);
}
- try output(context, " }");
+ try out_stream.writeAll(" }");
},
.Pointer => |ptr_info| switch (ptr_info.size) {
.One => switch (@typeInfo(ptr_info.child)) {
.Array => |info| {
if (info.child == u8) {
- return formatText(value, fmt, options, context, Errors, output);
+ return formatText(value, fmt, options, out_stream);
}
- return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
+ return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
},
.Enum, .Union, .Struct => {
- return formatType(value.*, fmt, options, context, Errors, output, max_depth);
+ return formatType(value.*, fmt, options, out_stream, max_depth);
},
- else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
+ else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
},
.Many, .C => {
if (ptr_info.sentinel) |sentinel| {
@@ -446,19 +434,19 @@ pub fn formatType(
}
if (ptr_info.child == u8) {
if (fmt.len > 0 and fmt[0] == 's') {
- return formatText(mem.span(value), fmt, options, context, Errors, output);
+ return formatText(mem.span(value), fmt, options, out_stream);
}
}
- return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
+ return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
},
.Slice => {
if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
- return formatText(value, fmt, options, context, Errors, output);
+ return formatText(value, fmt, options, out_stream);
}
if (ptr_info.child == u8) {
- return formatText(value, fmt, options, context, Errors, output);
+ return formatText(value, fmt, options, out_stream);
}
- return format(context, Errors, output, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
+ return format(out_stream, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
},
},
.Array => |info| {
@@ -473,24 +461,24 @@ pub fn formatType(
.sentinel = null,
},
});
- return formatType(@as(Slice, &value), fmt, options, context, Errors, output, max_depth);
+ return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth);
},
.Vector => {
const len = @typeInfo(T).Vector.len;
- try output(context, "{ ");
+ try out_stream.writeAll("{ ");
var i: usize = 0;
while (i < len) : (i += 1) {
- try formatValue(value[i], fmt, options, context, Errors, output);
+ try formatValue(value[i], fmt, options, out_stream);
if (i < len - 1) {
- try output(context, ", ");
+ try out_stream.writeAll(", ");
}
}
- try output(context, " }");
+ try out_stream.writeAll(" }");
},
.Fn => {
- return format(context, Errors, output, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
+ return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
},
- .Type => return output(context, @typeName(T)),
+ .Type => return out_stream.writeAll(@typeName(T)),
.EnumLiteral => {
const buffer = [_]u8{'.'} ++ @tagName(value);
return formatType(buffer, fmt, options, context, Errors, output, max_depth);
@@ -503,21 +491,19 @@ fn formatValue(
value: var,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
if (comptime std.mem.eql(u8, fmt, "B")) {
- return formatBytes(value, options, 1000, context, Errors, output);
+ return formatBytes(value, options, 1000, out_stream);
} else if (comptime std.mem.eql(u8, fmt, "Bi")) {
- return formatBytes(value, options, 1024, context, Errors, output);
+ return formatBytes(value, options, 1024, out_stream);
}
const T = @TypeOf(value);
switch (@typeInfo(T)) {
- .Float => return formatFloatValue(value, fmt, options, context, Errors, output),
- .Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output),
- .Bool => return output(context, if (value) "true" else "false"),
+ .Float => return formatFloatValue(value, fmt, options, out_stream),
+ .Int, .ComptimeInt => return formatIntValue(value, fmt, options, out_stream),
+ .Bool => return out_stream.writeAll(if (value) "true" else "false"),
else => comptime unreachable,
}
}
@@ -526,10 +512,8 @@ pub fn formatIntValue(
value: var,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
comptime var radix = 10;
comptime var uppercase = false;
@@ -544,7 +528,7 @@ pub fn formatIntValue(
uppercase = false;
} else if (comptime std.mem.eql(u8, fmt, "c")) {
if (@TypeOf(int_value).bit_count <= 8) {
- return formatAsciiChar(@as(u8, int_value), options, context, Errors, output);
+ return formatAsciiChar(@as(u8, int_value), options, out_stream);
} else {
@compileError("Cannot print integer that is larger than 8 bits as a ascii");
}
@@ -561,21 +545,19 @@ pub fn formatIntValue(
@compileError("Unknown format string: '" ++ fmt ++ "'");
}
- return formatInt(int_value, radix, uppercase, options, context, Errors, output);
+ return formatInt(int_value, radix, uppercase, options, out_stream);
}
fn formatFloatValue(
value: var,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
- return formatFloatScientific(value, options, context, Errors, output);
+ return formatFloatScientific(value, options, out_stream);
} else if (comptime std.mem.eql(u8, fmt, "d")) {
- return formatFloatDecimal(value, options, context, Errors, output);
+ return formatFloatDecimal(value, options, out_stream);
} else {
@compileError("Unknown format string: '" ++ fmt ++ "'");
}
@@ -585,17 +567,15 @@ pub fn formatText(
bytes: []const u8,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
if (fmt.len == 0) {
- return output(context, bytes);
+ return out_stream.writeAll(bytes);
} else if (comptime std.mem.eql(u8, fmt, "s")) {
- return formatBuf(bytes, options, context, Errors, output);
+ return formatBuf(bytes, options, out_stream);
} else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
for (bytes) |c| {
- try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, context, Errors, output);
+ try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, out_stream);
}
return;
} else {
@@ -606,27 +586,23 @@ pub fn formatText(
pub fn formatAsciiChar(
c: u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
- return output(context, @as(*const [1]u8, &c)[0..]);
+ out_stream: var,
+) !void {
+ return out_stream.writeAll(@as(*const [1]u8, &c)[0..]);
}
pub fn formatBuf(
buf: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
- try output(context, buf);
+ out_stream: var,
+) !void {
+ try out_stream.writeAll(buf);
const width = options.width orelse 0;
var leftover_padding = if (width > buf.len) (width - buf.len) else return;
const pad_byte: u8 = options.fill;
while (leftover_padding > 0) : (leftover_padding -= 1) {
- try output(context, @as(*const [1]u8, &pad_byte)[0..1]);
+ try out_stream.writeAll(@as(*const [1]u8, &pad_byte)[0..1]);
}
}
@@ -636,40 +612,38 @@ pub fn formatBuf(
pub fn formatFloatScientific(
value: var,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
var x = @floatCast(f64, value);
// Errol doesn't handle these special cases.
if (math.signbit(x)) {
- try output(context, "-");
+ try out_stream.writeAll("-");
x = -x;
}
if (math.isNan(x)) {
- return output(context, "nan");
+ return out_stream.writeAll("nan");
}
if (math.isPositiveInf(x)) {
- return output(context, "inf");
+ return out_stream.writeAll("inf");
}
if (x == 0.0) {
- try output(context, "0");
+ try out_stream.writeAll("0");
if (options.precision) |precision| {
if (precision != 0) {
- try output(context, ".");
+ try out_stream.writeAll(".");
var i: usize = 0;
while (i < precision) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
} else {
- try output(context, ".0");
+ try out_stream.writeAll(".0");
}
- try output(context, "e+00");
+ try out_stream.writeAll("e+00");
return;
}
@@ -679,50 +653,50 @@ pub fn formatFloatScientific(
if (options.precision) |precision| {
errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
- try output(context, float_decimal.digits[0..1]);
+ try out_stream.writeAll(float_decimal.digits[0..1]);
// {e0} case prints no `.`
if (precision != 0) {
- try output(context, ".");
+ try out_stream.writeAll(".");
var printed: usize = 0;
if (float_decimal.digits.len > 1) {
const num_digits = math.min(float_decimal.digits.len, precision + 1);
- try output(context, float_decimal.digits[1..num_digits]);
+ try out_stream.writeAll(float_decimal.digits[1..num_digits]);
printed += num_digits - 1;
}
while (printed < precision) : (printed += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
} else {
- try output(context, float_decimal.digits[0..1]);
- try output(context, ".");
+ try out_stream.writeAll(float_decimal.digits[0..1]);
+ try out_stream.writeAll(".");
if (float_decimal.digits.len > 1) {
const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;
- try output(context, float_decimal.digits[1..num_digits]);
+ try out_stream.writeAll(float_decimal.digits[1..num_digits]);
} else {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
- try output(context, "e");
+ try out_stream.writeAll("e");
const exp = float_decimal.exp - 1;
if (exp >= 0) {
- try output(context, "+");
+ try out_stream.writeAll("+");
if (exp > -10 and exp < 10) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
- try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
+ try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
} else {
- try output(context, "-");
+ try out_stream.writeAll("-");
if (exp > -10 and exp < 10) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
- try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
+ try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
}
}
@@ -731,36 +705,34 @@ pub fn formatFloatScientific(
pub fn formatFloatDecimal(
value: var,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
var x = @as(f64, value);
// Errol doesn't handle these special cases.
if (math.signbit(x)) {
- try output(context, "-");
+ try out_stream.writeAll("-");
x = -x;
}
if (math.isNan(x)) {
- return output(context, "nan");
+ return out_stream.writeAll("nan");
}
if (math.isPositiveInf(x)) {
- return output(context, "inf");
+ return out_stream.writeAll("inf");
}
if (x == 0.0) {
- try output(context, "0");
+ try out_stream.writeAll("0");
if (options.precision) |precision| {
if (precision != 0) {
- try output(context, ".");
+ try out_stream.writeAll(".");
var i: usize = 0;
while (i < precision) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
} else {
- try output(context, ".0");
+ try out_stream.writeAll(".0");
}
}
@@ -782,14 +754,14 @@ pub fn formatFloatDecimal(
if (num_digits_whole > 0) {
// We may have to zero pad, for instance 1e4 requires zero padding.
- try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
+ try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
var i = num_digits_whole_no_pad;
while (i < num_digits_whole) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
} else {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
// {.0} special case doesn't want a trailing '.'
@@ -797,7 +769,7 @@ pub fn formatFloatDecimal(
return;
}
- try output(context, ".");
+ try out_stream.writeAll(".");
// Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
var printed: usize = 0;
@@ -809,7 +781,7 @@ pub fn formatFloatDecimal(
var i: usize = 0;
while (i < zeros_to_print) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
printed += 1;
}
@@ -821,14 +793,14 @@ pub fn formatFloatDecimal(
// Remaining fractional portion, zero-padding if insufficient.
assert(precision >= printed);
if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
- try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
+ try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
return;
} else {
- try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
+ try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
printed += float_decimal.digits.len - num_digits_whole_no_pad;
while (printed < precision) : (printed += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
} else {
@@ -840,14 +812,14 @@ pub fn formatFloatDecimal(
if (num_digits_whole > 0) {
// We may have to zero pad, for instance 1e4 requires zero padding.
- try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
+ try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
var i = num_digits_whole_no_pad;
while (i < num_digits_whole) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
} else {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
// Omit `.` if no fractional portion
@@ -855,7 +827,7 @@ pub fn formatFloatDecimal(
return;
}
- try output(context, ".");
+ try out_stream.writeAll(".");
// Zero-fill until we reach significant digits or run out of precision.
if (float_decimal.exp < 0) {
@@ -863,11 +835,11 @@ pub fn formatFloatDecimal(
var i: usize = 0;
while (i < zero_digit_count) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
- try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
+ try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
}
}
@@ -875,12 +847,10 @@ pub fn formatBytes(
value: var,
options: FormatOptions,
comptime radix: usize,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
if (value == 0) {
- return output(context, "0B");
+ return out_stream.writeAll("0B");
}
const mags_si = " kMGTPEZY";
@@ -897,10 +867,10 @@ pub fn formatBytes(
else => unreachable,
};
- try formatFloatDecimal(new_value, options, context, Errors, output);
+ try formatFloatDecimal(new_value, options, out_stream);
if (suffix == ' ') {
- return output(context, "B");
+ return out_stream.writeAll("B");
}
const buf = switch (radix) {
@@ -908,7 +878,7 @@ pub fn formatBytes(
1024 => &[_]u8{ suffix, 'i', 'B' },
else => unreachable,
};
- return output(context, buf);
+ return out_stream.writeAll(buf);
}
pub fn formatInt(
@@ -916,10 +886,8 @@ pub fn formatInt(
base: u8,
uppercase: bool,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
const int_value = if (@TypeOf(value) == comptime_int) blk: {
const Int = math.IntFittingRange(value, value);
break :blk @as(Int, value);
@@ -927,9 +895,9 @@ pub fn formatInt(
value;
if (@TypeOf(int_value).is_signed) {
- return formatIntSigned(int_value, base, uppercase, options, context, Errors, output);
+ return formatIntSigned(int_value, base, uppercase, options, out_stream);
} else {
- return formatIntUnsigned(int_value, base, uppercase, options, context, Errors, output);
+ return formatIntUnsigned(int_value, base, uppercase, options, out_stream);
}
}
@@ -938,10 +906,8 @@ fn formatIntSigned(
base: u8,
uppercase: bool,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
const new_options = FormatOptions{
.width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
.precision = options.precision,
@@ -950,15 +916,15 @@ fn formatIntSigned(
const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
const Uint = std.meta.IntType(false, bit_count);
if (value < 0) {
- try output(context, "-");
+ try out_stream.writeAll("-");
const new_value = math.absCast(value);
- return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
+ return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
} else if (options.width == null or options.width.? == 0) {
- return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, context, Errors, output);
+ return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, out_stream);
} else {
- try output(context, "+");
+ try out_stream.writeAll("+");
const new_value = @intCast(Uint, value);
- return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
+ return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
}
}
@@ -967,10 +933,8 @@ fn formatIntUnsigned(
base: u8,
uppercase: bool,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
assert(base >= 2);
var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count);
@@ -994,16 +958,16 @@ fn formatIntUnsigned(
const zero_byte: u8 = options.fill;
var leftover_padding = padding - index;
while (true) {
- try output(context, @as(*const [1]u8, &zero_byte)[0..]);
+ try out_stream.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
leftover_padding -= 1;
if (leftover_padding == 0) break;
}
mem.set(u8, buf[0..index], options.fill);
- return output(context, &buf);
+ return out_stream.writeAll(&buf);
} else {
const padded_buf = buf[index - padding ..];
mem.set(u8, padded_buf[0..padding], options.fill);
- return output(context, padded_buf);
+ return out_stream.writeAll(padded_buf);
}
}
@@ -1451,12 +1415,12 @@ test "custom" {
options: FormatOptions,
context: var,
comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
- ) Errors!void {
+ comptime output: fn (@TypeOf(context), []const u8) !void,
+ ) !void {
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
- return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });
+ return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
} else if (comptime std.mem.eql(u8, fmt, "d")) {
- return std.fmt.format(context, Errors, output, "{d:.3}x{d:.3}", .{ self.x, self.y });
+ return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
} else {
@compileError("Unknown format character: '" ++ fmt ++ "'");
}
@@ -1658,10 +1622,10 @@ test "formatType max_depth" {
options: FormatOptions,
context: var,
comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
- ) Errors!void {
+ comptime output: fn (@TypeOf(context), []const u8) !void,
+ ) !void {
if (fmt.len == 0) {
- return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });
+ return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
} else {
@compileError("Unknown format string: '" ++ fmt ++ "'");
}
From e1e9ff9546d0898764ff9c9383e57d0fa4e9bd0e Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 12:02:33 -0600
Subject: [PATCH 075/111] Get formatIntBuf working
---
lib/std/fmtstream.zig | 1215 ++++++++++++++++++++---------------------
1 file changed, 602 insertions(+), 613 deletions(-)
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index bb8d52d74..d64c6cdf7 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -972,20 +972,9 @@ fn formatIntUnsigned(
}
pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
- var context = FormatIntBuf{
- .out_buf = out_buf,
- .index = 0,
- };
- formatInt(value, base, uppercase, options, &context, error{}, formatIntCallback) catch unreachable;
- return context.index;
-}
-const FormatIntBuf = struct {
- out_buf: []u8,
- index: usize,
-};
-fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
- mem.copy(u8, context.out_buf[context.index..], bytes);
- context.index += bytes.len;
+ var fbs = std.io.fixedBufferStream(out_buf);
+ formatInt(value, base, uppercase, options, fbs.outStream()) catch unreachable;
+ return fbs.pos;
}
pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
@@ -1085,48 +1074,48 @@ fn digitToChar(digit: u8, uppercase: bool) u8 {
};
}
-const BufPrintContext = struct {
- remaining: []u8,
-};
+// const BufPrintContext = struct {
+// remaining: []u8,
+// };
-fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
- if (context.remaining.len < bytes.len) {
- mem.copy(u8, context.remaining, bytes[0..context.remaining.len]);
- return error.BufferTooSmall;
- }
- mem.copy(u8, context.remaining, bytes);
- context.remaining = context.remaining[bytes.len..];
-}
+// fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
+// if (context.remaining.len < bytes.len) {
+// mem.copy(u8, context.remaining, bytes[0..context.remaining.len]);
+// return error.BufferTooSmall;
+// }
+// mem.copy(u8, context.remaining, bytes);
+// context.remaining = context.remaining[bytes.len..];
+// }
-pub const BufPrintError = error{
- /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
- BufferTooSmall,
-};
-pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
- var context = BufPrintContext{ .remaining = buf };
- try format(&context, BufPrintError, bufPrintWrite, fmt, args);
- return buf[0 .. buf.len - context.remaining.len];
-}
+// pub const BufPrintError = error{
+// /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
+// BufferTooSmall,
+// };
+// pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
+// var context = BufPrintContext{ .remaining = buf };
+// try format(&context, BufPrintError, bufPrintWrite, fmt, args);
+// return buf[0 .. buf.len - context.remaining.len];
+// }
-pub const AllocPrintError = error{OutOfMemory};
+// pub const AllocPrintError = error{OutOfMemory};
-pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
- var size: usize = 0;
- format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
- const buf = try allocator.alloc(u8, size);
- return bufPrint(buf, fmt, args) catch |err| switch (err) {
- error.BufferTooSmall => unreachable, // we just counted the size above
- };
-}
+// pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
+// var size: usize = 0;
+// format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
+// const buf = try allocator.alloc(u8, size);
+// return bufPrint(buf, fmt, args) catch |err| switch (err) {
+// error.BufferTooSmall => unreachable, // we just counted the size above
+// };
+// }
-fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
- size.* += bytes.len;
-}
+// fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
+// size.* += bytes.len;
+// }
-pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
- const result = try allocPrint(allocator, fmt ++ "\x00", args);
- return result[0 .. result.len - 1 :0];
-}
+// pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
+// const result = try allocPrint(allocator, fmt ++ "\x00", args);
+// return result[0 .. result.len - 1 :0];
+// }
test "bufPrintInt" {
var buffer: [100]u8 = undefined;
@@ -1153,566 +1142,566 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options:
return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
}
-test "parse u64 digit too big" {
- _ = parseUnsigned(u64, "123a", 10) catch |err| {
- if (err == error.InvalidCharacter) return;
- unreachable;
- };
- unreachable;
-}
-
-test "parse unsigned comptime" {
- comptime {
- std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
- }
-}
-
-test "optional" {
- {
- const value: ?i32 = 1234;
- try testFmt("optional: 1234\n", "optional: {}\n", .{value});
- }
- {
- const value: ?i32 = null;
- try testFmt("optional: null\n", "optional: {}\n", .{value});
- }
-}
-
-test "error" {
- {
- const value: anyerror!i32 = 1234;
- try testFmt("error union: 1234\n", "error union: {}\n", .{value});
- }
- {
- const value: anyerror!i32 = error.InvalidChar;
- try testFmt("error union: error.InvalidChar\n", "error union: {}\n", .{value});
- }
-}
-
-test "int.small" {
- {
- const value: u3 = 0b101;
- try testFmt("u3: 5\n", "u3: {}\n", .{value});
- }
-}
-
-test "int.specifier" {
- {
- const value: u8 = 'a';
- try testFmt("u8: a\n", "u8: {c}\n", .{value});
- }
- {
- const value: u8 = 0b1100;
- try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", .{value});
- }
-}
-
-test "int.padded" {
- try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
- try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
-}
-
-test "buffer" {
- {
- var buf1: [32]u8 = undefined;
- var context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
- var res = buf1[0 .. buf1.len - context.remaining.len];
- std.testing.expect(mem.eql(u8, res, "1234"));
-
- context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
- res = buf1[0 .. buf1.len - context.remaining.len];
- std.testing.expect(mem.eql(u8, res, "a"));
-
- context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
- res = buf1[0 .. buf1.len - context.remaining.len];
- std.testing.expect(mem.eql(u8, res, "1100"));
- }
-}
-
-test "array" {
- {
- const value: [3]u8 = "abc".*;
- try testFmt("array: abc\n", "array: {}\n", .{value});
- try testFmt("array: abc\n", "array: {}\n", .{&value});
-
- var buf: [100]u8 = undefined;
- try testFmt(
- try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@ptrToInt(&value)}),
- "array: {*}\n",
- .{&value},
- );
- }
-}
-
-test "slice" {
- {
- const value: []const u8 = "abc";
- try testFmt("slice: abc\n", "slice: {}\n", .{value});
- }
- {
- const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
- try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
- }
-
- try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
- try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
-}
-
-test "pointer" {
- {
- const value = @intToPtr(*align(1) i32, 0xdeadbeef);
- try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", .{value});
- try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", .{value});
- }
- {
- const value = @intToPtr(fn () void, 0xdeadbeef);
- try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
- }
- {
- const value = @intToPtr(fn () void, 0xdeadbeef);
- try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
- }
-}
-
-test "cstr" {
- try testFmt(
- "cstr: Test C\n",
- "cstr: {s}\n",
- .{@ptrCast([*c]const u8, "Test C")},
- );
- try testFmt(
- "cstr: Test C \n",
- "cstr: {s:10}\n",
- .{@ptrCast([*c]const u8, "Test C")},
- );
-}
-
-test "filesize" {
- try testFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
- try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
-}
-
-test "struct" {
- {
- const Struct = struct {
- field: u8,
- };
- const value = Struct{ .field = 42 };
- try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{value});
- try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
- }
- {
- const Struct = struct {
- a: u0,
- b: u1,
- };
- const value = Struct{ .a = 0, .b = 1 };
- try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
- }
-}
-
-test "enum" {
- const Enum = enum {
- One,
- Two,
- };
- const value = Enum.Two;
- try testFmt("enum: Enum.Two\n", "enum: {}\n", .{value});
- try testFmt("enum: Enum.Two\n", "enum: {}\n", .{&value});
-}
-
-test "non-exhaustive enum" {
- const Enum = enum(u16) {
- One = 0x000f,
- Two = 0xbeef,
- _,
- };
- try testFmt("enum: Enum(15)\n", "enum: {}\n", .{Enum.One});
- try testFmt("enum: Enum(48879)\n", "enum: {}\n", .{Enum.Two});
- try testFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
- try testFmt("enum: Enum(f)\n", "enum: {x}\n", .{Enum.One});
- try testFmt("enum: Enum(beef)\n", "enum: {x}\n", .{Enum.Two});
- try testFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
-}
-
-test "float.scientific" {
- try testFmt("f32: 1.34000003e+00", "f32: {e}", .{@as(f32, 1.34)});
- try testFmt("f32: 1.23400001e+01", "f32: {e}", .{@as(f32, 12.34)});
- try testFmt("f64: -1.234e+11", "f64: {e}", .{@as(f64, -12.34e10)});
- try testFmt("f64: 9.99996e-40", "f64: {e}", .{@as(f64, 9.999960e-40)});
-}
-
-test "float.scientific.precision" {
- try testFmt("f64: 1.40971e-42", "f64: {e:.5}", .{@as(f64, 1.409706e-42)});
- try testFmt("f64: 1.00000e-09", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 814313563)))});
- try testFmt("f64: 7.81250e-03", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1006632960)))});
- // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
- // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
- try testFmt("f64: 1.00001e+05", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1203982400)))});
-}
-
-test "float.special" {
- try testFmt("f64: nan", "f64: {}", .{math.nan_f64});
- // negative nan is not defined by IEE 754,
- // and ARM thus normalizes it to positive nan
- if (builtin.arch != builtin.Arch.arm) {
- try testFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
- }
- try testFmt("f64: inf", "f64: {}", .{math.inf_f64});
- try testFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
-}
-
-test "float.decimal" {
- try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
- try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
- try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)});
- try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)});
- // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
- // -11.12339... is rounded back up to -11.1234
- try testFmt("f32: -11.1234", "f32: {d:.4}", .{@as(f32, -11.1234)});
- try testFmt("f32: 91.12345", "f32: {d:.5}", .{@as(f32, 91.12345)});
- try testFmt("f64: 91.1234567890", "f64: {d:.10}", .{@as(f64, 91.12345678901235)});
- try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 0.0)});
- try testFmt("f64: 6", "f64: {d:.0}", .{@as(f64, 5.700)});
- try testFmt("f64: 10.0", "f64: {d:.1}", .{@as(f64, 9.999)});
- try testFmt("f64: 1.000", "f64: {d:.3}", .{@as(f64, 1.0)});
- try testFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)});
- try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
- try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
-}
-
-test "float.libc.sanity" {
- try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 916964781)))});
- try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 925353389)))});
- try testFmt("f64: 0.10000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1036831278)))});
- try testFmt("f64: 1.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1065353133)))});
- try testFmt("f64: 10.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1092616192)))});
-
- // libc differences
- //
- // This is 0.015625 exactly according to gdb. We thus round down,
- // however glibc rounds up for some reason. This occurs for all
- // floats of the form x.yyyy25 on a precision point.
- try testFmt("f64: 0.01563", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1015021568)))});
- // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
- // also rounds to 630 so I'm inclined to believe libc is not
- // optimal here.
- try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1518338049)))});
-}
-
-test "custom" {
- const Vec2 = struct {
- const SelfType = @This();
- x: f32,
- y: f32,
-
- pub fn format(
- self: SelfType,
- comptime fmt: []const u8,
- options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) !void,
- ) !void {
- if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
- return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
- } else if (comptime std.mem.eql(u8, fmt, "d")) {
- return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
- } else {
- @compileError("Unknown format character: '" ++ fmt ++ "'");
- }
- }
- };
-
- var buf1: [32]u8 = undefined;
- var value = Vec2{
- .x = 10.2,
- .y = 2.22,
- };
- try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
- try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
-
- // same thing but not passing a pointer
- try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
- try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
-}
-
-test "struct" {
- const S = struct {
- a: u32,
- b: anyerror,
- };
-
- const inst = S{
- .a = 456,
- .b = error.Unused,
- };
-
- try testFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
-}
-
-test "union" {
- const TU = union(enum) {
- float: f32,
- int: u32,
- };
-
- const UU = union {
- float: f32,
- int: u32,
- };
-
- const EU = extern union {
- float: f32,
- int: u32,
- };
-
- const tu_inst = TU{ .int = 123 };
- const uu_inst = UU{ .int = 456 };
- const eu_inst = EU{ .float = 321.123 };
-
- try testFmt("TU{ .int = 123 }", "{}", .{tu_inst});
-
- var buf: [100]u8 = undefined;
- const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
- std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
-
- const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
- std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
-}
-
-test "enum" {
- const E = enum {
- One,
- Two,
- Three,
- };
-
- const inst = E.Two;
-
- try testFmt("E.Two", "{}", .{inst});
-}
-
-test "struct.self-referential" {
- const S = struct {
- const SelfType = @This();
- a: ?*SelfType,
- };
-
- var inst = S{
- .a = null,
- };
- inst.a = &inst;
-
- try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
-}
-
-test "struct.zero-size" {
- const A = struct {
- fn foo() void {}
- };
- const B = struct {
- a: A,
- c: i32,
- };
-
- const a = A{};
- const b = B{ .a = a, .c = 0 };
-
- try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
-}
-
-test "bytes.hex" {
- const some_bytes = "\xCA\xFE\xBA\xBE";
- try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
- try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
- //Test Slices
- try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
- try testFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
- const bytes_with_zeros = "\x00\x0E\xBA\xBE";
- try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
-}
-
-fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void {
- var buf: [100]u8 = undefined;
- const result = try bufPrint(buf[0..], template, args);
- if (mem.eql(u8, result, expected)) return;
-
- std.debug.warn("\n====== expected this output: =========\n", .{});
- std.debug.warn("{}", .{expected});
- std.debug.warn("\n======== instead found this: =========\n", .{});
- std.debug.warn("{}", .{result});
- std.debug.warn("\n======================================\n", .{});
- return error.TestFailed;
-}
-
-pub fn trim(buf: []const u8) []const u8 {
- var start: usize = 0;
- while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
-
- var end: usize = buf.len;
- while (true) {
- if (end > start) {
- const new_end = end - 1;
- if (isWhiteSpace(buf[new_end])) {
- end = new_end;
- continue;
- }
- }
- break;
- }
- return buf[start..end];
-}
-
-test "trim" {
- std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
- std.testing.expect(mem.eql(u8, "", trim(" ")));
- std.testing.expect(mem.eql(u8, "", trim("")));
- std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
- std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
-}
-
-pub fn isWhiteSpace(byte: u8) bool {
- return switch (byte) {
- ' ', '\t', '\n', '\r' => true,
- else => false,
- };
-}
-
-pub fn hexToBytes(out: []u8, input: []const u8) !void {
- if (out.len * 2 < input.len)
- return error.InvalidLength;
-
- var in_i: usize = 0;
- while (in_i != input.len) : (in_i += 2) {
- const hi = try charToDigit(input[in_i], 16);
- const lo = try charToDigit(input[in_i + 1], 16);
- out[in_i / 2] = (hi << 4) | lo;
- }
-}
-
-test "hexToBytes" {
- const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
- var pb: [32]u8 = undefined;
- try hexToBytes(pb[0..], test_hex_str);
- try testFmt(test_hex_str, "{X}", .{pb});
-}
-
-test "formatIntValue with comptime_int" {
- const value: comptime_int = 123456789123456789;
-
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
- std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
-}
-
-test "formatType max_depth" {
- const Vec2 = struct {
- const SelfType = @This();
- x: f32,
- y: f32,
-
- pub fn format(
- self: SelfType,
- comptime fmt: []const u8,
- options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) !void,
- ) !void {
- if (fmt.len == 0) {
- return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
- } else {
- @compileError("Unknown format string: '" ++ fmt ++ "'");
- }
- }
- };
- const E = enum {
- One,
- Two,
- Three,
- };
- const TU = union(enum) {
- const SelfType = @This();
- float: f32,
- int: u32,
- ptr: ?*SelfType,
- };
- const S = struct {
- const SelfType = @This();
- a: ?*SelfType,
- tu: TU,
- e: E,
- vec: Vec2,
- };
-
- var inst = S{
- .a = null,
- .tu = TU{ .ptr = null },
- .e = E.Two,
- .vec = Vec2{ .x = 10.2, .y = 2.22 },
- };
- inst.a = &inst;
- inst.tu.ptr = &inst.tu;
-
- var buf0 = std.ArrayList(u8).init(std.testing.allocator);
- defer buf0.deinit();
- try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
- std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
-
- var buf1 = std.ArrayList(u8).init(std.testing.allocator);
- defer buf1.deinit();
- try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
- std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
-
- var buf2 = std.ArrayList(u8).init(std.testing.allocator);
- defer buf2.deinit();
- try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
- std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
-
- var buf3 = std.ArrayList(u8).init(std.testing.allocator);
- defer buf3.deinit();
- try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
- std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
-}
-
-test "positional" {
- try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
- try testFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
- try testFmt("0 0", "{0} {0}", .{@as(usize, 0)});
- try testFmt("0 1", "{} {1}", .{ @as(usize, 0), @as(usize, 1) });
- try testFmt("1 0 0 1", "{1} {} {0} {}", .{ @as(usize, 0), @as(usize, 1) });
-}
-
-test "positional with specifier" {
- try testFmt("10.0", "{0d:.1}", .{@as(f64, 9.999)});
-}
-
-test "positional/alignment/width/precision" {
- try testFmt("10.0", "{0d: >3.1}", .{@as(f64, 9.999)});
-}
-
-test "vector" {
- // https://github.com/ziglang/zig/issues/3317
- if (builtin.arch == .mipsel) return error.SkipZigTest;
-
- const vbool: @Vector(4, bool) = [_]bool{ true, false, true, false };
- const vi64: @Vector(4, i64) = [_]i64{ -2, -1, 0, 1 };
- const vu64: @Vector(4, u64) = [_]u64{ 1000, 2000, 3000, 4000 };
-
- try testFmt("{ true, false, true, false }", "{}", .{vbool});
- try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
- try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
- try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
- try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
- try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
- try testFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
-}
-
-test "enum-literal" {
- try testFmt(".hello_world", "{}", .{.hello_world});
-}
+// test "parse u64 digit too big" {
+// _ = parseUnsigned(u64, "123a", 10) catch |err| {
+// if (err == error.InvalidCharacter) return;
+// unreachable;
+// };
+// unreachable;
+// }
+
+// test "parse unsigned comptime" {
+// comptime {
+// std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
+// }
+// }
+
+// test "optional" {
+// {
+// const value: ?i32 = 1234;
+// try testFmt("optional: 1234\n", "optional: {}\n", .{value});
+// }
+// {
+// const value: ?i32 = null;
+// try testFmt("optional: null\n", "optional: {}\n", .{value});
+// }
+// }
+
+// test "error" {
+// {
+// const value: anyerror!i32 = 1234;
+// try testFmt("error union: 1234\n", "error union: {}\n", .{value});
+// }
+// {
+// const value: anyerror!i32 = error.InvalidChar;
+// try testFmt("error union: error.InvalidChar\n", "error union: {}\n", .{value});
+// }
+// }
+
+// test "int.small" {
+// {
+// const value: u3 = 0b101;
+// try testFmt("u3: 5\n", "u3: {}\n", .{value});
+// }
+// }
+
+// test "int.specifier" {
+// {
+// const value: u8 = 'a';
+// try testFmt("u8: a\n", "u8: {c}\n", .{value});
+// }
+// {
+// const value: u8 = 0b1100;
+// try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", .{value});
+// }
+// }
+
+// test "int.padded" {
+// try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
+// try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
+// }
+
+// test "buffer" {
+// {
+// var buf1: [32]u8 = undefined;
+// var context = BufPrintContext{ .remaining = buf1[0..] };
+// try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
+// var res = buf1[0 .. buf1.len - context.remaining.len];
+// std.testing.expect(mem.eql(u8, res, "1234"));
+
+// context = BufPrintContext{ .remaining = buf1[0..] };
+// try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
+// res = buf1[0 .. buf1.len - context.remaining.len];
+// std.testing.expect(mem.eql(u8, res, "a"));
+
+// context = BufPrintContext{ .remaining = buf1[0..] };
+// try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
+// res = buf1[0 .. buf1.len - context.remaining.len];
+// std.testing.expect(mem.eql(u8, res, "1100"));
+// }
+// }
+
+// test "array" {
+// {
+// const value: [3]u8 = "abc".*;
+// try testFmt("array: abc\n", "array: {}\n", .{value});
+// try testFmt("array: abc\n", "array: {}\n", .{&value});
+
+// var buf: [100]u8 = undefined;
+// try testFmt(
+// try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@ptrToInt(&value)}),
+// "array: {*}\n",
+// .{&value},
+// );
+// }
+// }
+
+// test "slice" {
+// {
+// const value: []const u8 = "abc";
+// try testFmt("slice: abc\n", "slice: {}\n", .{value});
+// }
+// {
+// const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
+// try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
+// }
+
+// try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
+// try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
+// }
+
+// test "pointer" {
+// {
+// const value = @intToPtr(*align(1) i32, 0xdeadbeef);
+// try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", .{value});
+// try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", .{value});
+// }
+// {
+// const value = @intToPtr(fn () void, 0xdeadbeef);
+// try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
+// }
+// {
+// const value = @intToPtr(fn () void, 0xdeadbeef);
+// try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
+// }
+// }
+
+// test "cstr" {
+// try testFmt(
+// "cstr: Test C\n",
+// "cstr: {s}\n",
+// .{@ptrCast([*c]const u8, "Test C")},
+// );
+// try testFmt(
+// "cstr: Test C \n",
+// "cstr: {s:10}\n",
+// .{@ptrCast([*c]const u8, "Test C")},
+// );
+// }
+
+// test "filesize" {
+// try testFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
+// try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
+// }
+
+// test "struct" {
+// {
+// const Struct = struct {
+// field: u8,
+// };
+// const value = Struct{ .field = 42 };
+// try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{value});
+// try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
+// }
+// {
+// const Struct = struct {
+// a: u0,
+// b: u1,
+// };
+// const value = Struct{ .a = 0, .b = 1 };
+// try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
+// }
+// }
+
+// test "enum" {
+// const Enum = enum {
+// One,
+// Two,
+// };
+// const value = Enum.Two;
+// try testFmt("enum: Enum.Two\n", "enum: {}\n", .{value});
+// try testFmt("enum: Enum.Two\n", "enum: {}\n", .{&value});
+// }
+
+// test "non-exhaustive enum" {
+// const Enum = enum(u16) {
+// One = 0x000f,
+// Two = 0xbeef,
+// _,
+// };
+// try testFmt("enum: Enum(15)\n", "enum: {}\n", .{Enum.One});
+// try testFmt("enum: Enum(48879)\n", "enum: {}\n", .{Enum.Two});
+// try testFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
+// try testFmt("enum: Enum(f)\n", "enum: {x}\n", .{Enum.One});
+// try testFmt("enum: Enum(beef)\n", "enum: {x}\n", .{Enum.Two});
+// try testFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
+// }
+
+// test "float.scientific" {
+// try testFmt("f32: 1.34000003e+00", "f32: {e}", .{@as(f32, 1.34)});
+// try testFmt("f32: 1.23400001e+01", "f32: {e}", .{@as(f32, 12.34)});
+// try testFmt("f64: -1.234e+11", "f64: {e}", .{@as(f64, -12.34e10)});
+// try testFmt("f64: 9.99996e-40", "f64: {e}", .{@as(f64, 9.999960e-40)});
+// }
+
+// test "float.scientific.precision" {
+// try testFmt("f64: 1.40971e-42", "f64: {e:.5}", .{@as(f64, 1.409706e-42)});
+// try testFmt("f64: 1.00000e-09", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 814313563)))});
+// try testFmt("f64: 7.81250e-03", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1006632960)))});
+// // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
+// // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
+// try testFmt("f64: 1.00001e+05", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1203982400)))});
+// }
+
+// test "float.special" {
+// try testFmt("f64: nan", "f64: {}", .{math.nan_f64});
+// // negative nan is not defined by IEE 754,
+// // and ARM thus normalizes it to positive nan
+// if (builtin.arch != builtin.Arch.arm) {
+// try testFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
+// }
+// try testFmt("f64: inf", "f64: {}", .{math.inf_f64});
+// try testFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
+// }
+
+// test "float.decimal" {
+// try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
+// try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
+// try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)});
+// try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)});
+// // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
+// // -11.12339... is rounded back up to -11.1234
+// try testFmt("f32: -11.1234", "f32: {d:.4}", .{@as(f32, -11.1234)});
+// try testFmt("f32: 91.12345", "f32: {d:.5}", .{@as(f32, 91.12345)});
+// try testFmt("f64: 91.1234567890", "f64: {d:.10}", .{@as(f64, 91.12345678901235)});
+// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 0.0)});
+// try testFmt("f64: 6", "f64: {d:.0}", .{@as(f64, 5.700)});
+// try testFmt("f64: 10.0", "f64: {d:.1}", .{@as(f64, 9.999)});
+// try testFmt("f64: 1.000", "f64: {d:.3}", .{@as(f64, 1.0)});
+// try testFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)});
+// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
+// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
+// }
+
+// test "float.libc.sanity" {
+// try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 916964781)))});
+// try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 925353389)))});
+// try testFmt("f64: 0.10000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1036831278)))});
+// try testFmt("f64: 1.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1065353133)))});
+// try testFmt("f64: 10.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1092616192)))});
+
+// // libc differences
+// //
+// // This is 0.015625 exactly according to gdb. We thus round down,
+// // however glibc rounds up for some reason. This occurs for all
+// // floats of the form x.yyyy25 on a precision point.
+// try testFmt("f64: 0.01563", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1015021568)))});
+// // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
+// // also rounds to 630 so I'm inclined to believe libc is not
+// // optimal here.
+// try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1518338049)))});
+// }
+
+// test "custom" {
+// const Vec2 = struct {
+// const SelfType = @This();
+// x: f32,
+// y: f32,
+
+// pub fn format(
+// self: SelfType,
+// comptime fmt: []const u8,
+// options: FormatOptions,
+// context: var,
+// comptime Errors: type,
+// comptime output: fn (@TypeOf(context), []const u8) !void,
+// ) !void {
+// if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
+// return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
+// } else if (comptime std.mem.eql(u8, fmt, "d")) {
+// return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
+// } else {
+// @compileError("Unknown format character: '" ++ fmt ++ "'");
+// }
+// }
+// };
+
+// var buf1: [32]u8 = undefined;
+// var value = Vec2{
+// .x = 10.2,
+// .y = 2.22,
+// };
+// try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
+// try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
+
+// // same thing but not passing a pointer
+// try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
+// try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
+// }
+
+// test "struct" {
+// const S = struct {
+// a: u32,
+// b: anyerror,
+// };
+
+// const inst = S{
+// .a = 456,
+// .b = error.Unused,
+// };
+
+// try testFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
+// }
+
+// test "union" {
+// const TU = union(enum) {
+// float: f32,
+// int: u32,
+// };
+
+// const UU = union {
+// float: f32,
+// int: u32,
+// };
+
+// const EU = extern union {
+// float: f32,
+// int: u32,
+// };
+
+// const tu_inst = TU{ .int = 123 };
+// const uu_inst = UU{ .int = 456 };
+// const eu_inst = EU{ .float = 321.123 };
+
+// try testFmt("TU{ .int = 123 }", "{}", .{tu_inst});
+
+// var buf: [100]u8 = undefined;
+// const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
+// std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
+
+// const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
+// std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
+// }
+
+// test "enum" {
+// const E = enum {
+// One,
+// Two,
+// Three,
+// };
+
+// const inst = E.Two;
+
+// try testFmt("E.Two", "{}", .{inst});
+// }
+
+// test "struct.self-referential" {
+// const S = struct {
+// const SelfType = @This();
+// a: ?*SelfType,
+// };
+
+// var inst = S{
+// .a = null,
+// };
+// inst.a = &inst;
+
+// try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
+// }
+
+// test "struct.zero-size" {
+// const A = struct {
+// fn foo() void {}
+// };
+// const B = struct {
+// a: A,
+// c: i32,
+// };
+
+// const a = A{};
+// const b = B{ .a = a, .c = 0 };
+
+// try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
+// }
+
+// test "bytes.hex" {
+// const some_bytes = "\xCA\xFE\xBA\xBE";
+// try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
+// try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
+// //Test Slices
+// try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
+// try testFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
+// const bytes_with_zeros = "\x00\x0E\xBA\xBE";
+// try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
+// }
+
+// fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void {
+// var buf: [100]u8 = undefined;
+// const result = try bufPrint(buf[0..], template, args);
+// if (mem.eql(u8, result, expected)) return;
+
+// std.debug.warn("\n====== expected this output: =========\n", .{});
+// std.debug.warn("{}", .{expected});
+// std.debug.warn("\n======== instead found this: =========\n", .{});
+// std.debug.warn("{}", .{result});
+// std.debug.warn("\n======================================\n", .{});
+// return error.TestFailed;
+// }
+
+// pub fn trim(buf: []const u8) []const u8 {
+// var start: usize = 0;
+// while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
+
+// var end: usize = buf.len;
+// while (true) {
+// if (end > start) {
+// const new_end = end - 1;
+// if (isWhiteSpace(buf[new_end])) {
+// end = new_end;
+// continue;
+// }
+// }
+// break;
+// }
+// return buf[start..end];
+// }
+
+// test "trim" {
+// std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
+// std.testing.expect(mem.eql(u8, "", trim(" ")));
+// std.testing.expect(mem.eql(u8, "", trim("")));
+// std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
+// std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
+// }
+
+// pub fn isWhiteSpace(byte: u8) bool {
+// return switch (byte) {
+// ' ', '\t', '\n', '\r' => true,
+// else => false,
+// };
+// }
+
+// pub fn hexToBytes(out: []u8, input: []const u8) !void {
+// if (out.len * 2 < input.len)
+// return error.InvalidLength;
+
+// var in_i: usize = 0;
+// while (in_i != input.len) : (in_i += 2) {
+// const hi = try charToDigit(input[in_i], 16);
+// const lo = try charToDigit(input[in_i + 1], 16);
+// out[in_i / 2] = (hi << 4) | lo;
+// }
+// }
+
+// test "hexToBytes" {
+// const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
+// var pb: [32]u8 = undefined;
+// try hexToBytes(pb[0..], test_hex_str);
+// try testFmt(test_hex_str, "{X}", .{pb});
+// }
+
+// test "formatIntValue with comptime_int" {
+// const value: comptime_int = 123456789123456789;
+
+// var buf = std.ArrayList(u8).init(std.testing.allocator);
+// defer buf.deinit();
+// try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
+// std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
+// }
+
+// test "formatType max_depth" {
+// const Vec2 = struct {
+// const SelfType = @This();
+// x: f32,
+// y: f32,
+
+// pub fn format(
+// self: SelfType,
+// comptime fmt: []const u8,
+// options: FormatOptions,
+// context: var,
+// comptime Errors: type,
+// comptime output: fn (@TypeOf(context), []const u8) !void,
+// ) !void {
+// if (fmt.len == 0) {
+// return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
+// } else {
+// @compileError("Unknown format string: '" ++ fmt ++ "'");
+// }
+// }
+// };
+// const E = enum {
+// One,
+// Two,
+// Three,
+// };
+// const TU = union(enum) {
+// const SelfType = @This();
+// float: f32,
+// int: u32,
+// ptr: ?*SelfType,
+// };
+// const S = struct {
+// const SelfType = @This();
+// a: ?*SelfType,
+// tu: TU,
+// e: E,
+// vec: Vec2,
+// };
+
+// var inst = S{
+// .a = null,
+// .tu = TU{ .ptr = null },
+// .e = E.Two,
+// .vec = Vec2{ .x = 10.2, .y = 2.22 },
+// };
+// inst.a = &inst;
+// inst.tu.ptr = &inst.tu;
+
+// var buf0 = std.ArrayList(u8).init(std.testing.allocator);
+// defer buf0.deinit();
+// try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
+// std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
+
+// var buf1 = std.ArrayList(u8).init(std.testing.allocator);
+// defer buf1.deinit();
+// try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
+// std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
+
+// var buf2 = std.ArrayList(u8).init(std.testing.allocator);
+// defer buf2.deinit();
+// try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
+// std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
+
+// var buf3 = std.ArrayList(u8).init(std.testing.allocator);
+// defer buf3.deinit();
+// try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
+// std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
+// }
+
+// test "positional" {
+// try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
+// try testFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
+// try testFmt("0 0", "{0} {0}", .{@as(usize, 0)});
+// try testFmt("0 1", "{} {1}", .{ @as(usize, 0), @as(usize, 1) });
+// try testFmt("1 0 0 1", "{1} {} {0} {}", .{ @as(usize, 0), @as(usize, 1) });
+// }
+
+// test "positional with specifier" {
+// try testFmt("10.0", "{0d:.1}", .{@as(f64, 9.999)});
+// }
+
+// test "positional/alignment/width/precision" {
+// try testFmt("10.0", "{0d: >3.1}", .{@as(f64, 9.999)});
+// }
+
+// test "vector" {
+// // https://github.com/ziglang/zig/issues/3317
+// if (builtin.arch == .mipsel) return error.SkipZigTest;
+
+// const vbool: @Vector(4, bool) = [_]bool{ true, false, true, false };
+// const vi64: @Vector(4, i64) = [_]i64{ -2, -1, 0, 1 };
+// const vu64: @Vector(4, u64) = [_]u64{ 1000, 2000, 3000, 4000 };
+
+// try testFmt("{ true, false, true, false }", "{}", .{vbool});
+// try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
+// try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
+// try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
+// try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
+// try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
+// try testFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
+// }
+
+// test "enum-literal" {
+// try testFmt(".hello_world", "{}", .{.hello_world});
+// }
From 8241b96f78fa8ee33f9a73d4d296509d49b6f351 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 12:25:12 -0600
Subject: [PATCH 076/111] Re-enable testFmt
---
lib/std/fmtstream.zig | 75 ++++++++++++++++++-------------------------
1 file changed, 32 insertions(+), 43 deletions(-)
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index d64c6cdf7..4a7d8041c 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -1074,28 +1074,17 @@ fn digitToChar(digit: u8, uppercase: bool) u8 {
};
}
-// const BufPrintContext = struct {
-// remaining: []u8,
-// };
-
-// fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
-// if (context.remaining.len < bytes.len) {
-// mem.copy(u8, context.remaining, bytes[0..context.remaining.len]);
-// return error.BufferTooSmall;
-// }
-// mem.copy(u8, context.remaining, bytes);
-// context.remaining = context.remaining[bytes.len..];
-// }
-
-// pub const BufPrintError = error{
-// /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
-// BufferTooSmall,
-// };
-// pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
-// var context = BufPrintContext{ .remaining = buf };
-// try format(&context, BufPrintError, bufPrintWrite, fmt, args);
-// return buf[0 .. buf.len - context.remaining.len];
-// }
+pub const BufPrintError = error{
+ /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
+ BufferTooSmall,
+};
+pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
+ var os = std.io.SliceOutStream.init(buf);
+ format(&os.stream, fmt, args) catch |err| switch (err) {
+ error.OutOfMemory => return error.BufferTooSmall,
+ };
+ return buf[0..os.pos];
+}
// pub const AllocPrintError = error{OutOfMemory};
@@ -1514,29 +1503,29 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options:
// try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
// }
-// test "bytes.hex" {
-// const some_bytes = "\xCA\xFE\xBA\xBE";
-// try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
-// try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
-// //Test Slices
-// try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
-// try testFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
-// const bytes_with_zeros = "\x00\x0E\xBA\xBE";
-// try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
-// }
+test "bytes.hex" {
+ const some_bytes = "\xCA\xFE\xBA\xBE";
+ try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
+ try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
+ //Test Slices
+ try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
+ try testFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
+ const bytes_with_zeros = "\x00\x0E\xBA\xBE";
+ try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
+}
-// fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void {
-// var buf: [100]u8 = undefined;
-// const result = try bufPrint(buf[0..], template, args);
-// if (mem.eql(u8, result, expected)) return;
+fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void {
+ var buf: [100]u8 = undefined;
+ const result = try bufPrint(buf[0..], template, args);
+ if (mem.eql(u8, result, expected)) return;
-// std.debug.warn("\n====== expected this output: =========\n", .{});
-// std.debug.warn("{}", .{expected});
-// std.debug.warn("\n======== instead found this: =========\n", .{});
-// std.debug.warn("{}", .{result});
-// std.debug.warn("\n======================================\n", .{});
-// return error.TestFailed;
-// }
+ std.debug.warn("\n====== expected this output: =========\n", .{});
+ std.debug.warn("{}", .{expected});
+ std.debug.warn("\n======== instead found this: =========\n", .{});
+ std.debug.warn("{}", .{result});
+ std.debug.warn("\n======================================\n", .{});
+ return error.TestFailed;
+}
// pub fn trim(buf: []const u8) []const u8 {
// var start: usize = 0;
From 78d12762a9c78f9563a3cfd29541d0a04f78ab58 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 13:22:27 -0600
Subject: [PATCH 077/111] Re-enable a bunch of tests
---
lib/std/fmtstream.zig | 798 +++++++++++++++++++++---------------------
1 file changed, 398 insertions(+), 400 deletions(-)
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index 4a7d8041c..3a2767c85 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -430,7 +430,7 @@ pub fn formatType(
},
.Many, .C => {
if (ptr_info.sentinel) |sentinel| {
- return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
+ return formatType(mem.span(value), fmt, options, out_stream, max_depth);
}
if (ptr_info.child == u8) {
if (fmt.len > 0 and fmt[0] == 's') {
@@ -481,7 +481,7 @@ pub fn formatType(
.Type => return out_stream.writeAll(@typeName(T)),
.EnumLiteral => {
const buffer = [_]u8{'.'} ++ @tagName(value);
- return formatType(buffer, fmt, options, context, Errors, output, max_depth);
+ return formatType(buffer, fmt, options, out_stream, max_depth);
},
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
}
@@ -1079,11 +1079,11 @@ pub const BufPrintError = error{
BufferTooSmall,
};
pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
- var os = std.io.SliceOutStream.init(buf);
- format(&os.stream, fmt, args) catch |err| switch (err) {
- error.OutOfMemory => return error.BufferTooSmall,
+ var fbs = std.io.fixedBufferStream(buf);
+ format(fbs.outStream(), fmt, args) catch |err| switch (err) {
+ error.NoSpaceLeft => return error.BufferTooSmall,
};
- return buf[0..os.pos];
+ return buf[0..fbs.pos];
}
// pub const AllocPrintError = error{OutOfMemory};
@@ -1131,348 +1131,346 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options:
return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
}
-// test "parse u64 digit too big" {
-// _ = parseUnsigned(u64, "123a", 10) catch |err| {
-// if (err == error.InvalidCharacter) return;
-// unreachable;
-// };
-// unreachable;
-// }
+test "parse u64 digit too big" {
+ _ = parseUnsigned(u64, "123a", 10) catch |err| {
+ if (err == error.InvalidCharacter) return;
+ unreachable;
+ };
+ unreachable;
+}
-// test "parse unsigned comptime" {
-// comptime {
-// std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
-// }
-// }
+test "parse unsigned comptime" {
+ comptime {
+ std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
+ }
+}
-// test "optional" {
-// {
-// const value: ?i32 = 1234;
-// try testFmt("optional: 1234\n", "optional: {}\n", .{value});
-// }
-// {
-// const value: ?i32 = null;
-// try testFmt("optional: null\n", "optional: {}\n", .{value});
-// }
-// }
+test "optional" {
+ {
+ const value: ?i32 = 1234;
+ try testFmt("optional: 1234\n", "optional: {}\n", .{value});
+ }
+ {
+ const value: ?i32 = null;
+ try testFmt("optional: null\n", "optional: {}\n", .{value});
+ }
+}
-// test "error" {
-// {
-// const value: anyerror!i32 = 1234;
-// try testFmt("error union: 1234\n", "error union: {}\n", .{value});
-// }
-// {
-// const value: anyerror!i32 = error.InvalidChar;
-// try testFmt("error union: error.InvalidChar\n", "error union: {}\n", .{value});
-// }
-// }
+test "error" {
+ {
+ const value: anyerror!i32 = 1234;
+ try testFmt("error union: 1234\n", "error union: {}\n", .{value});
+ }
+ {
+ const value: anyerror!i32 = error.InvalidChar;
+ try testFmt("error union: error.InvalidChar\n", "error union: {}\n", .{value});
+ }
+}
-// test "int.small" {
-// {
-// const value: u3 = 0b101;
-// try testFmt("u3: 5\n", "u3: {}\n", .{value});
-// }
-// }
+test "int.small" {
+ {
+ const value: u3 = 0b101;
+ try testFmt("u3: 5\n", "u3: {}\n", .{value});
+ }
+}
-// test "int.specifier" {
-// {
-// const value: u8 = 'a';
-// try testFmt("u8: a\n", "u8: {c}\n", .{value});
-// }
-// {
-// const value: u8 = 0b1100;
-// try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", .{value});
-// }
-// }
+test "int.specifier" {
+ {
+ const value: u8 = 'a';
+ try testFmt("u8: a\n", "u8: {c}\n", .{value});
+ }
+ {
+ const value: u8 = 0b1100;
+ try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", .{value});
+ }
+}
-// test "int.padded" {
-// try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
-// try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
-// }
+test "int.padded" {
+ try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
+ try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
+}
-// test "buffer" {
-// {
-// var buf1: [32]u8 = undefined;
-// var context = BufPrintContext{ .remaining = buf1[0..] };
-// try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
-// var res = buf1[0 .. buf1.len - context.remaining.len];
-// std.testing.expect(mem.eql(u8, res, "1234"));
+test "buffer" {
+ {
+ var buf1: [32]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buf1);
+ try formatType(1234, "", FormatOptions{}, fbs.outStream(), default_max_depth);
+ var res = buf1[0..fbs.pos];
+ std.testing.expect(mem.eql(u8, res, "1234"));
-// context = BufPrintContext{ .remaining = buf1[0..] };
-// try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
-// res = buf1[0 .. buf1.len - context.remaining.len];
-// std.testing.expect(mem.eql(u8, res, "a"));
+ try fbs.seekTo(0);
+ try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth);
+ res = buf1[0..fbs.pos];
+ std.testing.expect(mem.eql(u8, res, "a"));
-// context = BufPrintContext{ .remaining = buf1[0..] };
-// try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
-// res = buf1[0 .. buf1.len - context.remaining.len];
-// std.testing.expect(mem.eql(u8, res, "1100"));
-// }
-// }
+ try fbs.seekTo(0);
+ try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth);
+ res = buf1[0..fbs.pos];
+ std.testing.expect(mem.eql(u8, res, "1100"));
+ }
+}
-// test "array" {
-// {
-// const value: [3]u8 = "abc".*;
-// try testFmt("array: abc\n", "array: {}\n", .{value});
-// try testFmt("array: abc\n", "array: {}\n", .{&value});
+test "array" {
+ {
+ const value: [3]u8 = "abc".*;
+ try testFmt("array: abc\n", "array: {}\n", .{value});
+ try testFmt("array: abc\n", "array: {}\n", .{&value});
-// var buf: [100]u8 = undefined;
-// try testFmt(
-// try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@ptrToInt(&value)}),
-// "array: {*}\n",
-// .{&value},
-// );
-// }
-// }
+ var buf: [100]u8 = undefined;
+ try testFmt(
+ try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@ptrToInt(&value)}),
+ "array: {*}\n",
+ .{&value},
+ );
+ }
+}
-// test "slice" {
-// {
-// const value: []const u8 = "abc";
-// try testFmt("slice: abc\n", "slice: {}\n", .{value});
-// }
-// {
-// const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
-// try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
-// }
+test "slice" {
+ {
+ const value: []const u8 = "abc";
+ try testFmt("slice: abc\n", "slice: {}\n", .{value});
+ }
+ {
+ const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
+ try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
+ }
-// try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
-// try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
-// }
+ try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
+ try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
+}
-// test "pointer" {
-// {
-// const value = @intToPtr(*align(1) i32, 0xdeadbeef);
-// try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", .{value});
-// try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", .{value});
-// }
-// {
-// const value = @intToPtr(fn () void, 0xdeadbeef);
-// try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
-// }
-// {
-// const value = @intToPtr(fn () void, 0xdeadbeef);
-// try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
-// }
-// }
+test "pointer" {
+ {
+ const value = @intToPtr(*align(1) i32, 0xdeadbeef);
+ try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", .{value});
+ try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", .{value});
+ }
+ {
+ const value = @intToPtr(fn () void, 0xdeadbeef);
+ try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
+ }
+ {
+ const value = @intToPtr(fn () void, 0xdeadbeef);
+ try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
+ }
+}
-// test "cstr" {
-// try testFmt(
-// "cstr: Test C\n",
-// "cstr: {s}\n",
-// .{@ptrCast([*c]const u8, "Test C")},
-// );
-// try testFmt(
-// "cstr: Test C \n",
-// "cstr: {s:10}\n",
-// .{@ptrCast([*c]const u8, "Test C")},
-// );
-// }
+test "cstr" {
+ try testFmt(
+ "cstr: Test C\n",
+ "cstr: {s}\n",
+ .{@ptrCast([*c]const u8, "Test C")},
+ );
+ try testFmt(
+ "cstr: Test C \n",
+ "cstr: {s:10}\n",
+ .{@ptrCast([*c]const u8, "Test C")},
+ );
+}
-// test "filesize" {
-// try testFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
-// try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
-// }
+test "filesize" {
+ try testFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
+ try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
+}
-// test "struct" {
-// {
-// const Struct = struct {
-// field: u8,
-// };
-// const value = Struct{ .field = 42 };
-// try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{value});
-// try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
-// }
-// {
-// const Struct = struct {
-// a: u0,
-// b: u1,
-// };
-// const value = Struct{ .a = 0, .b = 1 };
-// try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
-// }
-// }
+test "struct" {
+ {
+ const Struct = struct {
+ field: u8,
+ };
+ const value = Struct{ .field = 42 };
+ try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{value});
+ try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
+ }
+ {
+ const Struct = struct {
+ a: u0,
+ b: u1,
+ };
+ const value = Struct{ .a = 0, .b = 1 };
+ try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
+ }
+}
-// test "enum" {
-// const Enum = enum {
-// One,
-// Two,
-// };
-// const value = Enum.Two;
-// try testFmt("enum: Enum.Two\n", "enum: {}\n", .{value});
-// try testFmt("enum: Enum.Two\n", "enum: {}\n", .{&value});
-// }
+test "enum" {
+ const Enum = enum {
+ One,
+ Two,
+ };
+ const value = Enum.Two;
+ try testFmt("enum: Enum.Two\n", "enum: {}\n", .{value});
+ try testFmt("enum: Enum.Two\n", "enum: {}\n", .{&value});
+}
-// test "non-exhaustive enum" {
-// const Enum = enum(u16) {
-// One = 0x000f,
-// Two = 0xbeef,
-// _,
-// };
-// try testFmt("enum: Enum(15)\n", "enum: {}\n", .{Enum.One});
-// try testFmt("enum: Enum(48879)\n", "enum: {}\n", .{Enum.Two});
-// try testFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
-// try testFmt("enum: Enum(f)\n", "enum: {x}\n", .{Enum.One});
-// try testFmt("enum: Enum(beef)\n", "enum: {x}\n", .{Enum.Two});
-// try testFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
-// }
+test "non-exhaustive enum" {
+ const Enum = enum(u16) {
+ One = 0x000f,
+ Two = 0xbeef,
+ _,
+ };
+ try testFmt("enum: Enum(15)\n", "enum: {}\n", .{Enum.One});
+ try testFmt("enum: Enum(48879)\n", "enum: {}\n", .{Enum.Two});
+ try testFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
+ try testFmt("enum: Enum(f)\n", "enum: {x}\n", .{Enum.One});
+ try testFmt("enum: Enum(beef)\n", "enum: {x}\n", .{Enum.Two});
+ try testFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
+}
-// test "float.scientific" {
-// try testFmt("f32: 1.34000003e+00", "f32: {e}", .{@as(f32, 1.34)});
-// try testFmt("f32: 1.23400001e+01", "f32: {e}", .{@as(f32, 12.34)});
-// try testFmt("f64: -1.234e+11", "f64: {e}", .{@as(f64, -12.34e10)});
-// try testFmt("f64: 9.99996e-40", "f64: {e}", .{@as(f64, 9.999960e-40)});
-// }
+test "float.scientific" {
+ try testFmt("f32: 1.34000003e+00", "f32: {e}", .{@as(f32, 1.34)});
+ try testFmt("f32: 1.23400001e+01", "f32: {e}", .{@as(f32, 12.34)});
+ try testFmt("f64: -1.234e+11", "f64: {e}", .{@as(f64, -12.34e10)});
+ try testFmt("f64: 9.99996e-40", "f64: {e}", .{@as(f64, 9.999960e-40)});
+}
-// test "float.scientific.precision" {
-// try testFmt("f64: 1.40971e-42", "f64: {e:.5}", .{@as(f64, 1.409706e-42)});
-// try testFmt("f64: 1.00000e-09", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 814313563)))});
-// try testFmt("f64: 7.81250e-03", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1006632960)))});
-// // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
-// // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
-// try testFmt("f64: 1.00001e+05", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1203982400)))});
-// }
+test "float.scientific.precision" {
+ try testFmt("f64: 1.40971e-42", "f64: {e:.5}", .{@as(f64, 1.409706e-42)});
+ try testFmt("f64: 1.00000e-09", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 814313563)))});
+ try testFmt("f64: 7.81250e-03", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1006632960)))});
+ // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
+ // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
+ try testFmt("f64: 1.00001e+05", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1203982400)))});
+}
-// test "float.special" {
-// try testFmt("f64: nan", "f64: {}", .{math.nan_f64});
-// // negative nan is not defined by IEE 754,
-// // and ARM thus normalizes it to positive nan
-// if (builtin.arch != builtin.Arch.arm) {
-// try testFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
-// }
-// try testFmt("f64: inf", "f64: {}", .{math.inf_f64});
-// try testFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
-// }
+test "float.special" {
+ try testFmt("f64: nan", "f64: {}", .{math.nan_f64});
+ // negative nan is not defined by IEE 754,
+ // and ARM thus normalizes it to positive nan
+ if (builtin.arch != builtin.Arch.arm) {
+ try testFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
+ }
+ try testFmt("f64: inf", "f64: {}", .{math.inf_f64});
+ try testFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
+}
-// test "float.decimal" {
-// try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
-// try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
-// try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)});
-// try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)});
-// // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
-// // -11.12339... is rounded back up to -11.1234
-// try testFmt("f32: -11.1234", "f32: {d:.4}", .{@as(f32, -11.1234)});
-// try testFmt("f32: 91.12345", "f32: {d:.5}", .{@as(f32, 91.12345)});
-// try testFmt("f64: 91.1234567890", "f64: {d:.10}", .{@as(f64, 91.12345678901235)});
-// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 0.0)});
-// try testFmt("f64: 6", "f64: {d:.0}", .{@as(f64, 5.700)});
-// try testFmt("f64: 10.0", "f64: {d:.1}", .{@as(f64, 9.999)});
-// try testFmt("f64: 1.000", "f64: {d:.3}", .{@as(f64, 1.0)});
-// try testFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)});
-// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
-// try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
-// }
+test "float.decimal" {
+ try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
+ try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
+ try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)});
+ try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)});
+ // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
+ // -11.12339... is rounded back up to -11.1234
+ try testFmt("f32: -11.1234", "f32: {d:.4}", .{@as(f32, -11.1234)});
+ try testFmt("f32: 91.12345", "f32: {d:.5}", .{@as(f32, 91.12345)});
+ try testFmt("f64: 91.1234567890", "f64: {d:.10}", .{@as(f64, 91.12345678901235)});
+ try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 0.0)});
+ try testFmt("f64: 6", "f64: {d:.0}", .{@as(f64, 5.700)});
+ try testFmt("f64: 10.0", "f64: {d:.1}", .{@as(f64, 9.999)});
+ try testFmt("f64: 1.000", "f64: {d:.3}", .{@as(f64, 1.0)});
+ try testFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)});
+ try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
+ try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
+}
-// test "float.libc.sanity" {
-// try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 916964781)))});
-// try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 925353389)))});
-// try testFmt("f64: 0.10000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1036831278)))});
-// try testFmt("f64: 1.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1065353133)))});
-// try testFmt("f64: 10.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1092616192)))});
+test "float.libc.sanity" {
+ try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 916964781)))});
+ try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 925353389)))});
+ try testFmt("f64: 0.10000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1036831278)))});
+ try testFmt("f64: 1.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1065353133)))});
+ try testFmt("f64: 10.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1092616192)))});
-// // libc differences
-// //
-// // This is 0.015625 exactly according to gdb. We thus round down,
-// // however glibc rounds up for some reason. This occurs for all
-// // floats of the form x.yyyy25 on a precision point.
-// try testFmt("f64: 0.01563", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1015021568)))});
-// // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
-// // also rounds to 630 so I'm inclined to believe libc is not
-// // optimal here.
-// try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1518338049)))});
-// }
+ // libc differences
+ //
+ // This is 0.015625 exactly according to gdb. We thus round down,
+ // however glibc rounds up for some reason. This occurs for all
+ // floats of the form x.yyyy25 on a precision point.
+ try testFmt("f64: 0.01563", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1015021568)))});
+ // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
+ // also rounds to 630 so I'm inclined to believe libc is not
+ // optimal here.
+ try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1518338049)))});
+}
-// test "custom" {
-// const Vec2 = struct {
-// const SelfType = @This();
-// x: f32,
-// y: f32,
+test "custom" {
+ const Vec2 = struct {
+ const SelfType = @This();
+ x: f32,
+ y: f32,
-// pub fn format(
-// self: SelfType,
-// comptime fmt: []const u8,
-// options: FormatOptions,
-// context: var,
-// comptime Errors: type,
-// comptime output: fn (@TypeOf(context), []const u8) !void,
-// ) !void {
-// if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
-// return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
-// } else if (comptime std.mem.eql(u8, fmt, "d")) {
-// return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
-// } else {
-// @compileError("Unknown format character: '" ++ fmt ++ "'");
-// }
-// }
-// };
+ pub fn format(
+ self: SelfType,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ out_stream: var,
+ ) !void {
+ if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
+ return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
+ } else if (comptime std.mem.eql(u8, fmt, "d")) {
+ return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
+ } else {
+ @compileError("Unknown format character: '" ++ fmt ++ "'");
+ }
+ }
+ };
-// var buf1: [32]u8 = undefined;
-// var value = Vec2{
-// .x = 10.2,
-// .y = 2.22,
-// };
-// try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
-// try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
+ var buf1: [32]u8 = undefined;
+ var value = Vec2{
+ .x = 10.2,
+ .y = 2.22,
+ };
+ try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
+ try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
-// // same thing but not passing a pointer
-// try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
-// try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
-// }
+ // same thing but not passing a pointer
+ try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
+ try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
+}
-// test "struct" {
-// const S = struct {
-// a: u32,
-// b: anyerror,
-// };
+test "struct" {
+ const S = struct {
+ a: u32,
+ b: anyerror,
+ };
-// const inst = S{
-// .a = 456,
-// .b = error.Unused,
-// };
+ const inst = S{
+ .a = 456,
+ .b = error.Unused,
+ };
-// try testFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
-// }
+ try testFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
+}
-// test "union" {
-// const TU = union(enum) {
-// float: f32,
-// int: u32,
-// };
+test "union" {
+ const TU = union(enum) {
+ float: f32,
+ int: u32,
+ };
-// const UU = union {
-// float: f32,
-// int: u32,
-// };
+ const UU = union {
+ float: f32,
+ int: u32,
+ };
-// const EU = extern union {
-// float: f32,
-// int: u32,
-// };
+ const EU = extern union {
+ float: f32,
+ int: u32,
+ };
-// const tu_inst = TU{ .int = 123 };
-// const uu_inst = UU{ .int = 456 };
-// const eu_inst = EU{ .float = 321.123 };
+ const tu_inst = TU{ .int = 123 };
+ const uu_inst = UU{ .int = 456 };
+ const eu_inst = EU{ .float = 321.123 };
-// try testFmt("TU{ .int = 123 }", "{}", .{tu_inst});
+ try testFmt("TU{ .int = 123 }", "{}", .{tu_inst});
-// var buf: [100]u8 = undefined;
-// const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
-// std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
+ var buf: [100]u8 = undefined;
+ const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
+ std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
-// const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
-// std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
-// }
+ const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
+ std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
+}
-// test "enum" {
-// const E = enum {
-// One,
-// Two,
-// Three,
-// };
+test "enum" {
+ const E = enum {
+ One,
+ Two,
+ Three,
+ };
-// const inst = E.Two;
+ const inst = E.Two;
-// try testFmt("E.Two", "{}", .{inst});
-// }
+ try testFmt("E.Two", "{}", .{inst});
+}
// test "struct.self-referential" {
// const S = struct {
@@ -1488,20 +1486,20 @@ fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options:
// try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
// }
-// test "struct.zero-size" {
-// const A = struct {
-// fn foo() void {}
-// };
-// const B = struct {
-// a: A,
-// c: i32,
-// };
+test "struct.zero-size" {
+ const A = struct {
+ fn foo() void {}
+ };
+ const B = struct {
+ a: A,
+ c: i32,
+ };
-// const a = A{};
-// const b = B{ .a = a, .c = 0 };
+ const a = A{};
+ const b = B{ .a = a, .c = 0 };
-// try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
-// }
+ try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
+}
test "bytes.hex" {
const some_bytes = "\xCA\xFE\xBA\xBE";
@@ -1527,66 +1525,66 @@ fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void
return error.TestFailed;
}
-// pub fn trim(buf: []const u8) []const u8 {
-// var start: usize = 0;
-// while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
+pub fn trim(buf: []const u8) []const u8 {
+ var start: usize = 0;
+ while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
-// var end: usize = buf.len;
-// while (true) {
-// if (end > start) {
-// const new_end = end - 1;
-// if (isWhiteSpace(buf[new_end])) {
-// end = new_end;
-// continue;
-// }
-// }
-// break;
-// }
-// return buf[start..end];
-// }
+ var end: usize = buf.len;
+ while (true) {
+ if (end > start) {
+ const new_end = end - 1;
+ if (isWhiteSpace(buf[new_end])) {
+ end = new_end;
+ continue;
+ }
+ }
+ break;
+ }
+ return buf[start..end];
+}
-// test "trim" {
-// std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
-// std.testing.expect(mem.eql(u8, "", trim(" ")));
-// std.testing.expect(mem.eql(u8, "", trim("")));
-// std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
-// std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
-// }
+test "trim" {
+ std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
+ std.testing.expect(mem.eql(u8, "", trim(" ")));
+ std.testing.expect(mem.eql(u8, "", trim("")));
+ std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
+ std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
+}
-// pub fn isWhiteSpace(byte: u8) bool {
-// return switch (byte) {
-// ' ', '\t', '\n', '\r' => true,
-// else => false,
-// };
-// }
+pub fn isWhiteSpace(byte: u8) bool {
+ return switch (byte) {
+ ' ', '\t', '\n', '\r' => true,
+ else => false,
+ };
+}
-// pub fn hexToBytes(out: []u8, input: []const u8) !void {
-// if (out.len * 2 < input.len)
-// return error.InvalidLength;
+pub fn hexToBytes(out: []u8, input: []const u8) !void {
+ if (out.len * 2 < input.len)
+ return error.InvalidLength;
-// var in_i: usize = 0;
-// while (in_i != input.len) : (in_i += 2) {
-// const hi = try charToDigit(input[in_i], 16);
-// const lo = try charToDigit(input[in_i + 1], 16);
-// out[in_i / 2] = (hi << 4) | lo;
-// }
-// }
+ var in_i: usize = 0;
+ while (in_i != input.len) : (in_i += 2) {
+ const hi = try charToDigit(input[in_i], 16);
+ const lo = try charToDigit(input[in_i + 1], 16);
+ out[in_i / 2] = (hi << 4) | lo;
+ }
+}
-// test "hexToBytes" {
-// const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
-// var pb: [32]u8 = undefined;
-// try hexToBytes(pb[0..], test_hex_str);
-// try testFmt(test_hex_str, "{X}", .{pb});
-// }
+test "hexToBytes" {
+ const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
+ var pb: [32]u8 = undefined;
+ try hexToBytes(pb[0..], test_hex_str);
+ try testFmt(test_hex_str, "{X}", .{pb});
+}
-// test "formatIntValue with comptime_int" {
-// const value: comptime_int = 123456789123456789;
+test "formatIntValue with comptime_int" {
+ const value: comptime_int = 123456789123456789;
-// var buf = std.ArrayList(u8).init(std.testing.allocator);
-// defer buf.deinit();
-// try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
-// std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
-// }
+ var buf: [20]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buf);
+ try formatIntValue(value, "", FormatOptions{}, fbs.outStream());
+ std.testing.expect(mem.eql(u8, buf[0..fbs.pos], "123456789123456789"));
+}
// test "formatType max_depth" {
// const Vec2 = struct {
@@ -1658,39 +1656,39 @@ fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void
// std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
// }
-// test "positional" {
-// try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
-// try testFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
-// try testFmt("0 0", "{0} {0}", .{@as(usize, 0)});
-// try testFmt("0 1", "{} {1}", .{ @as(usize, 0), @as(usize, 1) });
-// try testFmt("1 0 0 1", "{1} {} {0} {}", .{ @as(usize, 0), @as(usize, 1) });
-// }
+test "positional" {
+ try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
+ try testFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
+ try testFmt("0 0", "{0} {0}", .{@as(usize, 0)});
+ try testFmt("0 1", "{} {1}", .{ @as(usize, 0), @as(usize, 1) });
+ try testFmt("1 0 0 1", "{1} {} {0} {}", .{ @as(usize, 0), @as(usize, 1) });
+}
-// test "positional with specifier" {
-// try testFmt("10.0", "{0d:.1}", .{@as(f64, 9.999)});
-// }
+test "positional with specifier" {
+ try testFmt("10.0", "{0d:.1}", .{@as(f64, 9.999)});
+}
-// test "positional/alignment/width/precision" {
-// try testFmt("10.0", "{0d: >3.1}", .{@as(f64, 9.999)});
-// }
+test "positional/alignment/width/precision" {
+ try testFmt("10.0", "{0d: >3.1}", .{@as(f64, 9.999)});
+}
-// test "vector" {
-// // https://github.com/ziglang/zig/issues/3317
-// if (builtin.arch == .mipsel) return error.SkipZigTest;
+test "vector" {
+ // https://github.com/ziglang/zig/issues/3317
+ if (builtin.arch == .mipsel) return error.SkipZigTest;
-// const vbool: @Vector(4, bool) = [_]bool{ true, false, true, false };
-// const vi64: @Vector(4, i64) = [_]i64{ -2, -1, 0, 1 };
-// const vu64: @Vector(4, u64) = [_]u64{ 1000, 2000, 3000, 4000 };
+ const vbool: @Vector(4, bool) = [_]bool{ true, false, true, false };
+ const vi64: @Vector(4, i64) = [_]i64{ -2, -1, 0, 1 };
+ const vu64: @Vector(4, u64) = [_]u64{ 1000, 2000, 3000, 4000 };
-// try testFmt("{ true, false, true, false }", "{}", .{vbool});
-// try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
-// try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
-// try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
-// try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
-// try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
-// try testFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
-// }
+ try testFmt("{ true, false, true, false }", "{}", .{vbool});
+ try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
+ try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
+ try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
+ try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
+ try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
+ try testFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
+}
-// test "enum-literal" {
-// try testFmt(".hello_world", "{}", .{.hello_world});
-// }
+test "enum-literal" {
+ try testFmt(".hello_world", "{}", .{.hello_world});
+}
From f51c8f26c195819bb49a641c82ee65bb2f8e3044 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 15:02:29 -0600
Subject: [PATCH 078/111] Apply explicit error type
---
lib/std/fmtstream.zig | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index 3a2767c85..ff7c492a1 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -316,7 +316,7 @@ pub fn formatType(
options: FormatOptions,
out_stream: var,
max_depth: usize,
-) !void {
+) @TypeOf(out_stream).Error!void {
if (comptime std.mem.eql(u8, fmt, "*")) {
try out_stream.writeAll(@typeName(@TypeOf(value).Child));
try out_stream.writeAll("@");
@@ -1472,19 +1472,19 @@ test "enum" {
try testFmt("E.Two", "{}", .{inst});
}
-// test "struct.self-referential" {
-// const S = struct {
-// const SelfType = @This();
-// a: ?*SelfType,
-// };
+test "struct.self-referential" {
+ const S = struct {
+ const SelfType = @This();
+ a: ?*SelfType,
+ };
-// var inst = S{
-// .a = null,
-// };
-// inst.a = &inst;
+ var inst = S{
+ .a = null,
+ };
+ inst.a = &inst;
-// try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
-// }
+ try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
+}
test "struct.zero-size" {
const A = struct {
From 1c18ab01a44bf3cbef356ff215e97dfe2788265b Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 15:10:27 -0600
Subject: [PATCH 079/111] Add back max_depth test
---
lib/std/fmtstream.zig | 138 ++++++++++++++++++++----------------------
1 file changed, 66 insertions(+), 72 deletions(-)
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index ff7c492a1..c062bbaa1 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -1083,6 +1083,8 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]
format(fbs.outStream(), fmt, args) catch |err| switch (err) {
error.NoSpaceLeft => return error.BufferTooSmall,
};
+ //TODO: should we change one of these return signatures?
+ //return fbs.getWritten();
return buf[0..fbs.pos];
}
@@ -1195,18 +1197,15 @@ test "buffer" {
var buf1: [32]u8 = undefined;
var fbs = std.io.fixedBufferStream(&buf1);
try formatType(1234, "", FormatOptions{}, fbs.outStream(), default_max_depth);
- var res = buf1[0..fbs.pos];
- std.testing.expect(mem.eql(u8, res, "1234"));
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
- try fbs.seekTo(0);
+ fbs.reset();
try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth);
- res = buf1[0..fbs.pos];
- std.testing.expect(mem.eql(u8, res, "a"));
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "a"));
- try fbs.seekTo(0);
+ fbs.reset();
try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth);
- res = buf1[0..fbs.pos];
- std.testing.expect(mem.eql(u8, res, "1100"));
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100"));
}
}
@@ -1583,78 +1582,73 @@ test "formatIntValue with comptime_int" {
var buf: [20]u8 = undefined;
var fbs = std.io.fixedBufferStream(&buf);
try formatIntValue(value, "", FormatOptions{}, fbs.outStream());
- std.testing.expect(mem.eql(u8, buf[0..fbs.pos], "123456789123456789"));
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789"));
}
-// test "formatType max_depth" {
-// const Vec2 = struct {
-// const SelfType = @This();
-// x: f32,
-// y: f32,
+test "formatType max_depth" {
+ const Vec2 = struct {
+ const SelfType = @This();
+ x: f32,
+ y: f32,
-// pub fn format(
-// self: SelfType,
-// comptime fmt: []const u8,
-// options: FormatOptions,
-// context: var,
-// comptime Errors: type,
-// comptime output: fn (@TypeOf(context), []const u8) !void,
-// ) !void {
-// if (fmt.len == 0) {
-// return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
-// } else {
-// @compileError("Unknown format string: '" ++ fmt ++ "'");
-// }
-// }
-// };
-// const E = enum {
-// One,
-// Two,
-// Three,
-// };
-// const TU = union(enum) {
-// const SelfType = @This();
-// float: f32,
-// int: u32,
-// ptr: ?*SelfType,
-// };
-// const S = struct {
-// const SelfType = @This();
-// a: ?*SelfType,
-// tu: TU,
-// e: E,
-// vec: Vec2,
-// };
+ pub fn format(
+ self: SelfType,
+ comptime fmt: []const u8,
+ options: FormatOptions,
+ out_stream: var,
+ ) !void {
+ if (fmt.len == 0) {
+ return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
+ } else {
+ @compileError("Unknown format string: '" ++ fmt ++ "'");
+ }
+ }
+ };
+ const E = enum {
+ One,
+ Two,
+ Three,
+ };
+ const TU = union(enum) {
+ const SelfType = @This();
+ float: f32,
+ int: u32,
+ ptr: ?*SelfType,
+ };
+ const S = struct {
+ const SelfType = @This();
+ a: ?*SelfType,
+ tu: TU,
+ e: E,
+ vec: Vec2,
+ };
-// var inst = S{
-// .a = null,
-// .tu = TU{ .ptr = null },
-// .e = E.Two,
-// .vec = Vec2{ .x = 10.2, .y = 2.22 },
-// };
-// inst.a = &inst;
-// inst.tu.ptr = &inst.tu;
+ var inst = S{
+ .a = null,
+ .tu = TU{ .ptr = null },
+ .e = E.Two,
+ .vec = Vec2{ .x = 10.2, .y = 2.22 },
+ };
+ inst.a = &inst;
+ inst.tu.ptr = &inst.tu;
-// var buf0 = std.ArrayList(u8).init(std.testing.allocator);
-// defer buf0.deinit();
-// try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
-// std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
+ var buf: [1000]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buf);
+ try formatType(inst, "", FormatOptions{}, fbs.outStream(), 0);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));
-// var buf1 = std.ArrayList(u8).init(std.testing.allocator);
-// defer buf1.deinit();
-// try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
-// std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
+ fbs.reset();
+ try formatType(inst, "", FormatOptions{}, fbs.outStream(), 1);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
-// var buf2 = std.ArrayList(u8).init(std.testing.allocator);
-// defer buf2.deinit();
-// try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
-// std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
+ fbs.reset();
+ try formatType(inst, "", FormatOptions{}, fbs.outStream(), 2);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
-// var buf3 = std.ArrayList(u8).init(std.testing.allocator);
-// defer buf3.deinit();
-// try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
-// std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
-// }
+ fbs.reset();
+ try formatType(inst, "", FormatOptions{}, fbs.outStream(), 3);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
+}
test "positional" {
try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
From 710b05b15302f05f98a31635af6d654858215f34 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 12 Mar 2020 16:46:16 +0200
Subject: [PATCH 080/111] support `@atomicRmw` at comptime
---
src/ir.cpp | 82 +++++++++++++++++++++++++++++---
test/compile_errors.zig | 18 +++----
test/stage1/behavior/atomics.zig | 29 +++++++++++
3 files changed, 114 insertions(+), 15 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index dc3e7941d..4f139895b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -28436,14 +28436,84 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
return ir_const_move(ira, &instruction->base.base, get_the_one_possible_value(ira->codegen, operand_type));
}
- if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar)
- {
- ir_add_error(ira, &instruction->base.base,
- buf_sprintf("compiler bug: TODO compile-time execution of @atomicRmw"));
- return ira->codegen->invalid_inst_gen;
+ IrInst *source_inst = &instruction->base.base;
+ if (instr_is_comptime(casted_operand) && instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar) {
+ ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ ZigValue *op1_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.base.source_node);
+ if (op1_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ ZigValue *op2_val = ir_resolve_const(ira, casted_operand, UndefBad);
+ if (op2_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ if (op == AtomicRmwOp_xchg) {
+ ir_analyze_store_ptr(ira, source_inst, casted_ptr, casted_operand, false);
+ return ir_const_move(ira, source_inst, op1_val);
+ }
+
+ if (operand_type->id == ZigTypeIdPointer || operand_type->id == ZigTypeIdOptional) {
+ ir_add_error(ira, &instruction->ordering->base,
+ buf_sprintf("TODO comptime @atomicRmw with pointers other than .Xchg"));
+ return ira->codegen->invalid_inst_gen;
+ }
+
+ if (op == AtomicRmwOp_min || op == AtomicRmwOp_max) {
+ IrBinOp bin_op;
+ if (op == AtomicRmwOp_min)
+ // store op2 if op2 < op1
+ bin_op = IrBinOpCmpGreaterThan;
+ else
+ // store op2 if op2 > op1
+ bin_op = IrBinOpCmpLessThan;
+
+ IrInstGen *dummy_value = ir_const(ira, source_inst, operand_type);
+ ir_eval_bin_op_cmp_scalar(ira, source_inst, op1_val, bin_op, op2_val, dummy_value->value);
+ if (dummy_value->value->data.x_bool)
+ ir_analyze_store_ptr(ira, source_inst, casted_ptr, casted_operand, false);
+ } else {
+ IrBinOp bin_op;
+ switch (op) {
+ case AtomicRmwOp_xchg:
+ case AtomicRmwOp_max:
+ case AtomicRmwOp_min:
+ zig_unreachable();
+ case AtomicRmwOp_add:
+ if (operand_type->id == ZigTypeIdFloat)
+ bin_op = IrBinOpAdd;
+ else
+ bin_op = IrBinOpAddWrap;
+ break;
+ case AtomicRmwOp_sub:
+ if (operand_type->id == ZigTypeIdFloat)
+ bin_op = IrBinOpSub;
+ else
+ bin_op = IrBinOpSubWrap;
+ break;
+ case AtomicRmwOp_and:
+ case AtomicRmwOp_nand:
+ bin_op = IrBinOpBinAnd;
+ break;
+ case AtomicRmwOp_or:
+ bin_op = IrBinOpBinOr;
+ break;
+ case AtomicRmwOp_xor:
+ bin_op = IrBinOpBinXor;
+ break;
+ }
+ ir_eval_math_op_scalar(ira, source_inst, operand_type, op1_val, bin_op, op2_val, op1_val);
+ if (op == AtomicRmwOp_nand) {
+ bigint_not(&op1_val->data.x_bigint, &op1_val->data.x_bigint,
+ operand_type->data.integral.bit_count, operand_type->data.integral.is_signed);
+ }
+ }
+ return ir_const_move(ira, source_inst, op1_val);
}
- return ir_build_atomic_rmw_gen(ira, &instruction->base.base, casted_ptr, casted_operand, op,
+ return ir_build_atomic_rmw_gen(ira, source_inst, casted_ptr, casted_operand, op,
ordering, operand_type);
}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 28529b3f5..2881c7f65 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2,15 +2,6 @@ const tests = @import("tests.zig");
const std = @import("std");
pub fn addCases(cases: *tests.CompileErrorContext) void {
- cases.add("atomicrmw with bool op not .Xchg",
- \\export fn entry() void {
- \\ var x = false;
- \\ _ = @atomicRmw(bool, &x, .Add, true, .SeqCst);
- \\}
- , &[_][]const u8{
- "tmp.zig:3:30: error: @atomicRmw with bool only allowed with .Xchg",
- });
-
cases.addTest("combination of noasync and async",
\\export fn entry() void {
\\ noasync {
@@ -26,6 +17,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:5:9: error: resume in noasync scope",
});
+ cases.add("atomicrmw with bool op not .Xchg",
+ \\export fn entry() void {
+ \\ var x = false;
+ \\ _ = @atomicRmw(bool, &x, .Add, true, .SeqCst);
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:3:30: error: @atomicRmw with bool only allowed with .Xchg",
+ });
+
cases.addTest("@TypeOf with no arguments",
\\export fn entry() void {
\\ _ = @TypeOf();
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index c655bfe7a..aca5593c6 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -149,6 +149,7 @@ fn testAtomicStore() void {
}
test "atomicrmw with floats" {
+ comptime testAtomicRmwFloat();
if (builtin.arch == .aarch64 or builtin.arch == .arm or builtin.arch == .riscv64)
return error.SkipZigTest;
testAtomicRmwFloat();
@@ -165,6 +166,34 @@ fn testAtomicRmwFloat() void {
expect(x == 4);
}
+test "atomicrmw with ints" {
+ testAtomicRmwFloat();
+ comptime testAtomicRmwFloat();
+}
+
+fn testAtomicRmwInt() void {
+ var x: u8 = 1;
+ _ = @atomicRmw(u8, &x, .Xchg, 3, .SeqCst);
+ expect(x == 3);
+ _ = @atomicRmw(u8, &x, .Add, 3, .SeqCst);
+ expect(x == 6);
+ _ = @atomicRmw(u8, &x, .Sub, 1, .SeqCst);
+ expect(x == 5);
+ _ = @atomicRmw(u8, &x, .And, 4, .SeqCst);
+ expect(x == 4);
+ _ = @atomicRmw(u8, &x, .Nand, 4, .SeqCst);
+ expect(x == 0xfb);
+ _ = @atomicRmw(u8, &x, .Or, 6, .SeqCst);
+ expect(x == 0xff);
+ _ = @atomicRmw(u8, &x, .Xor, 2, .SeqCst);
+ expect(x == 0xfd);
+ _ = @atomicRmw(u8, &x, .Max, 1, .SeqCst);
+ expect(x == 0xfd);
+ _ = @atomicRmw(u8, &x, .Min, 1, .SeqCst);
+ expect(x == 1);
+}
+
+
test "atomics with different types" {
testAtomicsWithType(bool, true, false);
inline for (.{ u1, i5, u15 }) |T| {
From 02c491e42affedf6dd33e75a456531bb60aff8a3 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 12 Mar 2020 17:14:01 +0200
Subject: [PATCH 081/111] translate-c fix order of tokens
---
src-self-hosted/translate_c.zig | 9 +++++----
test/translate_c.zig | 8 ++++++++
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index 934ed3634..40e7d7f79 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -5375,7 +5375,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
const first_tok = it.list.at(0);
const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));
const node = try c.a().create(ast.Node.CharLiteral);
- node.* = ast.Node.CharLiteral{
+ node.* = .{
.token = token,
};
return &node.base;
@@ -5384,7 +5384,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
const first_tok = it.list.at(0);
const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));
const node = try c.a().create(ast.Node.StringLiteral);
- node.* = ast.Node.StringLiteral{
+ node.* = .{
.token = token,
};
return &node.base;
@@ -5793,12 +5793,13 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
return node;
},
}
+ const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
+ const lhs_node = try cast_fn(c, node);
const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
const op_node = try c.a().create(ast.Node.InfixOp);
- const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
op_node.* = .{
.op_token = op_token,
- .lhs = try cast_fn(c, node),
+ .lhs = lhs_node,
.op = op_id,
.rhs = try cast_fn(c, rhs_node),
};
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 29b07b86a..9890c4034 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -3,6 +3,14 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void {
+ cases.add("correct semicolon after infixop",
+ \\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)
+ , &[_][]const u8{
+ \\pub inline fn __ferror_unlocked_body(_fp: var) @TypeOf(((_fp.*._flags) & _IO_ERR_SEEN) != 0) {
+ \\ return ((_fp.*._flags) & _IO_ERR_SEEN) != 0;
+ \\}
+ });
+
cases.add("c booleans are just ints",
\\#define FOO(x) ((x >= 0) + (x >= 0))
\\#define BAR 1 && 2 > 4
From d2e4aafd64184017dc1f152a4b46eeafca94bbd8 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 15:16:04 -0600
Subject: [PATCH 082/111] Fixup allocPrint
---
lib/std/fmtstream.zig | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index c062bbaa1..806ee3d04 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -1088,25 +1088,23 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]
return buf[0..fbs.pos];
}
-// pub const AllocPrintError = error{OutOfMemory};
+pub const AllocPrintError = error{OutOfMemory};
-// pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
-// var size: usize = 0;
-// format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
-// const buf = try allocator.alloc(u8, size);
-// return bufPrint(buf, fmt, args) catch |err| switch (err) {
-// error.BufferTooSmall => unreachable, // we just counted the size above
-// };
-// }
+pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
+ // Count the characters we need to preallocate
+ var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
+ format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
-// fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
-// size.* += bytes.len;
-// }
+ const buf = try allocator.alloc(u8, counting_stream.bytes_written);
+ return bufPrint(buf, fmt, args) catch |err| switch (err) {
+ error.BufferTooSmall => unreachable, // we just counted the size above
+ };
+}
-// pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
-// const result = try allocPrint(allocator, fmt ++ "\x00", args);
-// return result[0 .. result.len - 1 :0];
-// }
+pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
+ const result = try allocPrint(allocator, fmt ++ "\x00", args);
+ return result[0 .. result.len - 1 :0];
+}
test "bufPrintInt" {
var buffer: [100]u8 = undefined;
From 7364e965f473147a86cc62ccf47feac4878a15de Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 15:24:03 -0600
Subject: [PATCH 083/111] Force error coercion of custom formatters
---
lib/std/fmtstream.zig | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index 806ee3d04..8db0052a7 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -325,6 +325,10 @@ pub fn formatType(
}
const T = @TypeOf(value);
+ if (comptime std.meta.trait.hasFn("format")(T)) {
+ return try value.format(fmt, options, out_stream);
+ }
+
switch (@typeInfo(T)) {
.ComptimeInt, .Int, .Float => {
return formatValue(value, fmt, options, out_stream);
@@ -354,10 +358,6 @@ pub fn formatType(
return out_stream.writeAll(@errorName(value));
},
.Enum => |enumInfo| {
- if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, out_stream);
- }
-
try out_stream.writeAll(@typeName(T));
if (enumInfo.is_exhaustive) {
try out_stream.writeAll(".");
@@ -370,10 +370,6 @@ pub fn formatType(
}
},
.Union => {
- if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, out_stream);
- }
-
try out_stream.writeAll(@typeName(T));
if (max_depth == 0) {
return out_stream.writeAll("{ ... }");
@@ -394,10 +390,6 @@ pub fn formatType(
}
},
.Struct => |StructT| {
- if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, out_stream);
- }
-
try out_stream.writeAll(@typeName(T));
if (max_depth == 0) {
return out_stream.writeAll("{ ... }");
From c11d1055b868add74cc58f3bf745e93110ae6071 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 15:35:18 -0600
Subject: [PATCH 084/111] Integrated outstreams with new formatter
---
lib/std/http/headers.zig | 18 ++++++++----------
lib/std/io/out_stream.zig | 2 +-
lib/std/math/big/int.zig | 8 +++-----
lib/std/net.zig | 22 ++++++++++------------
lib/std/net/test.zig | 4 ++--
lib/std/os/uefi.zig | 10 +++-------
6 files changed, 27 insertions(+), 37 deletions(-)
diff --git a/lib/std/http/headers.zig b/lib/std/http/headers.zig
index a7a1464f9..cb232a3e3 100644
--- a/lib/std/http/headers.zig
+++ b/lib/std/http/headers.zig
@@ -349,16 +349,14 @@ pub const Headers = struct {
pub fn format(
self: Self,
comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
- context: var,
- comptime Errors: type,
- output: fn (@TypeOf(context), []const u8) Errors!void,
- ) Errors!void {
+ options: std.fmtstream.FormatOptions,
+ out_stream: var,
+ ) !void {
for (self.toSlice()) |entry| {
- try output(context, entry.name);
- try output(context, ": ");
- try output(context, entry.value);
- try output(context, "\n");
+ try out_stream.writeAll(entry.name);
+ try out_stream.writeAll(": ");
+ try out_stream.writeAll(entry.value);
+ try out_stream.writeAll("\n");
}
}
};
@@ -593,5 +591,5 @@ test "Headers.format" {
\\foo: bar
\\cookie: somevalue
\\
- , try std.fmt.bufPrint(buf[0..], "{}", .{h}));
+ , try std.fmtstream.bufPrint(buf[0..], "{}", .{h}));
}
diff --git a/lib/std/io/out_stream.zig b/lib/std/io/out_stream.zig
index 03901f667..876a3b470 100644
--- a/lib/std/io/out_stream.zig
+++ b/lib/std/io/out_stream.zig
@@ -25,7 +25,7 @@ pub fn OutStream(
}
pub fn print(self: Self, comptime format: []const u8, args: var) Error!void {
- return std.fmt.format(self, Error, writeAll, format, args);
+ return std.fmtstream.format(self, format, args);
}
pub fn writeByte(self: Self, byte: u8) Error!void {
diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig
index 8fda3f647..cef2bae98 100644
--- a/lib/std/math/big/int.zig
+++ b/lib/std/math/big/int.zig
@@ -518,17 +518,15 @@ pub const Int = struct {
pub fn format(
self: Int,
comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
- context: var,
- comptime FmtError: type,
- output: fn (@TypeOf(context), []const u8) FmtError!void,
+ options: std.fmtstream.FormatOptions,
+ out_stream: var,
) FmtError!void {
self.assertWritable();
// TODO look at fmt and support other bases
// TODO support read-only fixed integers
const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating");
defer self.allocator.?.free(str);
- return output(context, str);
+ return out_stream.print(str);
}
/// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
diff --git a/lib/std/net.zig b/lib/std/net.zig
index de10a1764..9395d34f4 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -268,16 +268,14 @@ pub const Address = extern union {
pub fn format(
self: Address,
comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ options: std.fmtstream.FormatOptions,
+ out_stream: var,
) !void {
switch (self.any.family) {
os.AF_INET => {
const port = mem.bigToNative(u16, self.in.port);
const bytes = @ptrCast(*const [4]u8, &self.in.addr);
- try std.fmt.format(context, Errors, output, "{}.{}.{}.{}:{}", .{
+ try std.fmtstream.format(out_stream, "{}.{}.{}.{}:{}", .{
bytes[0],
bytes[1],
bytes[2],
@@ -288,7 +286,7 @@ pub const Address = extern union {
os.AF_INET6 => {
const port = mem.bigToNative(u16, self.in6.port);
if (mem.eql(u8, self.in6.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {
- try std.fmt.format(context, Errors, output, "[::ffff:{}.{}.{}.{}]:{}", .{
+ try std.fmtstream.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{
self.in6.addr[12],
self.in6.addr[13],
self.in6.addr[14],
@@ -308,30 +306,30 @@ pub const Address = extern union {
break :blk buf;
},
};
- try output(context, "[");
+ try out_stream.writeAll("[");
var i: usize = 0;
var abbrv = false;
while (i < native_endian_parts.len) : (i += 1) {
if (native_endian_parts[i] == 0) {
if (!abbrv) {
- try output(context, if (i == 0) "::" else ":");
+ try out_stream.writeAll(if (i == 0) "::" else ":");
abbrv = true;
}
continue;
}
- try std.fmt.format(context, Errors, output, "{x}", .{native_endian_parts[i]});
+ try std.fmtstream.format(out_stream, "{x}", .{native_endian_parts[i]});
if (i != native_endian_parts.len - 1) {
- try output(context, ":");
+ try out_stream.writeAll(":");
}
}
- try std.fmt.format(context, Errors, output, "]:{}", .{port});
+ try std.fmtstream.format(out_stream, "]:{}", .{port});
},
os.AF_UNIX => {
if (!has_unix_sockets) {
unreachable;
}
- try std.fmt.format(context, Errors, output, "{}", .{&self.un.path});
+ try std.fmtstream.format(out_stream, "{}", .{&self.un.path});
},
else => unreachable,
}
diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig
index 087f965c4..0dc3b3020 100644
--- a/lib/std/net/test.zig
+++ b/lib/std/net/test.zig
@@ -29,7 +29,7 @@ test "parse and render IPv6 addresses" {
};
for (ips) |ip, i| {
var addr = net.Address.parseIp6(ip, 0) catch unreachable;
- var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
+ var newIp = std.fmtstream.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
std.testing.expect(std.mem.eql(u8, printed[i], newIp[1 .. newIp.len - 3]));
}
@@ -51,7 +51,7 @@ test "parse and render IPv4 addresses" {
"127.0.0.1",
}) |ip| {
var addr = net.Address.parseIp4(ip, 0) catch unreachable;
- var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
+ var newIp = std.fmtstream.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
}
diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig
index 81d13ac1c..5d9a678ce 100644
--- a/lib/std/os/uefi.zig
+++ b/lib/std/os/uefi.zig
@@ -5,8 +5,6 @@ pub const protocols = @import("uefi/protocols.zig");
pub const status = @import("uefi/status.zig");
pub const tables = @import("uefi/tables.zig");
-const fmt = @import("std").fmt;
-
/// The EFI image's handle that is passed to its entry point.
pub var handle: Handle = undefined;
@@ -29,13 +27,11 @@ pub const Guid = extern struct {
pub fn format(
self: @This(),
comptime f: []const u8,
- options: fmt.FormatOptions,
- context: var,
- comptime Errors: type,
- output: fn (@TypeOf(context), []const u8) Errors!void,
+ options: std.fmtstream.FormatOptions,
+ out_stream: var,
) Errors!void {
if (f.len == 0) {
- return fmt.format(context, Errors, output, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
+ return std.fmtstream.format(out_stream, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
self.time_low,
self.time_mid,
self.time_high_and_version,
From ce19638cd4690a8ac01a04500fcc525341d0de78 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 12 Mar 2020 17:31:10 +0200
Subject: [PATCH 085/111] disable test on mipsel
---
test/stage1/behavior/atomics.zig | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index aca5593c6..36751e7d2 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -149,10 +149,10 @@ fn testAtomicStore() void {
}
test "atomicrmw with floats" {
- comptime testAtomicRmwFloat();
if (builtin.arch == .aarch64 or builtin.arch == .arm or builtin.arch == .riscv64)
return error.SkipZigTest;
testAtomicRmwFloat();
+ comptime testAtomicRmwFloat();
}
fn testAtomicRmwFloat() void {
@@ -167,8 +167,10 @@ fn testAtomicRmwFloat() void {
}
test "atomicrmw with ints" {
- testAtomicRmwFloat();
- comptime testAtomicRmwFloat();
+ if (builtin.arch == .mipsel)
+ return error.SkipZigTest;
+ testAtomicRmwInt();
+ comptime testAtomicRmwInt();
}
fn testAtomicRmwInt() void {
From 214af69814b3940236ace44ada0243726d29debf Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 12 Mar 2020 11:40:44 -0400
Subject: [PATCH 086/111] ci: remove workaround for FreeBSD upstream bug
---
ci/srht/freebsd_script | 7 -------
1 file changed, 7 deletions(-)
diff --git a/ci/srht/freebsd_script b/ci/srht/freebsd_script
index 969e644d5..12cd2d540 100755
--- a/ci/srht/freebsd_script
+++ b/ci/srht/freebsd_script
@@ -3,13 +3,6 @@
set -x
set -e
-# The following line can be removed as soon as FreeBSD fixes
-# their packaging glitch. If not fixed by March 15, 2020
-# there is something wrong. Should be fixed much sooner.
-# note: this will cause some complaints when running
-# pkg commands but let's ignore them.
-sudo rm /usr/local/etc/pkg/repos/FreeBSD.conf
-
sudo pkg update -fq
sudo pkg install -y cmake py27-s3cmd wget curl jq
From 0fbccec000efcfe23188027e474530641daf67cd Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Fri, 6 Mar 2020 08:59:21 -0600
Subject: [PATCH 087/111] Convert builtin to fmtstream
---
lib/std/builtin.zig | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index fa5b49db3..5cac8c962 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -426,29 +426,27 @@ pub const Version = struct {
pub fn parse(text: []const u8) !Version {
var it = std.mem.separate(text, ".");
return Version{
- .major = try std.fmt.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
- .minor = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
- .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
+ .major = try std.fmtstream.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
+ .minor = try std.fmtstream.parseInt(u32, it.next() orelse "0", 10),
+ .patch = try std.fmtstream.parseInt(u32, it.next() orelse "0", 10),
};
}
pub fn format(
self: Version,
comptime fmt: []const u8,
- options: std.fmt.FormatOptions,
- context: var,
- comptime Error: type,
- comptime output: fn (@TypeOf(context), []const u8) Error!void,
- ) Error!void {
+ options: std.fmtstream.FormatOptions,
+ out_stream: var,
+ ) !void {
if (fmt.len == 0) {
if (self.patch == 0) {
if (self.minor == 0) {
- return std.fmt.format(context, Error, output, "{}", .{self.major});
+ return std.fmtstream.format(out_stream, "{}", .{self.major});
} else {
- return std.fmt.format(context, Error, output, "{}.{}", .{ self.major, self.minor });
+ return std.fmtstream.format(out_stream, "{}.{}", .{ self.major, self.minor });
}
} else {
- return std.fmt.format(context, Error, output, "{}.{}.{}", .{ self.major, self.minor, self.patch });
+ return std.fmtstream.format(out_stream, "{}.{}.{}", .{ self.major, self.minor, self.patch });
}
} else {
@compileError("Unknown format string: '" ++ fmt ++ "'");
From 2429fdd73bc2405034805893f169ae58c1c34c56 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 18:59:16 -0600
Subject: [PATCH 088/111] Convert JSON to fmtstream
---
lib/std/json.zig | 134 +++++++++++++++++++++++++----------------------
1 file changed, 72 insertions(+), 62 deletions(-)
diff --git a/lib/std/json.zig b/lib/std/json.zig
index 4e2440d4e..f3a081107 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -2252,45 +2252,43 @@ pub const StringifyOptions = struct {
pub fn stringify(
value: var,
options: StringifyOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
const T = @TypeOf(value);
switch (@typeInfo(T)) {
.Float, .ComptimeFloat => {
- return std.fmt.formatFloatScientific(value, std.fmt.FormatOptions{}, context, Errors, output);
+ return std.fmtstream.formatFloatScientific(value, std.fmtstream.FormatOptions{}, out_stream);
},
.Int, .ComptimeInt => {
- return std.fmt.formatIntValue(value, "", std.fmt.FormatOptions{}, context, Errors, output);
+ return std.fmtstream.formatIntValue(value, "", std.fmtstream.FormatOptions{}, out_stream);
},
.Bool => {
- return output(context, if (value) "true" else "false");
+ return out_stream.writeAll(if (value) "true" else "false");
},
.Optional => {
if (value) |payload| {
- return try stringify(payload, options, context, Errors, output);
+ return try stringify(payload, options, out_stream);
} else {
- return output(context, "null");
+ return out_stream.writeAll("null");
}
},
.Enum => {
if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
- return value.jsonStringify(options, context, Errors, output);
+ return value.jsonStringify(options, out_stream);
}
@compileError("Unable to stringify enum '" ++ @typeName(T) ++ "'");
},
.Union => {
if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
- return value.jsonStringify(options, context, Errors, output);
+ return value.jsonStringify(options, out_stream);
}
const info = @typeInfo(T).Union;
if (info.tag_type) |UnionTagType| {
inline for (info.fields) |u_field| {
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
- return try stringify(@field(value, u_field.name), options, context, Errors, output);
+ return try stringify(@field(value, u_field.name), options, out_stream);
}
}
} else {
@@ -2299,10 +2297,10 @@ pub fn stringify(
},
.Struct => |S| {
if (comptime std.meta.trait.hasFn("jsonStringify")(T)) {
- return value.jsonStringify(options, context, Errors, output);
+ return value.jsonStringify(options, out_stream);
}
- try output(context, "{");
+ try out_stream.writeAll("{");
comptime var field_output = false;
inline for (S.fields) |Field, field_i| {
// don't include void fields
@@ -2311,39 +2309,39 @@ pub fn stringify(
if (!field_output) {
field_output = true;
} else {
- try output(context, ",");
+ try out_stream.writeAll(",");
}
- try stringify(Field.name, options, context, Errors, output);
- try output(context, ":");
- try stringify(@field(value, Field.name), options, context, Errors, output);
+ try stringify(Field.name, options, out_stream);
+ try out_stream.writeAll(":");
+ try stringify(@field(value, Field.name), options, out_stream);
}
- try output(context, "}");
+ try out_stream.writeAll("}");
return;
},
.Pointer => |ptr_info| switch (ptr_info.size) {
.One => {
// TODO: avoid loops?
- return try stringify(value.*, options, context, Errors, output);
+ return try stringify(value.*, options, out_stream);
},
// TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
.Slice => {
if (ptr_info.child == u8 and std.unicode.utf8ValidateSlice(value)) {
- try output(context, "\"");
+ try out_stream.writeAll("\"");
var i: usize = 0;
while (i < value.len) : (i += 1) {
switch (value[i]) {
// normal ascii characters
- 0x20...0x21, 0x23...0x2E, 0x30...0x5B, 0x5D...0x7F => try output(context, value[i .. i + 1]),
+ 0x20...0x21, 0x23...0x2E, 0x30...0x5B, 0x5D...0x7F => try out_stream.writeAll(value[i .. i + 1]),
// control characters with short escapes
- '\\' => try output(context, "\\\\"),
- '\"' => try output(context, "\\\""),
- '/' => try output(context, "\\/"),
- 0x8 => try output(context, "\\b"),
- 0xC => try output(context, "\\f"),
- '\n' => try output(context, "\\n"),
- '\r' => try output(context, "\\r"),
- '\t' => try output(context, "\\t"),
+ '\\' => try out_stream.writeAll("\\\\"),
+ '\"' => try out_stream.writeAll("\\\""),
+ '/' => try out_stream.writeAll("\\/"),
+ 0x8 => try out_stream.writeAll("\\b"),
+ 0xC => try out_stream.writeAll("\\f"),
+ '\n' => try out_stream.writeAll("\\n"),
+ '\r' => try out_stream.writeAll("\\r"),
+ '\t' => try out_stream.writeAll("\\t"),
else => {
const ulen = std.unicode.utf8ByteSequenceLength(value[i]) catch unreachable;
const codepoint = std.unicode.utf8Decode(value[i .. i + ulen]) catch unreachable;
@@ -2351,40 +2349,40 @@ pub fn stringify(
// If the character is in the Basic Multilingual Plane (U+0000 through U+FFFF),
// then it may be represented as a six-character sequence: a reverse solidus, followed
// by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point.
- try output(context, "\\u");
- try std.fmt.formatIntValue(codepoint, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output);
+ try out_stream.writeAll("\\u");
+ try std.fmtstream.formatIntValue(codepoint, "x", std.fmtstream.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
} else {
// To escape an extended character that is not in the Basic Multilingual Plane,
// the character is represented as a 12-character sequence, encoding the UTF-16 surrogate pair.
const high = @intCast(u16, (codepoint - 0x10000) >> 10) + 0xD800;
const low = @intCast(u16, codepoint & 0x3FF) + 0xDC00;
- try output(context, "\\u");
- try std.fmt.formatIntValue(high, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output);
- try output(context, "\\u");
- try std.fmt.formatIntValue(low, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output);
+ try out_stream.writeAll("\\u");
+ try std.fmtstream.formatIntValue(high, "x", std.fmtstream.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
+ try out_stream.writeAll("\\u");
+ try std.fmtstream.formatIntValue(low, "x", std.fmtstream.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
}
i += ulen - 1;
},
}
}
- try output(context, "\"");
+ try out_stream.writeAll("\"");
return;
}
- try output(context, "[");
+ try out_stream.writeAll("[");
for (value) |x, i| {
if (i != 0) {
- try output(context, ",");
+ try out_stream.writeAll(",");
}
- try stringify(x, options, context, Errors, output);
+ try stringify(x, options, out_stream);
}
- try output(context, "]");
+ try out_stream.writeAll("]");
return;
},
else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
},
.Array => |info| {
- return try stringify(value[0..], options, context, Errors, output);
+ return try stringify(value[0..], options, out_stream);
},
else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
}
@@ -2392,10 +2390,26 @@ pub fn stringify(
}
fn teststringify(expected: []const u8, value: var) !void {
- const TestStringifyContext = struct {
+ const ValidationOutStream = struct {
+ const Self = @This();
+ pub const OutStream = std.io.OutStream(*Self, Error, write);
+ pub const Error = error{
+ TooMuchData,
+ DifferentData,
+ };
+
expected_remaining: []const u8,
- fn testStringifyWrite(context: *@This(), bytes: []const u8) !void {
- if (context.expected_remaining.len < bytes.len) {
+
+ fn init(exp: []const u8) Self {
+ return .{ .expected_remaining = exp };
+ }
+
+ pub fn outStream(self: *Self) OutStream {
+ return .{ .context = self };
+ }
+
+ fn write(self: *Self, bytes: []const u8) Error!usize {
+ if (self.expected_remaining.len < bytes.len) {
std.debug.warn(
\\====== expected this output: =========
\\{}
@@ -2403,12 +2417,12 @@ fn teststringify(expected: []const u8, value: var) !void {
\\{}
\\======================================
, .{
- context.expected_remaining,
+ self.expected_remaining,
bytes,
});
return error.TooMuchData;
}
- if (!mem.eql(u8, context.expected_remaining[0..bytes.len], bytes)) {
+ if (!mem.eql(u8, self.expected_remaining[0..bytes.len], bytes)) {
std.debug.warn(
\\====== expected this output: =========
\\{}
@@ -2416,21 +2430,19 @@ fn teststringify(expected: []const u8, value: var) !void {
\\{}
\\======================================
, .{
- context.expected_remaining[0..bytes.len],
+ self.expected_remaining[0..bytes.len],
bytes,
});
return error.DifferentData;
}
- context.expected_remaining = context.expected_remaining[bytes.len..];
+ self.expected_remaining = self.expected_remaining[bytes.len..];
+ return bytes.len;
}
};
- var buf: [100]u8 = undefined;
- var context = TestStringifyContext{ .expected_remaining = expected };
- try stringify(value, StringifyOptions{}, &context, error{
- TooMuchData,
- DifferentData,
- }, TestStringifyContext.testStringifyWrite);
- if (context.expected_remaining.len > 0) return error.NotEnoughData;
+
+ var vos = ValidationOutStream.init(expected);
+ try stringify(value, StringifyOptions{}, vos.outStream());
+ if (vos.expected_remaining.len > 0) return error.NotEnoughData;
}
test "stringify basic types" {
@@ -2498,13 +2510,11 @@ test "stringify struct with custom stringifier" {
pub fn jsonStringify(
value: Self,
options: StringifyOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ out_stream: var,
) !void {
- try output(context, "[\"something special\",");
- try stringify(42, options, context, Errors, output);
- try output(context, "]");
+ try out_stream.writeAll("[\"something special\",");
+ try stringify(42, options, out_stream);
+ try out_stream.writeAll("]");
}
}{ .foo = 42 });
}
From 8dd078b99a31f49194c07af93b0f555f2c7260dc Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Sat, 29 Feb 2020 21:43:54 -0600
Subject: [PATCH 089/111] Convert Buffer to use fmtstream
---
lib/std/buffer.zig | 12 +++---------
lib/std/fmtstream.zig | 13 ++++++++-----
2 files changed, 11 insertions(+), 14 deletions(-)
diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig
index 28ce2a561..93281c35e 100644
--- a/lib/std/buffer.zig
+++ b/lib/std/buffer.zig
@@ -65,15 +65,9 @@ pub const Buffer = struct {
}
pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: var) !Buffer {
- const countSize = struct {
- fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
- size.* += bytes.len;
- }
- }.countSize;
- var size: usize = 0;
- std.fmt.format(&size, error{}, countSize, format, args) catch |err| switch (err) {};
+ const size = std.fmtstream.count(format, args);
var self = try Buffer.initSize(allocator, size);
- assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size);
+ assert((std.fmtstream.bufPrint(self.list.items, format, args) catch unreachable).len == size);
return self;
}
@@ -155,7 +149,7 @@ pub const Buffer = struct {
}
pub fn print(self: *Buffer, comptime fmt: []const u8, args: var) !void {
- return std.fmt.format(self, error{OutOfMemory}, Buffer.append, fmt, args);
+ return self.outStream().print(fmt, args);
}
pub fn outStream(self: *Buffer) std.io.OutStream(*Buffer, error{OutOfMemory}, appendWrite) {
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index 8db0052a7..237d00145 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -1080,14 +1080,17 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]
return buf[0..fbs.pos];
}
+// Count the characters needed for format. Useful for preallocating memory
+pub fn count(comptime fmt: []const u8, args: var) usize {
+ var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
+ format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
+ return counting_stream.bytes_written;
+}
+
pub const AllocPrintError = error{OutOfMemory};
pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
- // Count the characters we need to preallocate
- var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
- format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
-
- const buf = try allocator.alloc(u8, counting_stream.bytes_written);
+ const buf = try allocator.alloc(u8, count(fmt, args));
return bufPrint(buf, fmt, args) catch |err| switch (err) {
error.BufferTooSmall => unreachable, // we just counted the size above
};
From 4023ed56d4fd7b627aed73428b5fa4be4b7c05ad Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Fri, 6 Mar 2020 09:33:12 -0600
Subject: [PATCH 090/111] Convert translate-c to fmtstream
---
src-self-hosted/translate_c.zig | 51 +++++++++++++++------------------
1 file changed, 23 insertions(+), 28 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index f14ebe330..7b05a76cb 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -89,7 +89,7 @@ const Scope = struct {
var proposed_name = name;
while (scope.contains(proposed_name)) {
scope.mangle_count += 1;
- proposed_name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, scope.mangle_count });
+ proposed_name = try std.fmtstream.allocPrint(c.a(), "{}_{}", .{ name, scope.mangle_count });
}
try scope.variables.push(.{ .name = name, .alias = proposed_name });
return proposed_name;
@@ -246,7 +246,7 @@ pub const Context = struct {
const line = ZigClangSourceManager_getSpellingLineNumber(c.source_manager, spelling_loc);
const column = ZigClangSourceManager_getSpellingColumnNumber(c.source_manager, spelling_loc);
- return std.fmt.allocPrint(c.a(), "{}:{}:{}", .{ filename, line, column });
+ return std.fmtstream.allocPrint(c.a(), "{}:{}:{}", .{ filename, line, column });
}
};
@@ -516,7 +516,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
const arg_name = blk: {
const param_prefix = if (is_const) "" else "arg_";
- const bare_arg_name = try std.fmt.allocPrint(c.a(), "{}{}", .{ param_prefix, mangled_param_name });
+ const bare_arg_name = try std.fmtstream.allocPrint(c.a(), "{}{}", .{ param_prefix, mangled_param_name });
break :blk try block_scope.makeMangledName(c, bare_arg_name);
};
@@ -560,7 +560,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{var_name, c.getMangle()}) else var_name;
+ const checked_name = if (isZigPrimitiveType(var_name)) try std.fmtstream.allocPrint(c.a(), "{}_{}", .{var_name, c.getMangle()}) else var_name;
const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
@@ -620,7 +620,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
_ = try appendToken(rp.c, .LParen, "(");
const expr = try transCreateNodeStringLiteral(
rp.c,
- try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),
+ try std.fmtstream.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),
);
_ = try appendToken(rp.c, .RParen, ")");
@@ -677,7 +677,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{typedef_name, c.getMangle()}) else typedef_name;
+ const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmtstream.allocPrint(c.a(), "{}_{}", .{typedef_name, c.getMangle()}) else typedef_name;
if (mem.eql(u8, checked_name, "uint8_t"))
return transTypeDefAsBuiltin(c, typedef_decl, "u8")
@@ -738,7 +738,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
// Record declarations such as `struct {...} x` have no name but they're not
// anonymous hence here isAnonymousStructOrUnion is not needed
if (bare_name.len == 0) {
- bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
+ bare_name = try std.fmtstream.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_unnamed = true;
}
@@ -755,7 +755,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
return null;
}
- const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
+ const name = try std.fmtstream.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
_ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
@@ -812,7 +812,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
var is_anon = false;
var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
- raw_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
+ raw_name = try std.fmtstream.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_anon = true;
}
const field_name = try appendIdentifier(c, raw_name);
@@ -882,11 +882,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, enum_decl)));
var is_unnamed = false;
if (bare_name.len == 0) {
- bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
+ bare_name = try std.fmtstream.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_unnamed = true;
}
- const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});
+ const name = try std.fmtstream.allocPrint(c.a(), "enum_{}", .{bare_name});
_ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
node.eq_token = try appendToken(c, .Equal, "=");
@@ -1754,9 +1754,9 @@ fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
// Handle the remaining escapes Zig doesn't support by turning them
// into their respective hex representation
if (std.ascii.isCntrl(c))
- return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable
+ return std.fmtstream.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable
else
- return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable;
+ return std.fmtstream.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable;
},
};
}
@@ -2436,7 +2436,7 @@ fn transCase(
) TransError!*ast.Node {
const block_scope = scope.findBlockScope(rp.c) catch unreachable;
const switch_scope = scope.getSwitch();
- const label = try std.fmt.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)});
+ const label = try std.fmtstream.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)});
_ = try appendToken(rp.c, .Semicolon, ";");
const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: {
@@ -4607,7 +4607,7 @@ fn finishTransFnProto(
_ = try appendToken(rp.c, .LParen, "(");
const expr = try transCreateNodeStringLiteral(
rp.c,
- try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),
+ try std.fmtstream.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),
);
_ = try appendToken(rp.c, .RParen, ")");
@@ -4752,15 +4752,10 @@ fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenInd
}
fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: var) !ast.TokenIndex {
- const S = struct {
- fn callback(context: *Context, bytes: []const u8) error{OutOfMemory}!void {
- return context.source_buffer.append(bytes);
- }
- };
const start_index = c.source_buffer.len();
errdefer c.source_buffer.shrink(start_index);
- try std.fmt.format(c, error{OutOfMemory}, S.callback, format, args);
+ try c.source_buffer.print(format, args);
const end_index = c.source_buffer.len();
const token_index = c.tree.tokens.len;
const new_token = try c.tree.tokens.addOne();
@@ -4871,7 +4866,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
const name = try c.str(raw_name);
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{name, c.getMangle()}) else name;
+ const mangled_name = if (isZigPrimitiveType(name)) try std.fmtstream.allocPrint(c.a(), "{}_{}", .{name, c.getMangle()}) else name;
if (scope.containsNow(mangled_name)) {
continue;
}
@@ -5156,11 +5151,11 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
switch (lit_bytes[1]) {
'0'...'7' => {
// Octal
- lit_bytes = try std.fmt.allocPrint(c.a(), "0o{}", .{lit_bytes});
+ lit_bytes = try std.fmtstream.allocPrint(c.a(), "0o{}", .{lit_bytes});
},
'X' => {
// Hexadecimal with capital X, valid in C but not in Zig
- lit_bytes = try std.fmt.allocPrint(c.a(), "0x{}", .{lit_bytes[2..]});
+ lit_bytes = try std.fmtstream.allocPrint(c.a(), "0x{}", .{lit_bytes[2..]});
},
else => {},
}
@@ -5191,7 +5186,7 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
return &cast_node.base;
} else if (tok.id == .FloatLiteral) {
if (lit_bytes[0] == '.')
- lit_bytes = try std.fmt.allocPrint(c.a(), "0{}", .{lit_bytes});
+ lit_bytes = try std.fmtstream.allocPrint(c.a(), "0{}", .{lit_bytes});
if (tok.id.FloatLiteral == .None) {
return transCreateNodeFloat(c, lit_bytes);
}
@@ -5324,7 +5319,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const
num += c - 'A' + 10;
},
else => {
- i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
+ i += std.fmtstream.formatIntBuf(bytes[i..], num, 16, false, std.fmtstream.FormatOptions{ .fill = '0', .width = 2 });
num = 0;
if (c == '\\')
state = .Escape
@@ -5350,7 +5345,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const
};
num += c - '0';
} else {
- i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
+ i += std.fmtstream.formatIntBuf(bytes[i..], num, 16, false, std.fmtstream.FormatOptions{ .fill = '0', .width = 2 });
num = 0;
count = 0;
if (c == '\\')
@@ -5364,7 +5359,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const
}
}
if (state == .Hex or state == .Octal)
- i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
+ i += std.fmtstream.formatIntBuf(bytes[i..], num, 16, false, std.fmtstream.FormatOptions{ .fill = '0', .width = 2 });
return bytes[0..i];
}
From 0059d9ee3e7298df03723d97adbea72ff142cacd Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Fri, 6 Mar 2020 09:47:42 -0600
Subject: [PATCH 091/111] Convert fmt.bufPrint / fmt.allocPrint
---
lib/std/atomic/queue.zig | 4 ++--
lib/std/net.zig | 2 +-
lib/std/os.zig | 2 +-
lib/std/progress.zig | 6 +++---
lib/std/special/build_runner.zig | 6 +++---
lib/std/target.zig | 4 ++--
lib/std/zig/cross_target.zig | 2 +-
lib/std/zig/system.zig | 6 +++---
src-self-hosted/compilation.zig | 6 +++---
src-self-hosted/dep_tokenizer.zig | 2 +-
src-self-hosted/libc_installation.zig | 2 +-
src-self-hosted/link.zig | 20 ++++++++++----------
src-self-hosted/print_targets.zig | 2 +-
src-self-hosted/test.zig | 6 +++---
src-self-hosted/type.zig | 8 ++++----
test/src/compare_output.zig | 8 ++++----
test/src/run_translated_c.zig | 4 ++--
test/src/translate_c.zig | 4 ++--
test/tests.zig | 10 +++++-----
tools/process_headers.zig | 4 ++--
tools/update_glibc.zig | 4 ++--
21 files changed, 56 insertions(+), 56 deletions(-)
diff --git a/lib/std/atomic/queue.zig b/lib/std/atomic/queue.zig
index 1a0f39587..c308fa681 100644
--- a/lib/std/atomic/queue.zig
+++ b/lib/std/atomic/queue.zig
@@ -348,7 +348,7 @@ test "std.atomic.Queue dump" {
fbs.reset();
try queue.dumpToStream(fbs.outStream());
- var expected = try std.fmt.bufPrint(expected_buffer[0..],
+ var expected = try std.fmtstream.bufPrint(expected_buffer[0..],
\\head: 0x{x}=1
\\ (null)
\\tail: 0x{x}=1
@@ -368,7 +368,7 @@ test "std.atomic.Queue dump" {
fbs.reset();
try queue.dumpToStream(fbs.outStream());
- expected = try std.fmt.bufPrint(expected_buffer[0..],
+ expected = try std.fmtstream.bufPrint(expected_buffer[0..],
\\head: 0x{x}=1
\\ 0x{x}=2
\\ (null)
diff --git a/lib/std/net.zig b/lib/std/net.zig
index 9395d34f4..a1225654f 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -438,7 +438,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
const name_c = try std.cstr.addNullByte(allocator, name);
defer allocator.free(name_c);
- const port_c = try std.fmt.allocPrint(allocator, "{}\x00", .{port});
+ const port_c = try std.fmtstream.allocPrint(allocator, "{}\x00", .{port});
defer allocator.free(port_c);
const hints = os.addrinfo{
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 76a5dc2be..baea4cecc 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -3049,7 +3049,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP
defer close(fd);
var procfs_buf: ["/proc/self/fd/-2147483648".len:0]u8 = undefined;
- const proc_path = std.fmt.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", .{fd}) catch unreachable;
+ const proc_path = std.fmtstream.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", .{fd}) catch unreachable;
return readlinkC(@ptrCast([*:0]const u8, proc_path.ptr), out_buffer);
}
diff --git a/lib/std/progress.zig b/lib/std/progress.zig
index 0264d99c9..ebb983cdc 100644
--- a/lib/std/progress.zig
+++ b/lib/std/progress.zig
@@ -130,11 +130,11 @@ pub const Progress = struct {
var end: usize = 0;
if (self.columns_written > 0) {
// restore cursor position
- end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len;
+ end += (std.fmtstream.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len;
self.columns_written = 0;
// clear rest of line
- end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len;
+ end += (std.fmtstream.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len;
}
if (!self.done) {
@@ -185,7 +185,7 @@ pub const Progress = struct {
}
fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: var) void {
- if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| {
+ if (std.fmtstream.bufPrint(self.output_buffer[end.*..], format, args)) |written| {
const amt = written.len;
end.* += amt;
self.columns_written += amt;
diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig
index 974247e2a..c5a96df66 100644
--- a/lib/std/special/build_runner.zig
+++ b/lib/std/special/build_runner.zig
@@ -2,7 +2,7 @@ const root = @import("@build");
const std = @import("std");
const builtin = @import("builtin");
const io = std.io;
-const fmt = std.fmt;
+const fmtstream = std.fmtstream;
const Builder = std.build.Builder;
const mem = std.mem;
const process = std.process;
@@ -153,7 +153,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
const allocator = builder.allocator;
for (builder.top_level_steps.toSliceConst()) |top_level_step| {
const name = if (&top_level_step.step == builder.default_step)
- try fmt.allocPrint(allocator, "{} (default)", .{top_level_step.step.name})
+ try fmtstream.allocPrint(allocator, "{} (default)", .{top_level_step.step.name})
else
top_level_step.step.name;
try out_stream.print(" {s:22} {}\n", .{ name, top_level_step.description });
@@ -175,7 +175,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
try out_stream.print(" (none)\n", .{});
} else {
for (builder.available_options_list.toSliceConst()) |option| {
- const name = try fmt.allocPrint(allocator, " -D{}=[{}]", .{
+ const name = try fmtstream.allocPrint(allocator, " -D{}=[{}]", .{
option.name,
Builder.typeIdName(option.type_id),
});
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 8beb7c301..c117f60cc 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -972,7 +972,7 @@ pub const Target = struct {
}
pub fn linuxTripleSimple(allocator: *mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![:0]u8 {
- return std.fmt.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
+ return std.fmtstream.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
}
pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
@@ -1158,7 +1158,7 @@ pub const Target = struct {
var result: DynamicLinker = .{};
const S = struct {
fn print(r: *DynamicLinker, comptime fmt: []const u8, args: var) DynamicLinker {
- r.max_byte = @intCast(u8, (std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1);
+ r.max_byte = @intCast(u8, (std.fmtstream.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1);
return r.*;
}
fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index cec3ea05e..a60833f93 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -573,7 +573,7 @@ pub const CrossTarget = struct {
.Dynamic => "",
};
- return std.fmt.allocPrint0(allocator, "{}-{}{}", .{ arch, os, static_suffix });
+ return std.fmtstream.allocPrint0(allocator, "{}-{}{}", .{ arch, os, static_suffix });
}
pub const Executor = union(enum) {
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 558b50b5b..875ecd424 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -130,7 +130,7 @@ pub const NativePaths = struct {
}
pub fn addIncludeDirFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void {
- const item = try std.fmt.allocPrint0(self.include_dirs.allocator, fmt, args);
+ const item = try std.fmtstream.allocPrint0(self.include_dirs.allocator, fmt, args);
errdefer self.include_dirs.allocator.free(item);
try self.include_dirs.append(item);
}
@@ -140,7 +140,7 @@ pub const NativePaths = struct {
}
pub fn addLibDirFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void {
- const item = try std.fmt.allocPrint0(self.lib_dirs.allocator, fmt, args);
+ const item = try std.fmtstream.allocPrint0(self.lib_dirs.allocator, fmt, args);
errdefer self.lib_dirs.allocator.free(item);
try self.lib_dirs.append(item);
}
@@ -150,7 +150,7 @@ pub const NativePaths = struct {
}
pub fn addWarningFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void {
- const item = try std.fmt.allocPrint0(self.warnings.allocator, fmt, args);
+ const item = try std.fmtstream.allocPrint0(self.warnings.allocator, fmt, args);
errdefer self.warnings.allocator.free(item);
try self.warnings.append(item);
}
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
index 7a45bb3c3..fdaee7d12 100644
--- a/src-self-hosted/compilation.zig
+++ b/src-self-hosted/compilation.zig
@@ -1051,7 +1051,7 @@ pub const Compilation = struct {
}
fn addCompileError(self: *Compilation, tree_scope: *Scope.AstTree, span: Span, comptime fmt: []const u8, args: var) !void {
- const text = try std.fmt.allocPrint(self.gpa(), fmt, args);
+ const text = try std.fmtstream.allocPrint(self.gpa(), fmt, args);
errdefer self.gpa().free(text);
const msg = try Msg.createFromScope(self, tree_scope, span, text);
@@ -1061,7 +1061,7 @@ pub const Compilation = struct {
}
fn addCompileErrorCli(self: *Compilation, realpath: []const u8, comptime fmt: []const u8, args: var) !void {
- const text = try std.fmt.allocPrint(self.gpa(), fmt, args);
+ const text = try std.fmtstream.allocPrint(self.gpa(), fmt, args);
errdefer self.gpa().free(text);
const msg = try Msg.createFromCli(self, realpath, text);
@@ -1154,7 +1154,7 @@ pub const Compilation = struct {
const tmp_dir = try self.getTmpDir();
const file_prefix = self.getRandomFileName();
- const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", .{ file_prefix[0..], suffix });
+ const file_name = try std.fmtstream.allocPrint(self.gpa(), "{}{}", .{ file_prefix[0..], suffix });
defer self.gpa().free(file_name);
const full_path = try fs.path.join(self.gpa(), &[_][]const u8{ tmp_dir, file_name[0..] });
diff --git a/src-self-hosted/dep_tokenizer.zig b/src-self-hosted/dep_tokenizer.zig
index 5c250cdb9..11724a3d2 100644
--- a/src-self-hosted/dep_tokenizer.zig
+++ b/src-self-hosted/dep_tokenizer.zig
@@ -894,7 +894,7 @@ fn printSection(out: var, label: []const u8, bytes: []const u8) !void {
fn printLabel(out: var, label: []const u8, bytes: []const u8) !void {
var buf: [80]u8 = undefined;
- var text = try std.fmt.bufPrint(buf[0..], "{} {} bytes ", .{ label, bytes.len });
+ var text = try std.fmtstream.bufPrint(buf[0..], "{} {} bytes ", .{ label, bytes.len });
try out.write(text);
var i: usize = text.len;
const end = 79;
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
index 0f9736456..3b65fb172 100644
--- a/src-self-hosted/libc_installation.zig
+++ b/src-self-hosted/libc_installation.zig
@@ -543,7 +543,7 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
const allocator = args.allocator;
const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe;
- const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", .{args.search_basename});
+ const arg1 = try std.fmtstream.allocPrint(allocator, "-print-file-name={}", .{args.search_basename});
defer allocator.free(arg1);
const argv = [_][]const u8{ cc_exe, arg1 };
diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig
index 1efa15574..b63e6c24f 100644
--- a/src-self-hosted/link.zig
+++ b/src-self-hosted/link.zig
@@ -296,13 +296,13 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
const is_library = ctx.comp.kind == .Lib;
- const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", .{ctx.out_file_path.toSliceConst()});
+ const out_arg = try std.fmtstream.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", .{ctx.out_file_path.toSliceConst()});
try ctx.args.append(@ptrCast([*:0]const u8, out_arg.ptr));
if (ctx.comp.haveLibC()) {
- try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr));
- try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr));
- try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr));
+ try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmtstream.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr));
+ try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmtstream.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr));
+ try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmtstream.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr));
}
if (ctx.link_in_crt) {
@@ -310,20 +310,20 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
const d_str = if (ctx.comp.build_mode == .Debug) "d" else "";
if (ctx.comp.is_static) {
- const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", .{d_str});
+ const cmt_lib_name = try std.fmtstream.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", .{d_str});
try ctx.args.append(@ptrCast([*:0]const u8, cmt_lib_name.ptr));
} else {
- const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", .{d_str});
+ const msvcrt_lib_name = try std.fmtstream.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", .{d_str});
try ctx.args.append(@ptrCast([*:0]const u8, msvcrt_lib_name.ptr));
}
- const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", .{
+ const vcruntime_lib_name = try std.fmtstream.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", .{
lib_str,
d_str,
});
try ctx.args.append(@ptrCast([*:0]const u8, vcruntime_lib_name.ptr));
- const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", .{ lib_str, d_str });
+ const crt_lib_name = try std.fmtstream.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", .{ lib_str, d_str });
try ctx.args.append(@ptrCast([*:0]const u8, crt_lib_name.ptr));
// Visual C++ 2015 Conformance Changes
@@ -383,7 +383,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
.IPhoneOS => try ctx.args.append("-iphoneos_version_min"),
.IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"),
}
- const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", .{
+ const ver_str = try std.fmtstream.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", .{
platform.major,
platform.minor,
platform.micro,
@@ -445,7 +445,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
try ctx.args.append("-lSystem");
} else {
if (mem.indexOfScalar(u8, lib.name, '/') == null) {
- const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name});
+ const arg = try std.fmtstream.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name});
try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
} else {
const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig
index ad506425d..408c39fe7 100644
--- a/src-self-hosted/print_targets.zig
+++ b/src-self-hosted/print_targets.zig
@@ -138,7 +138,7 @@ pub fn cmdTargets(
for (available_glibcs) |glibc| {
try jws.arrayElem();
- const tmp = try std.fmt.allocPrint(allocator, "{}", .{glibc});
+ const tmp = try std.fmtstream.allocPrint(allocator, "{}", .{glibc});
defer allocator.free(tmp);
try jws.emitString(tmp);
}
diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig
index e87164c9f..98e9fb06d 100644
--- a/src-self-hosted/test.zig
+++ b/src-self-hosted/test.zig
@@ -81,7 +81,7 @@ pub const TestContext = struct {
msg: []const u8,
) !void {
var file_index_buf: [20]u8 = undefined;
- const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
+ const file_index = try std.fmtstream.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 });
if (std.fs.path.dirname(file1_path)) |dirname| {
@@ -114,10 +114,10 @@ pub const TestContext = struct {
expected_output: []const u8,
) !void {
var file_index_buf: [20]u8 = undefined;
- const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
+ const file_index = try std.fmtstream.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 });
- const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", .{ file1_path, (Target{ .Native = {} }).exeFileExt() });
+ const output_file = try std.fmtstream.allocPrint(allocator, "{}-out{}", .{ file1_path, (Target{ .Native = {} }).exeFileExt() });
if (std.fs.path.dirname(file1_path)) |dirname| {
try std.fs.cwd().makePath(dirname);
}
diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig
index 70ed754ce..c2b406823 100644
--- a/src-self-hosted/type.zig
+++ b/src-self-hosted/type.zig
@@ -581,7 +581,7 @@ pub const Type = struct {
errdefer comp.gpa().destroy(self);
const u_or_i = "ui"[@boolToInt(key.is_signed)];
- const name = try std.fmt.allocPrint(comp.gpa(), "{c}{}", .{ u_or_i, key.bit_count });
+ const name = try std.fmtstream.allocPrint(comp.gpa(), "{c}{}", .{ u_or_i, key.bit_count });
errdefer comp.gpa().free(name);
self.base.init(comp, .Int, name);
@@ -764,13 +764,13 @@ pub const Type = struct {
.Non => "",
};
const name = switch (self.key.alignment) {
- .Abi => try std.fmt.allocPrint(comp.gpa(), "{}{}{}{}", .{
+ .Abi => try std.fmtstream.allocPrint(comp.gpa(), "{}{}{}{}", .{
size_str,
mut_str,
vol_str,
self.key.child_type.name,
}),
- .Override => |alignment| try std.fmt.allocPrint(comp.gpa(), "{}align<{}> {}{}{}", .{
+ .Override => |alignment| try std.fmtstream.allocPrint(comp.gpa(), "{}align<{}> {}{}{}", .{
size_str,
alignment,
mut_str,
@@ -845,7 +845,7 @@ pub const Type = struct {
};
errdefer comp.gpa().destroy(self);
- const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", .{ key.len, key.elem_type.name });
+ const name = try std.fmtstream.allocPrint(comp.gpa(), "[{}]{}", .{ key.len, key.elem_type.name });
errdefer comp.gpa().free(name);
self.base.init(comp, .Array, name);
diff --git a/test/src/compare_output.zig b/test/src/compare_output.zig
index ae994a069..c68eb1eeb 100644
--- a/test/src/compare_output.zig
+++ b/test/src/compare_output.zig
@@ -4,7 +4,7 @@ const std = @import("std");
const builtin = std.builtin;
const build = std.build;
const ArrayList = std.ArrayList;
-const fmt = std.fmt;
+const fmtstream = std.fmtstream;
const mem = std.mem;
const fs = std.fs;
const warn = std.debug.warn;
@@ -97,7 +97,7 @@ pub const CompareOutputContext = struct {
switch (case.special) {
Special.Asm => {
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "assemble-and-link {}", .{
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "assemble-and-link {}", .{
case.name,
}) catch unreachable;
if (self.test_filter) |filter| {
@@ -116,7 +116,7 @@ pub const CompareOutputContext = struct {
},
Special.None => {
for (self.modes) |mode| {
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", .{
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "{} {} ({})", .{
"compare-output",
case.name,
@tagName(mode),
@@ -141,7 +141,7 @@ pub const CompareOutputContext = struct {
}
},
Special.RuntimeSafety => {
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "safety {}", .{case.name}) catch unreachable;
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "safety {}", .{case.name}) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/test/src/run_translated_c.zig b/test/src/run_translated_c.zig
index 14b0ce593..6304137e4 100644
--- a/test/src/run_translated_c.zig
+++ b/test/src/run_translated_c.zig
@@ -3,7 +3,7 @@
const std = @import("std");
const build = std.build;
const ArrayList = std.ArrayList;
-const fmt = std.fmt;
+const fmtstream = std.fmtstream;
const mem = std.mem;
const fs = std.fs;
const warn = std.debug.warn;
@@ -76,7 +76,7 @@ pub const RunTranslatedCContext = struct {
pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {
const b = self.b;
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "run-translated-c {}", .{case.name}) catch unreachable;
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "run-translated-c {}", .{case.name}) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/test/src/translate_c.zig b/test/src/translate_c.zig
index 9a6bd0d32..250ec6175 100644
--- a/test/src/translate_c.zig
+++ b/test/src/translate_c.zig
@@ -3,7 +3,7 @@
const std = @import("std");
const build = std.build;
const ArrayList = std.ArrayList;
-const fmt = std.fmt;
+const fmtstream = std.fmtstream;
const mem = std.mem;
const fs = std.fs;
const warn = std.debug.warn;
@@ -99,7 +99,7 @@ pub const TranslateCContext = struct {
const b = self.b;
const translate_c_cmd = "translate-c";
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {}", .{ translate_c_cmd, case.name }) catch unreachable;
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "{} {}", .{ translate_c_cmd, case.name }) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/test/tests.zig b/test/tests.zig
index 22dad10e3..61f694bed 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -8,7 +8,7 @@ const Buffer = std.Buffer;
const io = std.io;
const fs = std.fs;
const mem = std.mem;
-const fmt = std.fmt;
+const fmtstream = std.fmtstream;
const ArrayList = std.ArrayList;
const Mode = builtin.Mode;
const LibExeObjStep = build.LibExeObjStep;
@@ -484,7 +484,7 @@ pub const StackTracesContext = struct {
const expect_for_mode = expect[@enumToInt(mode)];
if (expect_for_mode.len == 0) continue;
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", .{
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "{} {} ({})", .{
"stack-trace",
name,
@tagName(mode),
@@ -943,7 +943,7 @@ pub const CompileErrorContext = struct {
pub fn addCase(self: *CompileErrorContext, case: *const TestCase) void {
const b = self.b;
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {}", .{
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "compile-error {}", .{
case.name,
}) catch unreachable;
if (self.test_filter) |filter| {
@@ -1009,7 +1009,7 @@ pub const StandaloneContext = struct {
const b = self.b;
for (self.modes) |mode| {
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})", .{
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "build {} ({})", .{
root_src,
@tagName(mode),
}) catch unreachable;
@@ -1152,7 +1152,7 @@ pub const GenHContext = struct {
const b = self.b;
const mode = builtin.Mode.Debug;
- const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", .{ case.name, @tagName(mode) }) catch unreachable;
+ const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "gen-h {} ({})", .{ case.name, @tagName(mode) }) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/tools/process_headers.zig b/tools/process_headers.zig
index abdc9fabf..43950750e 100644
--- a/tools/process_headers.zig
+++ b/tools/process_headers.zig
@@ -299,7 +299,7 @@ pub fn main() !void {
std.debug.warn("unrecognized C ABI: {}\n", .{abi_name});
usageAndExit(args[0]);
};
- const generic_name = try std.fmt.allocPrint(allocator, "generic-{}", .{abi_name});
+ const generic_name = try std.fmtstream.allocPrint(allocator, "generic-{}", .{abi_name});
// TODO compiler crashed when I wrote this the canonical way
var libc_targets: []const LibCTarget = undefined;
@@ -440,7 +440,7 @@ pub fn main() !void {
.specific => |a| @tagName(a),
else => @tagName(dest_target.arch),
};
- const out_subpath = try std.fmt.allocPrint(allocator, "{}-{}-{}", .{
+ const out_subpath = try std.fmtstream.allocPrint(allocator, "{}-{}-{}", .{
arch_name,
@tagName(dest_target.os),
@tagName(dest_target.abi),
diff --git a/tools/update_glibc.zig b/tools/update_glibc.zig
index 84522aabe..35351e4d2 100644
--- a/tools/update_glibc.zig
+++ b/tools/update_glibc.zig
@@ -1,6 +1,6 @@
const std = @import("std");
const fs = std.fs;
-const fmt = std.fmt;
+const fmtstream = std.fmtstream;
const assert = std.debug.assert;
// Example abilist path:
@@ -154,7 +154,7 @@ pub fn main() !void {
const fn_set = &target_funcs_gop.kv.value.list;
for (lib_names) |lib_name, lib_name_index| {
- const basename = try fmt.allocPrint(allocator, "lib{}.abilist", .{lib_name});
+ const basename = try fmtstream.allocPrint(allocator, "lib{}.abilist", .{lib_name});
const abi_list_filename = blk: {
if (abi_list.targets[0].abi == .gnuabi64 and std.mem.eql(u8, lib_name, "c")) {
break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "n64", basename });
From 6a53fe7c93ddc6216e7cd41514bebe701531c9c3 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Fri, 6 Mar 2020 12:03:15 -0600
Subject: [PATCH 092/111] Handle potential downcast when translating stream
size
---
lib/std/buffer.zig | 4 +++-
lib/std/fmtstream.zig | 10 +++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig
index 93281c35e..6d361bdb4 100644
--- a/lib/std/buffer.zig
+++ b/lib/std/buffer.zig
@@ -65,7 +65,9 @@ pub const Buffer = struct {
}
pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: var) !Buffer {
- const size = std.fmtstream.count(format, args);
+ const size = std.fmtstream.count(format, args) catch |err| switch (err) {
+ error.Overflow => return error.OutOfMemory,
+ };
var self = try Buffer.initSize(allocator, size);
assert((std.fmtstream.bufPrint(self.list.items, format, args) catch unreachable).len == size);
return self;
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
index 237d00145..93734d42a 100644
--- a/lib/std/fmtstream.zig
+++ b/lib/std/fmtstream.zig
@@ -1081,16 +1081,20 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]
}
// Count the characters needed for format. Useful for preallocating memory
-pub fn count(comptime fmt: []const u8, args: var) usize {
+pub fn count(comptime fmt: []const u8, args: var) !usize {
var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
- return counting_stream.bytes_written;
+ return std.math.cast(usize, counting_stream.bytes_written);
}
pub const AllocPrintError = error{OutOfMemory};
pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
- const buf = try allocator.alloc(u8, count(fmt, args));
+ const size = count(fmt, args) catch |err| switch (err) {
+ // Output too long. Can't possibly allocate enough memory to display it.
+ error.Overflow => return error.OutOfMemory,
+ };
+ const buf = try allocator.alloc(u8, size);
return bufPrint(buf, fmt, args) catch |err| switch (err) {
error.BufferTooSmall => unreachable, // we just counted the size above
};
From 786216ca5a7cc992d1be895702d37798bc85bf14 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Fri, 6 Mar 2020 16:52:46 -0600
Subject: [PATCH 093/111] Slap in workaround for Fifo
---
lib/std/fifo.zig | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/lib/std/fifo.zig b/lib/std/fifo.zig
index 85a0e4c9d..65ddc65d3 100644
--- a/lib/std/fifo.zig
+++ b/lib/std/fifo.zig
@@ -294,7 +294,19 @@ pub fn LinearFifo(
pub usingnamespace if (T == u8)
struct {
pub fn print(self: *Self, comptime format: []const u8, args: var) !void {
- return std.fmt.format(self, error{OutOfMemory}, Self.write, format, args);
+ // TODO: maybe expose this stream as a method?
+ const FifoStream = struct {
+ const OutStream = std.io.OutStream(*Self, Error, write);
+ const Error = error{OutOfMemory};
+
+ fn write(fifo: *Self, bytes: []const u8) Error!usize {
+ try fifo.write(bytes);
+ return bytes.len;
+ }
+ };
+
+ var out_stream = FifoStream.OutStream{ .context = self };
+ try out_stream.print(format, args);
}
}
else
From ed7f30e1cd0c00c82c511ad826fe8d8b60b2f57f Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Fri, 6 Mar 2020 16:45:42 -0600
Subject: [PATCH 094/111] Migrate last vestiges of fmt
---
src-self-hosted/dep_tokenizer.zig | 26 ++++++++++------------
test/stage1/behavior/enum_with_members.zig | 6 ++---
2 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/src-self-hosted/dep_tokenizer.zig b/src-self-hosted/dep_tokenizer.zig
index 11724a3d2..233b67817 100644
--- a/src-self-hosted/dep_tokenizer.zig
+++ b/src-self-hosted/dep_tokenizer.zig
@@ -306,12 +306,12 @@ pub const Tokenizer = struct {
fn errorPosition(self: *Tokenizer, position: usize, bytes: []const u8, comptime fmt: []const u8, args: var) Error {
var buffer = try std.Buffer.initSize(&self.arena.allocator, 0);
- std.fmt.format(&buffer, anyerror, std.Buffer.append, fmt, args) catch {};
+ try buffer.print(fmt, args);
try buffer.append(" '");
var out = makeOutput(std.Buffer.append, &buffer);
try printCharValues(&out, bytes);
try buffer.append("'");
- std.fmt.format(&buffer, anyerror, std.Buffer.append, " at position {}", .{position - (bytes.len - 1)}) catch {};
+ try buffer.print(" at position {}", .{position - (bytes.len - 1)});
self.error_text = buffer.toSlice();
return Error.InvalidInput;
}
@@ -319,10 +319,9 @@ pub const Tokenizer = struct {
fn errorIllegalChar(self: *Tokenizer, position: usize, char: u8, comptime fmt: []const u8, args: var) Error {
var buffer = try std.Buffer.initSize(&self.arena.allocator, 0);
try buffer.append("illegal char ");
- var out = makeOutput(std.Buffer.append, &buffer);
- try printUnderstandableChar(&out, char);
- std.fmt.format(&buffer, anyerror, std.Buffer.append, " at position {}", .{position}) catch {};
- if (fmt.len != 0) std.fmt.format(&buffer, anyerror, std.Buffer.append, ": " ++ fmt, args) catch {};
+ try printUnderstandableChar(&buffer, char);
+ try buffer.print(" at position {}", .{position});
+ if (fmt.len != 0) try buffer.print(": " ++ fmt, args);
self.error_text = buffer.toSlice();
return Error.InvalidInput;
}
@@ -980,13 +979,13 @@ fn hexDump16(out: var, offset: usize, bytes: []const u8) !void {
fn printDecValue(out: var, value: u64, width: u8) !void {
var buffer: [20]u8 = undefined;
- const len = std.fmt.formatIntBuf(buffer[0..], value, 10, false, width);
+ const len = std.fmtstream.formatIntBuf(buffer[0..], value, 10, false, width);
try out.write(buffer[0..len]);
}
fn printHexValue(out: var, value: u64, width: u8) !void {
var buffer: [16]u8 = undefined;
- const len = std.fmt.formatIntBuf(buffer[0..], value, 16, false, width);
+ const len = std.fmtstream.formatIntBuf(buffer[0..], value, 16, false, width);
try out.write(buffer[0..len]);
}
@@ -996,14 +995,13 @@ fn printCharValues(out: var, bytes: []const u8) !void {
}
}
-fn printUnderstandableChar(out: var, char: u8) !void {
+fn printUnderstandableChar(buffer: *std.Buffer, char: u8) !void {
if (!std.ascii.isPrint(char) or char == ' ') {
- const output = @typeInfo(@TypeOf(out)).Pointer.child.output;
- std.fmt.format(out.context, anyerror, output, "\\x{X:2}", .{char}) catch {};
+ try buffer.print("\\x{X:2}", .{char});
} else {
- try out.write("'");
- try out.write(&[_]u8{printable_char_tab[char]});
- try out.write("'");
+ try buffer.append("'");
+ try buffer.appendByte(printable_char_tab[char]);
+ try buffer.append("'");
}
}
diff --git a/test/stage1/behavior/enum_with_members.zig b/test/stage1/behavior/enum_with_members.zig
index 08b195494..b299301ce 100644
--- a/test/stage1/behavior/enum_with_members.zig
+++ b/test/stage1/behavior/enum_with_members.zig
@@ -1,6 +1,6 @@
const expect = @import("std").testing.expect;
const mem = @import("std").mem;
-const fmt = @import("std").fmt;
+const fmtstream = @import("std").fmtstream;
const ET = union(enum) {
SINT: i32,
@@ -8,8 +8,8 @@ const ET = union(enum) {
pub fn print(a: *const ET, buf: []u8) anyerror!usize {
return switch (a.*) {
- ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}),
- ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}),
+ ET.SINT => |x| fmtstream.formatIntBuf(buf, x, 10, false, fmtstream.FormatOptions{}),
+ ET.UINT => |x| fmtstream.formatIntBuf(buf, x, 10, false, fmtstream.FormatOptions{}),
};
}
};
From 4aae55b4ccf44fa3c2c2a81a6a34f3c898dece30 Mon Sep 17 00:00:00 2001
From: Benjamin Feng
Date: Fri, 6 Mar 2020 16:59:21 -0600
Subject: [PATCH 095/111] Replace fmt with new fmtstream
---
lib/std/atomic/queue.zig | 4 +-
lib/std/buffer.zig | 4 +-
lib/std/builtin.zig | 14 +-
lib/std/fmt.zig | 509 +++---
lib/std/fmtstream.zig | 1685 --------------------
lib/std/http/headers.zig | 4 +-
lib/std/io/out_stream.zig | 2 +-
lib/std/json.zig | 10 +-
lib/std/math/big/int.zig | 2 +-
lib/std/net.zig | 14 +-
lib/std/net/test.zig | 4 +-
lib/std/os.zig | 2 +-
lib/std/os/uefi.zig | 4 +-
lib/std/progress.zig | 6 +-
lib/std/special/build_runner.zig | 6 +-
lib/std/std.zig | 1 -
lib/std/target.zig | 4 +-
lib/std/zig/cross_target.zig | 2 +-
lib/std/zig/system.zig | 6 +-
src-self-hosted/compilation.zig | 6 +-
src-self-hosted/dep_tokenizer.zig | 6 +-
src-self-hosted/libc_installation.zig | 2 +-
src-self-hosted/link.zig | 20 +-
src-self-hosted/print_targets.zig | 2 +-
src-self-hosted/test.zig | 6 +-
src-self-hosted/translate_c.zig | 44 +-
src-self-hosted/type.zig | 8 +-
test/src/compare_output.zig | 8 +-
test/src/run_translated_c.zig | 4 +-
test/src/translate_c.zig | 4 +-
test/stage1/behavior/enum_with_members.zig | 6 +-
test/tests.zig | 10 +-
tools/process_headers.zig | 4 +-
tools/update_glibc.zig | 4 +-
34 files changed, 331 insertions(+), 2086 deletions(-)
delete mode 100644 lib/std/fmtstream.zig
diff --git a/lib/std/atomic/queue.zig b/lib/std/atomic/queue.zig
index c308fa681..1a0f39587 100644
--- a/lib/std/atomic/queue.zig
+++ b/lib/std/atomic/queue.zig
@@ -348,7 +348,7 @@ test "std.atomic.Queue dump" {
fbs.reset();
try queue.dumpToStream(fbs.outStream());
- var expected = try std.fmtstream.bufPrint(expected_buffer[0..],
+ var expected = try std.fmt.bufPrint(expected_buffer[0..],
\\head: 0x{x}=1
\\ (null)
\\tail: 0x{x}=1
@@ -368,7 +368,7 @@ test "std.atomic.Queue dump" {
fbs.reset();
try queue.dumpToStream(fbs.outStream());
- expected = try std.fmtstream.bufPrint(expected_buffer[0..],
+ expected = try std.fmt.bufPrint(expected_buffer[0..],
\\head: 0x{x}=1
\\ 0x{x}=2
\\ (null)
diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig
index 6d361bdb4..cf028f104 100644
--- a/lib/std/buffer.zig
+++ b/lib/std/buffer.zig
@@ -65,11 +65,11 @@ pub const Buffer = struct {
}
pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: var) !Buffer {
- const size = std.fmtstream.count(format, args) catch |err| switch (err) {
+ const size = std.fmt.count(format, args) catch |err| switch (err) {
error.Overflow => return error.OutOfMemory,
};
var self = try Buffer.initSize(allocator, size);
- assert((std.fmtstream.bufPrint(self.list.items, format, args) catch unreachable).len == size);
+ assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size);
return self;
}
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 5cac8c962..c8cd6c05c 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -426,27 +426,27 @@ pub const Version = struct {
pub fn parse(text: []const u8) !Version {
var it = std.mem.separate(text, ".");
return Version{
- .major = try std.fmtstream.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
- .minor = try std.fmtstream.parseInt(u32, it.next() orelse "0", 10),
- .patch = try std.fmtstream.parseInt(u32, it.next() orelse "0", 10),
+ .major = try std.fmt.parseInt(u32, it.next() orelse return error.InvalidVersion, 10),
+ .minor = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
+ .patch = try std.fmt.parseInt(u32, it.next() orelse "0", 10),
};
}
pub fn format(
self: Version,
comptime fmt: []const u8,
- options: std.fmtstream.FormatOptions,
+ options: std.fmt.FormatOptions,
out_stream: var,
) !void {
if (fmt.len == 0) {
if (self.patch == 0) {
if (self.minor == 0) {
- return std.fmtstream.format(out_stream, "{}", .{self.major});
+ return std.fmt.format(out_stream, "{}", .{self.major});
} else {
- return std.fmtstream.format(out_stream, "{}.{}", .{ self.major, self.minor });
+ return std.fmt.format(out_stream, "{}.{}", .{ self.major, self.minor });
}
} else {
- return std.fmtstream.format(out_stream, "{}.{}.{}", .{ self.major, self.minor, self.patch });
+ return std.fmt.format(out_stream, "{}.{}.{}", .{ self.major, self.minor, self.patch });
}
} else {
@compileError("Unknown format string: '" ++ fmt ++ "'");
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index a7525ba79..5173015b3 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -69,19 +69,17 @@ fn peekIsAlign(comptime fmt: []const u8) bool {
///
/// If a formatted user type contains a function of the type
/// ```
-/// fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, context: var, comptime Errors: type, comptime output: fn (@TypeOf(context), []const u8) Errors!void) Errors!void
+/// fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void
/// ```
/// with `?` being the type formatted, this function will be called instead of the default implementation.
/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
///
/// A user type may be a `struct`, `vector`, `union` or `enum` type.
pub fn format(
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ out_stream: var,
comptime fmt: []const u8,
args: var,
-) Errors!void {
+) !void {
const ArgSetType = u32;
if (@typeInfo(@TypeOf(args)) != .Struct) {
@compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
@@ -138,7 +136,7 @@ pub fn format(
.Start => switch (c) {
'{' => {
if (start_index < i) {
- try output(context, fmt[start_index..i]);
+ try out_stream.writeAll(fmt[start_index..i]);
}
start_index = i;
@@ -150,7 +148,7 @@ pub fn format(
},
'}' => {
if (start_index < i) {
- try output(context, fmt[start_index..i]);
+ try out_stream.writeAll(fmt[start_index..i]);
}
state = .CloseBrace;
},
@@ -185,9 +183,7 @@ pub fn format(
args[arg_to_print],
fmt[0..0],
options,
- context,
- Errors,
- output,
+ out_stream,
default_max_depth,
);
@@ -218,9 +214,7 @@ pub fn format(
args[arg_to_print],
fmt[specifier_start..i],
options,
- context,
- Errors,
- output,
+ out_stream,
default_max_depth,
);
state = .Start;
@@ -265,9 +259,7 @@ pub fn format(
args[arg_to_print],
fmt[specifier_start..specifier_end],
options,
- context,
- Errors,
- output,
+ out_stream,
default_max_depth,
);
state = .Start;
@@ -293,9 +285,7 @@ pub fn format(
args[arg_to_print],
fmt[specifier_start..specifier_end],
options,
- context,
- Errors,
- output,
+ out_stream,
default_max_depth,
);
state = .Start;
@@ -316,7 +306,7 @@ pub fn format(
}
}
if (start_index < fmt.len) {
- try output(context, fmt[start_index..]);
+ try out_stream.writeAll(fmt[start_index..]);
}
}
@@ -324,141 +314,131 @@ pub fn formatType(
value: var,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
+ out_stream: var,
max_depth: usize,
-) Errors!void {
+) @TypeOf(out_stream).Error!void {
if (comptime std.mem.eql(u8, fmt, "*")) {
- try output(context, @typeName(@TypeOf(value).Child));
- try output(context, "@");
- try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, context, Errors, output);
+ try out_stream.writeAll(@typeName(@TypeOf(value).Child));
+ try out_stream.writeAll("@");
+ try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, out_stream);
return;
}
const T = @TypeOf(value);
+ if (comptime std.meta.trait.hasFn("format")(T)) {
+ return try value.format(fmt, options, out_stream);
+ }
+
switch (@typeInfo(T)) {
.ComptimeInt, .Int, .Float => {
- return formatValue(value, fmt, options, context, Errors, output);
+ return formatValue(value, fmt, options, out_stream);
},
.Void => {
- return output(context, "void");
+ return out_stream.writeAll("void");
},
.Bool => {
- return output(context, if (value) "true" else "false");
+ return out_stream.writeAll(if (value) "true" else "false");
},
.Optional => {
if (value) |payload| {
- return formatType(payload, fmt, options, context, Errors, output, max_depth);
+ return formatType(payload, fmt, options, out_stream, max_depth);
} else {
- return output(context, "null");
+ return out_stream.writeAll("null");
}
},
.ErrorUnion => {
if (value) |payload| {
- return formatType(payload, fmt, options, context, Errors, output, max_depth);
+ return formatType(payload, fmt, options, out_stream, max_depth);
} else |err| {
- return formatType(err, fmt, options, context, Errors, output, max_depth);
+ return formatType(err, fmt, options, out_stream, max_depth);
}
},
.ErrorSet => {
- try output(context, "error.");
- return output(context, @errorName(value));
+ try out_stream.writeAll("error.");
+ return out_stream.writeAll(@errorName(value));
},
.Enum => |enumInfo| {
- if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, context, Errors, output);
- }
-
- try output(context, @typeName(T));
+ try out_stream.writeAll(@typeName(T));
if (enumInfo.is_exhaustive) {
- try output(context, ".");
- try output(context, @tagName(value));
+ try out_stream.writeAll(".");
+ try out_stream.writeAll(@tagName(value));
} else {
// TODO: when @tagName works on exhaustive enums print known enum strings
- try output(context, "(");
- try formatType(@enumToInt(value), fmt, options, context, Errors, output, max_depth);
- try output(context, ")");
+ try out_stream.writeAll("(");
+ try formatType(@enumToInt(value), fmt, options, out_stream, max_depth);
+ try out_stream.writeAll(")");
}
},
.Union => {
- if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, context, Errors, output);
- }
-
- try output(context, @typeName(T));
+ try out_stream.writeAll(@typeName(T));
if (max_depth == 0) {
- return output(context, "{ ... }");
+ return out_stream.writeAll("{ ... }");
}
const info = @typeInfo(T).Union;
if (info.tag_type) |UnionTagType| {
- try output(context, "{ .");
- try output(context, @tagName(@as(UnionTagType, value)));
- try output(context, " = ");
+ try out_stream.writeAll("{ .");
+ try out_stream.writeAll(@tagName(@as(UnionTagType, value)));
+ try out_stream.writeAll(" = ");
inline for (info.fields) |u_field| {
if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
- try formatType(@field(value, u_field.name), fmt, options, context, Errors, output, max_depth - 1);
+ try formatType(@field(value, u_field.name), fmt, options, out_stream, max_depth - 1);
}
}
- try output(context, " }");
+ try out_stream.writeAll(" }");
} else {
- try format(context, Errors, output, "@{x}", .{@ptrToInt(&value)});
+ try format(out_stream, "@{x}", .{@ptrToInt(&value)});
}
},
.Struct => |StructT| {
- if (comptime std.meta.trait.hasFn("format")(T)) {
- return value.format(fmt, options, context, Errors, output);
- }
-
- try output(context, @typeName(T));
+ try out_stream.writeAll(@typeName(T));
if (max_depth == 0) {
- return output(context, "{ ... }");
+ return out_stream.writeAll("{ ... }");
}
- try output(context, "{");
+ try out_stream.writeAll("{");
inline for (StructT.fields) |f, i| {
if (i == 0) {
- try output(context, " .");
+ try out_stream.writeAll(" .");
} else {
- try output(context, ", .");
+ try out_stream.writeAll(", .");
}
- try output(context, f.name);
- try output(context, " = ");
- try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1);
+ try out_stream.writeAll(f.name);
+ try out_stream.writeAll(" = ");
+ try formatType(@field(value, f.name), fmt, options, out_stream, max_depth - 1);
}
- try output(context, " }");
+ try out_stream.writeAll(" }");
},
.Pointer => |ptr_info| switch (ptr_info.size) {
.One => switch (@typeInfo(ptr_info.child)) {
.Array => |info| {
if (info.child == u8) {
- return formatText(value, fmt, options, context, Errors, output);
+ return formatText(value, fmt, options, out_stream);
}
- return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
+ return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
},
.Enum, .Union, .Struct => {
- return formatType(value.*, fmt, options, context, Errors, output, max_depth);
+ return formatType(value.*, fmt, options, out_stream, max_depth);
},
- else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
+ else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
},
.Many, .C => {
if (ptr_info.sentinel) |sentinel| {
- return formatType(mem.span(value), fmt, options, context, Errors, output, max_depth);
+ return formatType(mem.span(value), fmt, options, out_stream, max_depth);
}
if (ptr_info.child == u8) {
if (fmt.len > 0 and fmt[0] == 's') {
- return formatText(mem.span(value), fmt, options, context, Errors, output);
+ return formatText(mem.span(value), fmt, options, out_stream);
}
}
- return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
+ return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
},
.Slice => {
if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
- return formatText(value, fmt, options, context, Errors, output);
+ return formatText(value, fmt, options, out_stream);
}
if (ptr_info.child == u8) {
- return formatText(value, fmt, options, context, Errors, output);
+ return formatText(value, fmt, options, out_stream);
}
- return format(context, Errors, output, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
+ return format(out_stream, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
},
},
.Array => |info| {
@@ -473,27 +453,27 @@ pub fn formatType(
.sentinel = null,
},
});
- return formatType(@as(Slice, &value), fmt, options, context, Errors, output, max_depth);
+ return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth);
},
.Vector => {
const len = @typeInfo(T).Vector.len;
- try output(context, "{ ");
+ try out_stream.writeAll("{ ");
var i: usize = 0;
while (i < len) : (i += 1) {
- try formatValue(value[i], fmt, options, context, Errors, output);
+ try formatValue(value[i], fmt, options, out_stream);
if (i < len - 1) {
- try output(context, ", ");
+ try out_stream.writeAll(", ");
}
}
- try output(context, " }");
+ try out_stream.writeAll(" }");
},
.Fn => {
- return format(context, Errors, output, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
+ return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
},
- .Type => return output(context, @typeName(T)),
+ .Type => return out_stream.writeAll(@typeName(T)),
.EnumLiteral => {
const buffer = [_]u8{'.'} ++ @tagName(value);
- return formatType(buffer, fmt, options, context, Errors, output, max_depth);
+ return formatType(buffer, fmt, options, out_stream, max_depth);
},
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
}
@@ -503,21 +483,19 @@ fn formatValue(
value: var,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
if (comptime std.mem.eql(u8, fmt, "B")) {
- return formatBytes(value, options, 1000, context, Errors, output);
+ return formatBytes(value, options, 1000, out_stream);
} else if (comptime std.mem.eql(u8, fmt, "Bi")) {
- return formatBytes(value, options, 1024, context, Errors, output);
+ return formatBytes(value, options, 1024, out_stream);
}
const T = @TypeOf(value);
switch (@typeInfo(T)) {
- .Float => return formatFloatValue(value, fmt, options, context, Errors, output),
- .Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output),
- .Bool => return output(context, if (value) "true" else "false"),
+ .Float => return formatFloatValue(value, fmt, options, out_stream),
+ .Int, .ComptimeInt => return formatIntValue(value, fmt, options, out_stream),
+ .Bool => return out_stream.writeAll(if (value) "true" else "false"),
else => comptime unreachable,
}
}
@@ -526,10 +504,8 @@ pub fn formatIntValue(
value: var,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
comptime var radix = 10;
comptime var uppercase = false;
@@ -544,7 +520,7 @@ pub fn formatIntValue(
uppercase = false;
} else if (comptime std.mem.eql(u8, fmt, "c")) {
if (@TypeOf(int_value).bit_count <= 8) {
- return formatAsciiChar(@as(u8, int_value), options, context, Errors, output);
+ return formatAsciiChar(@as(u8, int_value), options, out_stream);
} else {
@compileError("Cannot print integer that is larger than 8 bits as a ascii");
}
@@ -561,21 +537,19 @@ pub fn formatIntValue(
@compileError("Unknown format string: '" ++ fmt ++ "'");
}
- return formatInt(int_value, radix, uppercase, options, context, Errors, output);
+ return formatInt(int_value, radix, uppercase, options, out_stream);
}
fn formatFloatValue(
value: var,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
- return formatFloatScientific(value, options, context, Errors, output);
+ return formatFloatScientific(value, options, out_stream);
} else if (comptime std.mem.eql(u8, fmt, "d")) {
- return formatFloatDecimal(value, options, context, Errors, output);
+ return formatFloatDecimal(value, options, out_stream);
} else {
@compileError("Unknown format string: '" ++ fmt ++ "'");
}
@@ -585,17 +559,15 @@ pub fn formatText(
bytes: []const u8,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
if (fmt.len == 0) {
- return output(context, bytes);
+ return out_stream.writeAll(bytes);
} else if (comptime std.mem.eql(u8, fmt, "s")) {
- return formatBuf(bytes, options, context, Errors, output);
+ return formatBuf(bytes, options, out_stream);
} else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
for (bytes) |c| {
- try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, context, Errors, output);
+ try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, out_stream);
}
return;
} else {
@@ -606,27 +578,23 @@ pub fn formatText(
pub fn formatAsciiChar(
c: u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
- return output(context, @as(*const [1]u8, &c)[0..]);
+ out_stream: var,
+) !void {
+ return out_stream.writeAll(@as(*const [1]u8, &c)[0..]);
}
pub fn formatBuf(
buf: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
- try output(context, buf);
+ out_stream: var,
+) !void {
+ try out_stream.writeAll(buf);
const width = options.width orelse 0;
var leftover_padding = if (width > buf.len) (width - buf.len) else return;
const pad_byte: u8 = options.fill;
while (leftover_padding > 0) : (leftover_padding -= 1) {
- try output(context, @as(*const [1]u8, &pad_byte)[0..1]);
+ try out_stream.writeAll(@as(*const [1]u8, &pad_byte)[0..1]);
}
}
@@ -636,40 +604,38 @@ pub fn formatBuf(
pub fn formatFloatScientific(
value: var,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
var x = @floatCast(f64, value);
// Errol doesn't handle these special cases.
if (math.signbit(x)) {
- try output(context, "-");
+ try out_stream.writeAll("-");
x = -x;
}
if (math.isNan(x)) {
- return output(context, "nan");
+ return out_stream.writeAll("nan");
}
if (math.isPositiveInf(x)) {
- return output(context, "inf");
+ return out_stream.writeAll("inf");
}
if (x == 0.0) {
- try output(context, "0");
+ try out_stream.writeAll("0");
if (options.precision) |precision| {
if (precision != 0) {
- try output(context, ".");
+ try out_stream.writeAll(".");
var i: usize = 0;
while (i < precision) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
} else {
- try output(context, ".0");
+ try out_stream.writeAll(".0");
}
- try output(context, "e+00");
+ try out_stream.writeAll("e+00");
return;
}
@@ -679,50 +645,50 @@ pub fn formatFloatScientific(
if (options.precision) |precision| {
errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
- try output(context, float_decimal.digits[0..1]);
+ try out_stream.writeAll(float_decimal.digits[0..1]);
// {e0} case prints no `.`
if (precision != 0) {
- try output(context, ".");
+ try out_stream.writeAll(".");
var printed: usize = 0;
if (float_decimal.digits.len > 1) {
const num_digits = math.min(float_decimal.digits.len, precision + 1);
- try output(context, float_decimal.digits[1..num_digits]);
+ try out_stream.writeAll(float_decimal.digits[1..num_digits]);
printed += num_digits - 1;
}
while (printed < precision) : (printed += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
} else {
- try output(context, float_decimal.digits[0..1]);
- try output(context, ".");
+ try out_stream.writeAll(float_decimal.digits[0..1]);
+ try out_stream.writeAll(".");
if (float_decimal.digits.len > 1) {
const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;
- try output(context, float_decimal.digits[1..num_digits]);
+ try out_stream.writeAll(float_decimal.digits[1..num_digits]);
} else {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
- try output(context, "e");
+ try out_stream.writeAll("e");
const exp = float_decimal.exp - 1;
if (exp >= 0) {
- try output(context, "+");
+ try out_stream.writeAll("+");
if (exp > -10 and exp < 10) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
- try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
+ try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
} else {
- try output(context, "-");
+ try out_stream.writeAll("-");
if (exp > -10 and exp < 10) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
- try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, context, Errors, output);
+ try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
}
}
@@ -731,36 +697,34 @@ pub fn formatFloatScientific(
pub fn formatFloatDecimal(
value: var,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
var x = @as(f64, value);
// Errol doesn't handle these special cases.
if (math.signbit(x)) {
- try output(context, "-");
+ try out_stream.writeAll("-");
x = -x;
}
if (math.isNan(x)) {
- return output(context, "nan");
+ return out_stream.writeAll("nan");
}
if (math.isPositiveInf(x)) {
- return output(context, "inf");
+ return out_stream.writeAll("inf");
}
if (x == 0.0) {
- try output(context, "0");
+ try out_stream.writeAll("0");
if (options.precision) |precision| {
if (precision != 0) {
- try output(context, ".");
+ try out_stream.writeAll(".");
var i: usize = 0;
while (i < precision) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
} else {
- try output(context, ".0");
+ try out_stream.writeAll(".0");
}
}
@@ -782,14 +746,14 @@ pub fn formatFloatDecimal(
if (num_digits_whole > 0) {
// We may have to zero pad, for instance 1e4 requires zero padding.
- try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
+ try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
var i = num_digits_whole_no_pad;
while (i < num_digits_whole) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
} else {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
// {.0} special case doesn't want a trailing '.'
@@ -797,7 +761,7 @@ pub fn formatFloatDecimal(
return;
}
- try output(context, ".");
+ try out_stream.writeAll(".");
// Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
var printed: usize = 0;
@@ -809,7 +773,7 @@ pub fn formatFloatDecimal(
var i: usize = 0;
while (i < zeros_to_print) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
printed += 1;
}
@@ -821,14 +785,14 @@ pub fn formatFloatDecimal(
// Remaining fractional portion, zero-padding if insufficient.
assert(precision >= printed);
if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
- try output(context, float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
+ try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
return;
} else {
- try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
+ try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
printed += float_decimal.digits.len - num_digits_whole_no_pad;
while (printed < precision) : (printed += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
} else {
@@ -840,14 +804,14 @@ pub fn formatFloatDecimal(
if (num_digits_whole > 0) {
// We may have to zero pad, for instance 1e4 requires zero padding.
- try output(context, float_decimal.digits[0..num_digits_whole_no_pad]);
+ try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
var i = num_digits_whole_no_pad;
while (i < num_digits_whole) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
} else {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
// Omit `.` if no fractional portion
@@ -855,7 +819,7 @@ pub fn formatFloatDecimal(
return;
}
- try output(context, ".");
+ try out_stream.writeAll(".");
// Zero-fill until we reach significant digits or run out of precision.
if (float_decimal.exp < 0) {
@@ -863,11 +827,11 @@ pub fn formatFloatDecimal(
var i: usize = 0;
while (i < zero_digit_count) : (i += 1) {
- try output(context, "0");
+ try out_stream.writeAll("0");
}
}
- try output(context, float_decimal.digits[num_digits_whole_no_pad..]);
+ try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
}
}
@@ -875,12 +839,10 @@ pub fn formatBytes(
value: var,
options: FormatOptions,
comptime radix: usize,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
if (value == 0) {
- return output(context, "0B");
+ return out_stream.writeAll("0B");
}
const mags_si = " kMGTPEZY";
@@ -897,10 +859,10 @@ pub fn formatBytes(
else => unreachable,
};
- try formatFloatDecimal(new_value, options, context, Errors, output);
+ try formatFloatDecimal(new_value, options, out_stream);
if (suffix == ' ') {
- return output(context, "B");
+ return out_stream.writeAll("B");
}
const buf = switch (radix) {
@@ -908,7 +870,7 @@ pub fn formatBytes(
1024 => &[_]u8{ suffix, 'i', 'B' },
else => unreachable,
};
- return output(context, buf);
+ return out_stream.writeAll(buf);
}
pub fn formatInt(
@@ -916,10 +878,8 @@ pub fn formatInt(
base: u8,
uppercase: bool,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
const int_value = if (@TypeOf(value) == comptime_int) blk: {
const Int = math.IntFittingRange(value, value);
break :blk @as(Int, value);
@@ -927,9 +887,9 @@ pub fn formatInt(
value;
if (@TypeOf(int_value).is_signed) {
- return formatIntSigned(int_value, base, uppercase, options, context, Errors, output);
+ return formatIntSigned(int_value, base, uppercase, options, out_stream);
} else {
- return formatIntUnsigned(int_value, base, uppercase, options, context, Errors, output);
+ return formatIntUnsigned(int_value, base, uppercase, options, out_stream);
}
}
@@ -938,10 +898,8 @@ fn formatIntSigned(
base: u8,
uppercase: bool,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
const new_options = FormatOptions{
.width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
.precision = options.precision,
@@ -950,15 +908,15 @@ fn formatIntSigned(
const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
const Uint = std.meta.IntType(false, bit_count);
if (value < 0) {
- try output(context, "-");
+ try out_stream.writeAll("-");
const new_value = math.absCast(value);
- return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
+ return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
} else if (options.width == null or options.width.? == 0) {
- return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, context, Errors, output);
+ return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, out_stream);
} else {
- try output(context, "+");
+ try out_stream.writeAll("+");
const new_value = @intCast(Uint, value);
- return formatIntUnsigned(new_value, base, uppercase, new_options, context, Errors, output);
+ return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
}
}
@@ -967,10 +925,8 @@ fn formatIntUnsigned(
base: u8,
uppercase: bool,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
-) Errors!void {
+ out_stream: var,
+) !void {
assert(base >= 2);
var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count);
@@ -994,34 +950,23 @@ fn formatIntUnsigned(
const zero_byte: u8 = options.fill;
var leftover_padding = padding - index;
while (true) {
- try output(context, @as(*const [1]u8, &zero_byte)[0..]);
+ try out_stream.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
leftover_padding -= 1;
if (leftover_padding == 0) break;
}
mem.set(u8, buf[0..index], options.fill);
- return output(context, &buf);
+ return out_stream.writeAll(&buf);
} else {
const padded_buf = buf[index - padding ..];
mem.set(u8, padded_buf[0..padding], options.fill);
- return output(context, padded_buf);
+ return out_stream.writeAll(padded_buf);
}
}
pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
- var context = FormatIntBuf{
- .out_buf = out_buf,
- .index = 0,
- };
- formatInt(value, base, uppercase, options, &context, error{}, formatIntCallback) catch unreachable;
- return context.index;
-}
-const FormatIntBuf = struct {
- out_buf: []u8,
- index: usize,
-};
-fn formatIntCallback(context: *FormatIntBuf, bytes: []const u8) (error{}!void) {
- mem.copy(u8, context.out_buf[context.index..], bytes);
- context.index += bytes.len;
+ var fbs = std.io.fixedBufferStream(out_buf);
+ formatInt(value, base, uppercase, options, fbs.outStream()) catch unreachable;
+ return fbs.pos;
}
pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
@@ -1121,44 +1066,40 @@ fn digitToChar(digit: u8, uppercase: bool) u8 {
};
}
-const BufPrintContext = struct {
- remaining: []u8,
-};
-
-fn bufPrintWrite(context: *BufPrintContext, bytes: []const u8) !void {
- if (context.remaining.len < bytes.len) {
- mem.copy(u8, context.remaining, bytes[0..context.remaining.len]);
- return error.BufferTooSmall;
- }
- mem.copy(u8, context.remaining, bytes);
- context.remaining = context.remaining[bytes.len..];
-}
-
pub const BufPrintError = error{
/// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
BufferTooSmall,
};
pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
- var context = BufPrintContext{ .remaining = buf };
- try format(&context, BufPrintError, bufPrintWrite, fmt, args);
- return buf[0 .. buf.len - context.remaining.len];
+ var fbs = std.io.fixedBufferStream(buf);
+ format(fbs.outStream(), fmt, args) catch |err| switch (err) {
+ error.NoSpaceLeft => return error.BufferTooSmall,
+ };
+ //TODO: should we change one of these return signatures?
+ //return fbs.getWritten();
+ return buf[0..fbs.pos];
+}
+
+// Count the characters needed for format. Useful for preallocating memory
+pub fn count(comptime fmt: []const u8, args: var) !usize {
+ var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
+ format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
+ return std.math.cast(usize, counting_stream.bytes_written);
}
pub const AllocPrintError = error{OutOfMemory};
pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
- var size: usize = 0;
- format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
+ const size = count(fmt, args) catch |err| switch (err) {
+ // Output too long. Can't possibly allocate enough memory to display it.
+ error.Overflow => return error.OutOfMemory,
+ };
const buf = try allocator.alloc(u8, size);
return bufPrint(buf, fmt, args) catch |err| switch (err) {
error.BufferTooSmall => unreachable, // we just counted the size above
};
}
-fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
- size.* += bytes.len;
-}
-
pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
const result = try allocPrint(allocator, fmt ++ "\x00", args);
return result[0 .. result.len - 1 :0];
@@ -1251,20 +1192,17 @@ test "int.padded" {
test "buffer" {
{
var buf1: [32]u8 = undefined;
- var context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
- var res = buf1[0 .. buf1.len - context.remaining.len];
- std.testing.expect(mem.eql(u8, res, "1234"));
+ var fbs = std.io.fixedBufferStream(&buf1);
+ try formatType(1234, "", FormatOptions{}, fbs.outStream(), default_max_depth);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
- context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
- res = buf1[0 .. buf1.len - context.remaining.len];
- std.testing.expect(mem.eql(u8, res, "a"));
+ fbs.reset();
+ try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "a"));
- context = BufPrintContext{ .remaining = buf1[0..] };
- try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
- res = buf1[0 .. buf1.len - context.remaining.len];
- std.testing.expect(mem.eql(u8, res, "1100"));
+ fbs.reset();
+ try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100"));
}
}
@@ -1449,14 +1387,12 @@ test "custom" {
self: SelfType,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
- ) Errors!void {
+ out_stream: var,
+ ) !void {
if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
- return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });
+ return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
} else if (comptime std.mem.eql(u8, fmt, "d")) {
- return std.fmt.format(context, Errors, output, "{d:.3}x{d:.3}", .{ self.x, self.y });
+ return std.fmt.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
} else {
@compileError("Unknown format character: '" ++ fmt ++ "'");
}
@@ -1640,10 +1576,10 @@ test "hexToBytes" {
test "formatIntValue with comptime_int" {
const value: comptime_int = 123456789123456789;
- var buf = std.ArrayList(u8).init(std.testing.allocator);
- defer buf.deinit();
- try formatIntValue(value, "", FormatOptions{}, &buf, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice);
- std.testing.expect(mem.eql(u8, buf.toSliceConst(), "123456789123456789"));
+ var buf: [20]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buf);
+ try formatIntValue(value, "", FormatOptions{}, fbs.outStream());
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789"));
}
test "formatType max_depth" {
@@ -1656,12 +1592,10 @@ test "formatType max_depth" {
self: SelfType,
comptime fmt: []const u8,
options: FormatOptions,
- context: var,
- comptime Errors: type,
- comptime output: fn (@TypeOf(context), []const u8) Errors!void,
- ) Errors!void {
+ out_stream: var,
+ ) !void {
if (fmt.len == 0) {
- return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", .{ self.x, self.y });
+ return std.fmt.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
} else {
@compileError("Unknown format string: '" ++ fmt ++ "'");
}
@@ -1695,25 +1629,22 @@ test "formatType max_depth" {
inst.a = &inst;
inst.tu.ptr = &inst.tu;
- var buf0 = std.ArrayList(u8).init(std.testing.allocator);
- defer buf0.deinit();
- try formatType(inst, "", FormatOptions{}, &buf0, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 0);
- std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
+ var buf: [1000]u8 = undefined;
+ var fbs = std.io.fixedBufferStream(&buf);
+ try formatType(inst, "", FormatOptions{}, fbs.outStream(), 0);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));
- var buf1 = std.ArrayList(u8).init(std.testing.allocator);
- defer buf1.deinit();
- try formatType(inst, "", FormatOptions{}, &buf1, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 1);
- std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
+ fbs.reset();
+ try formatType(inst, "", FormatOptions{}, fbs.outStream(), 1);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
- var buf2 = std.ArrayList(u8).init(std.testing.allocator);
- defer buf2.deinit();
- try formatType(inst, "", FormatOptions{}, &buf2, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 2);
- std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
+ fbs.reset();
+ try formatType(inst, "", FormatOptions{}, fbs.outStream(), 2);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
- var buf3 = std.ArrayList(u8).init(std.testing.allocator);
- defer buf3.deinit();
- try formatType(inst, "", FormatOptions{}, &buf3, @TypeOf(std.ArrayList(u8).appendSlice).ReturnType.ErrorSet, std.ArrayList(u8).appendSlice, 3);
- std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
+ fbs.reset();
+ try formatType(inst, "", FormatOptions{}, fbs.outStream(), 3);
+ std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
}
test "positional" {
diff --git a/lib/std/fmtstream.zig b/lib/std/fmtstream.zig
deleted file mode 100644
index 93734d42a..000000000
--- a/lib/std/fmtstream.zig
+++ /dev/null
@@ -1,1685 +0,0 @@
-const std = @import("std.zig");
-const math = std.math;
-const assert = std.debug.assert;
-const mem = std.mem;
-const builtin = @import("builtin");
-const errol = @import("fmt/errol.zig");
-const lossyCast = std.math.lossyCast;
-
-pub const default_max_depth = 3;
-
-pub const Alignment = enum {
- Left,
- Center,
- Right,
-};
-
-pub const FormatOptions = struct {
- precision: ?usize = null,
- width: ?usize = null,
- alignment: ?Alignment = null,
- fill: u8 = ' ',
-};
-
-fn peekIsAlign(comptime fmt: []const u8) bool {
- // Should only be called during a state transition to the format segment.
- comptime assert(fmt[0] == ':');
-
- inline for (([_]u8{ 1, 2 })[0..]) |i| {
- if (fmt.len > i and (fmt[i] == '<' or fmt[i] == '^' or fmt[i] == '>')) {
- return true;
- }
- }
- return false;
-}
-
-/// Renders fmt string with args, calling output with slices of bytes.
-/// If `output` returns an error, the error is returned from `format` and
-/// `output` is not called again.
-///
-/// The format string must be comptime known and may contain placeholders following
-/// this format:
-/// `{[position][specifier]:[fill][alignment][width].[precision]}`
-///
-/// Each word between `[` and `]` is a parameter you have to replace with something:
-///
-/// - *position* is the index of the argument that should be inserted
-/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
-/// - *fill* is a single character which is used to pad the formatted text
-/// - *alignment* is one of the three characters `<`, `^` or `>`. they define if the text is *left*, *center*, or *right* aligned
-/// - *width* is the total width of the field in characters
-/// - *precision* specifies how many decimals a formatted number should have
-///
-/// Note that most of the parameters are optional and may be omitted. Also you can leave out separators like `:` and `.` when
-/// all parameters after the separator are omitted.
-/// Only exception is the *fill* parameter. If *fill* is required, one has to specify *alignment* as well, as otherwise
-/// the digits after `:` is interpreted as *width*, not *fill*.
-///
-/// The *specifier* has several options for types:
-/// - `x` and `X`:
-/// - format the non-numeric value as a string of bytes in hexadecimal notation ("binary dump") in either lower case or upper case
-/// - output numeric value in hexadecimal notation
-/// - `s`: print a pointer-to-many as a c-string, use zero-termination
-/// - `B` and `Bi`: output a memory size in either metric (1000) or power-of-two (1024) based notation. works for both float and integer values.
-/// - `e`: output floating point value in scientific notation
-/// - `d`: output numeric value in decimal notation
-/// - `b`: output integer value in binary notation
-/// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max.
-/// - `*`: output the address of the value instead of the value itself.
-///
-/// If a formatted user type contains a function of the type
-/// ```
-/// fn format(value: ?, comptime fmt: []const u8, options: std.fmtstream.FormatOptions, out_stream: var) !void
-/// ```
-/// with `?` being the type formatted, this function will be called instead of the default implementation.
-/// This allows user types to be formatted in a logical manner instead of dumping all fields of the type.
-///
-/// A user type may be a `struct`, `vector`, `union` or `enum` type.
-pub fn format(
- out_stream: var,
- comptime fmt: []const u8,
- args: var,
-) !void {
- const ArgSetType = u32;
- if (@typeInfo(@TypeOf(args)) != .Struct) {
- @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
- }
- if (args.len > ArgSetType.bit_count) {
- @compileError("32 arguments max are supported per format call");
- }
-
- const State = enum {
- Start,
- Positional,
- CloseBrace,
- Specifier,
- FormatFillAndAlign,
- FormatWidth,
- FormatPrecision,
- };
-
- comptime var start_index = 0;
- comptime var state = State.Start;
- comptime var maybe_pos_arg: ?comptime_int = null;
- comptime var specifier_start = 0;
- comptime var specifier_end = 0;
- comptime var options = FormatOptions{};
- comptime var arg_state: struct {
- next_arg: usize = 0,
- used_args: ArgSetType = 0,
- args_len: usize = args.len,
-
- fn hasUnusedArgs(comptime self: *@This()) bool {
- return (@popCount(ArgSetType, self.used_args) != self.args_len);
- }
-
- fn nextArg(comptime self: *@This(), comptime pos_arg: ?comptime_int) comptime_int {
- const next_idx = pos_arg orelse blk: {
- const arg = self.next_arg;
- self.next_arg += 1;
- break :blk arg;
- };
-
- if (next_idx >= self.args_len) {
- @compileError("Too few arguments");
- }
-
- // Mark this argument as used
- self.used_args |= 1 << next_idx;
-
- return next_idx;
- }
- } = .{};
-
- inline for (fmt) |c, i| {
- switch (state) {
- .Start => switch (c) {
- '{' => {
- if (start_index < i) {
- try out_stream.writeAll(fmt[start_index..i]);
- }
-
- start_index = i;
- specifier_start = i + 1;
- specifier_end = i + 1;
- maybe_pos_arg = null;
- state = .Positional;
- options = FormatOptions{};
- },
- '}' => {
- if (start_index < i) {
- try out_stream.writeAll(fmt[start_index..i]);
- }
- state = .CloseBrace;
- },
- else => {},
- },
- .Positional => switch (c) {
- '{' => {
- state = .Start;
- start_index = i;
- },
- ':' => {
- state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
- specifier_end = i;
- },
- '0'...'9' => {
- if (maybe_pos_arg == null) {
- maybe_pos_arg = 0;
- }
-
- maybe_pos_arg.? *= 10;
- maybe_pos_arg.? += c - '0';
- specifier_start = i + 1;
-
- if (maybe_pos_arg.? >= args.len) {
- @compileError("Positional value refers to non-existent argument");
- }
- },
- '}' => {
- const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
-
- try formatType(
- args[arg_to_print],
- fmt[0..0],
- options,
- out_stream,
- default_max_depth,
- );
-
- state = .Start;
- start_index = i + 1;
- },
- else => {
- state = .Specifier;
- specifier_start = i;
- },
- },
- .CloseBrace => switch (c) {
- '}' => {
- state = .Start;
- start_index = i;
- },
- else => @compileError("Single '}' encountered in format string"),
- },
- .Specifier => switch (c) {
- ':' => {
- specifier_end = i;
- state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
- },
- '}' => {
- const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
-
- try formatType(
- args[arg_to_print],
- fmt[specifier_start..i],
- options,
- out_stream,
- default_max_depth,
- );
- state = .Start;
- start_index = i + 1;
- },
- else => {},
- },
- // Only entered if the format string contains a fill/align segment.
- .FormatFillAndAlign => switch (c) {
- '<' => {
- options.alignment = Alignment.Left;
- state = .FormatWidth;
- },
- '^' => {
- options.alignment = Alignment.Center;
- state = .FormatWidth;
- },
- '>' => {
- options.alignment = Alignment.Right;
- state = .FormatWidth;
- },
- else => {
- options.fill = c;
- },
- },
- .FormatWidth => switch (c) {
- '0'...'9' => {
- if (options.width == null) {
- options.width = 0;
- }
-
- options.width.? *= 10;
- options.width.? += c - '0';
- },
- '.' => {
- state = .FormatPrecision;
- },
- '}' => {
- const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
-
- try formatType(
- args[arg_to_print],
- fmt[specifier_start..specifier_end],
- options,
- out_stream,
- default_max_depth,
- );
- state = .Start;
- start_index = i + 1;
- },
- else => {
- @compileError("Unexpected character in width value: " ++ [_]u8{c});
- },
- },
- .FormatPrecision => switch (c) {
- '0'...'9' => {
- if (options.precision == null) {
- options.precision = 0;
- }
-
- options.precision.? *= 10;
- options.precision.? += c - '0';
- },
- '}' => {
- const arg_to_print = comptime arg_state.nextArg(maybe_pos_arg);
-
- try formatType(
- args[arg_to_print],
- fmt[specifier_start..specifier_end],
- options,
- out_stream,
- default_max_depth,
- );
- state = .Start;
- start_index = i + 1;
- },
- else => {
- @compileError("Unexpected character in precision value: " ++ [_]u8{c});
- },
- },
- }
- }
- comptime {
- if (comptime arg_state.hasUnusedArgs()) {
- @compileError("Unused arguments");
- }
- if (state != State.Start) {
- @compileError("Incomplete format string: " ++ fmt);
- }
- }
- if (start_index < fmt.len) {
- try out_stream.writeAll(fmt[start_index..]);
- }
-}
-
-pub fn formatType(
- value: var,
- comptime fmt: []const u8,
- options: FormatOptions,
- out_stream: var,
- max_depth: usize,
-) @TypeOf(out_stream).Error!void {
- if (comptime std.mem.eql(u8, fmt, "*")) {
- try out_stream.writeAll(@typeName(@TypeOf(value).Child));
- try out_stream.writeAll("@");
- try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, out_stream);
- return;
- }
-
- const T = @TypeOf(value);
- if (comptime std.meta.trait.hasFn("format")(T)) {
- return try value.format(fmt, options, out_stream);
- }
-
- switch (@typeInfo(T)) {
- .ComptimeInt, .Int, .Float => {
- return formatValue(value, fmt, options, out_stream);
- },
- .Void => {
- return out_stream.writeAll("void");
- },
- .Bool => {
- return out_stream.writeAll(if (value) "true" else "false");
- },
- .Optional => {
- if (value) |payload| {
- return formatType(payload, fmt, options, out_stream, max_depth);
- } else {
- return out_stream.writeAll("null");
- }
- },
- .ErrorUnion => {
- if (value) |payload| {
- return formatType(payload, fmt, options, out_stream, max_depth);
- } else |err| {
- return formatType(err, fmt, options, out_stream, max_depth);
- }
- },
- .ErrorSet => {
- try out_stream.writeAll("error.");
- return out_stream.writeAll(@errorName(value));
- },
- .Enum => |enumInfo| {
- try out_stream.writeAll(@typeName(T));
- if (enumInfo.is_exhaustive) {
- try out_stream.writeAll(".");
- try out_stream.writeAll(@tagName(value));
- } else {
- // TODO: when @tagName works on exhaustive enums print known enum strings
- try out_stream.writeAll("(");
- try formatType(@enumToInt(value), fmt, options, out_stream, max_depth);
- try out_stream.writeAll(")");
- }
- },
- .Union => {
- try out_stream.writeAll(@typeName(T));
- if (max_depth == 0) {
- return out_stream.writeAll("{ ... }");
- }
- const info = @typeInfo(T).Union;
- if (info.tag_type) |UnionTagType| {
- try out_stream.writeAll("{ .");
- try out_stream.writeAll(@tagName(@as(UnionTagType, value)));
- try out_stream.writeAll(" = ");
- inline for (info.fields) |u_field| {
- if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) {
- try formatType(@field(value, u_field.name), fmt, options, out_stream, max_depth - 1);
- }
- }
- try out_stream.writeAll(" }");
- } else {
- try format(out_stream, "@{x}", .{@ptrToInt(&value)});
- }
- },
- .Struct => |StructT| {
- try out_stream.writeAll(@typeName(T));
- if (max_depth == 0) {
- return out_stream.writeAll("{ ... }");
- }
- try out_stream.writeAll("{");
- inline for (StructT.fields) |f, i| {
- if (i == 0) {
- try out_stream.writeAll(" .");
- } else {
- try out_stream.writeAll(", .");
- }
- try out_stream.writeAll(f.name);
- try out_stream.writeAll(" = ");
- try formatType(@field(value, f.name), fmt, options, out_stream, max_depth - 1);
- }
- try out_stream.writeAll(" }");
- },
- .Pointer => |ptr_info| switch (ptr_info.size) {
- .One => switch (@typeInfo(ptr_info.child)) {
- .Array => |info| {
- if (info.child == u8) {
- return formatText(value, fmt, options, out_stream);
- }
- return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
- },
- .Enum, .Union, .Struct => {
- return formatType(value.*, fmt, options, out_stream, max_depth);
- },
- else => return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
- },
- .Many, .C => {
- if (ptr_info.sentinel) |sentinel| {
- return formatType(mem.span(value), fmt, options, out_stream, max_depth);
- }
- if (ptr_info.child == u8) {
- if (fmt.len > 0 and fmt[0] == 's') {
- return formatText(mem.span(value), fmt, options, out_stream);
- }
- }
- return format(out_stream, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
- },
- .Slice => {
- if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
- return formatText(value, fmt, options, out_stream);
- }
- if (ptr_info.child == u8) {
- return formatText(value, fmt, options, out_stream);
- }
- return format(out_stream, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
- },
- },
- .Array => |info| {
- const Slice = @Type(builtin.TypeInfo{
- .Pointer = .{
- .size = .Slice,
- .is_const = true,
- .is_volatile = false,
- .is_allowzero = false,
- .alignment = @alignOf(info.child),
- .child = info.child,
- .sentinel = null,
- },
- });
- return formatType(@as(Slice, &value), fmt, options, out_stream, max_depth);
- },
- .Vector => {
- const len = @typeInfo(T).Vector.len;
- try out_stream.writeAll("{ ");
- var i: usize = 0;
- while (i < len) : (i += 1) {
- try formatValue(value[i], fmt, options, out_stream);
- if (i < len - 1) {
- try out_stream.writeAll(", ");
- }
- }
- try out_stream.writeAll(" }");
- },
- .Fn => {
- return format(out_stream, "{}@{x}", .{ @typeName(T), @ptrToInt(value) });
- },
- .Type => return out_stream.writeAll(@typeName(T)),
- .EnumLiteral => {
- const buffer = [_]u8{'.'} ++ @tagName(value);
- return formatType(buffer, fmt, options, out_stream, max_depth);
- },
- else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
- }
-}
-
-fn formatValue(
- value: var,
- comptime fmt: []const u8,
- options: FormatOptions,
- out_stream: var,
-) !void {
- if (comptime std.mem.eql(u8, fmt, "B")) {
- return formatBytes(value, options, 1000, out_stream);
- } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
- return formatBytes(value, options, 1024, out_stream);
- }
-
- const T = @TypeOf(value);
- switch (@typeInfo(T)) {
- .Float => return formatFloatValue(value, fmt, options, out_stream),
- .Int, .ComptimeInt => return formatIntValue(value, fmt, options, out_stream),
- .Bool => return out_stream.writeAll(if (value) "true" else "false"),
- else => comptime unreachable,
- }
-}
-
-pub fn formatIntValue(
- value: var,
- comptime fmt: []const u8,
- options: FormatOptions,
- out_stream: var,
-) !void {
- comptime var radix = 10;
- comptime var uppercase = false;
-
- const int_value = if (@TypeOf(value) == comptime_int) blk: {
- const Int = math.IntFittingRange(value, value);
- break :blk @as(Int, value);
- } else
- value;
-
- if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
- radix = 10;
- uppercase = false;
- } else if (comptime std.mem.eql(u8, fmt, "c")) {
- if (@TypeOf(int_value).bit_count <= 8) {
- return formatAsciiChar(@as(u8, int_value), options, out_stream);
- } else {
- @compileError("Cannot print integer that is larger than 8 bits as a ascii");
- }
- } else if (comptime std.mem.eql(u8, fmt, "b")) {
- radix = 2;
- uppercase = false;
- } else if (comptime std.mem.eql(u8, fmt, "x")) {
- radix = 16;
- uppercase = false;
- } else if (comptime std.mem.eql(u8, fmt, "X")) {
- radix = 16;
- uppercase = true;
- } else {
- @compileError("Unknown format string: '" ++ fmt ++ "'");
- }
-
- return formatInt(int_value, radix, uppercase, options, out_stream);
-}
-
-fn formatFloatValue(
- value: var,
- comptime fmt: []const u8,
- options: FormatOptions,
- out_stream: var,
-) !void {
- if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
- return formatFloatScientific(value, options, out_stream);
- } else if (comptime std.mem.eql(u8, fmt, "d")) {
- return formatFloatDecimal(value, options, out_stream);
- } else {
- @compileError("Unknown format string: '" ++ fmt ++ "'");
- }
-}
-
-pub fn formatText(
- bytes: []const u8,
- comptime fmt: []const u8,
- options: FormatOptions,
- out_stream: var,
-) !void {
- if (fmt.len == 0) {
- return out_stream.writeAll(bytes);
- } else if (comptime std.mem.eql(u8, fmt, "s")) {
- return formatBuf(bytes, options, out_stream);
- } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
- for (bytes) |c| {
- try formatInt(c, 16, fmt[0] == 'X', FormatOptions{ .width = 2, .fill = '0' }, out_stream);
- }
- return;
- } else {
- @compileError("Unknown format string: '" ++ fmt ++ "'");
- }
-}
-
-pub fn formatAsciiChar(
- c: u8,
- options: FormatOptions,
- out_stream: var,
-) !void {
- return out_stream.writeAll(@as(*const [1]u8, &c)[0..]);
-}
-
-pub fn formatBuf(
- buf: []const u8,
- options: FormatOptions,
- out_stream: var,
-) !void {
- try out_stream.writeAll(buf);
-
- const width = options.width orelse 0;
- var leftover_padding = if (width > buf.len) (width - buf.len) else return;
- const pad_byte: u8 = options.fill;
- while (leftover_padding > 0) : (leftover_padding -= 1) {
- try out_stream.writeAll(@as(*const [1]u8, &pad_byte)[0..1]);
- }
-}
-
-// Print a float in scientific notation to the specified precision. Null uses full precision.
-// It should be the case that every full precision, printed value can be re-parsed back to the
-// same type unambiguously.
-pub fn formatFloatScientific(
- value: var,
- options: FormatOptions,
- out_stream: var,
-) !void {
- var x = @floatCast(f64, value);
-
- // Errol doesn't handle these special cases.
- if (math.signbit(x)) {
- try out_stream.writeAll("-");
- x = -x;
- }
-
- if (math.isNan(x)) {
- return out_stream.writeAll("nan");
- }
- if (math.isPositiveInf(x)) {
- return out_stream.writeAll("inf");
- }
- if (x == 0.0) {
- try out_stream.writeAll("0");
-
- if (options.precision) |precision| {
- if (precision != 0) {
- try out_stream.writeAll(".");
- var i: usize = 0;
- while (i < precision) : (i += 1) {
- try out_stream.writeAll("0");
- }
- }
- } else {
- try out_stream.writeAll(".0");
- }
-
- try out_stream.writeAll("e+00");
- return;
- }
-
- var buffer: [32]u8 = undefined;
- var float_decimal = errol.errol3(x, buffer[0..]);
-
- if (options.precision) |precision| {
- errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Scientific);
-
- try out_stream.writeAll(float_decimal.digits[0..1]);
-
- // {e0} case prints no `.`
- if (precision != 0) {
- try out_stream.writeAll(".");
-
- var printed: usize = 0;
- if (float_decimal.digits.len > 1) {
- const num_digits = math.min(float_decimal.digits.len, precision + 1);
- try out_stream.writeAll(float_decimal.digits[1..num_digits]);
- printed += num_digits - 1;
- }
-
- while (printed < precision) : (printed += 1) {
- try out_stream.writeAll("0");
- }
- }
- } else {
- try out_stream.writeAll(float_decimal.digits[0..1]);
- try out_stream.writeAll(".");
- if (float_decimal.digits.len > 1) {
- const num_digits = if (@TypeOf(value) == f32) math.min(@as(usize, 9), float_decimal.digits.len) else float_decimal.digits.len;
-
- try out_stream.writeAll(float_decimal.digits[1..num_digits]);
- } else {
- try out_stream.writeAll("0");
- }
- }
-
- try out_stream.writeAll("e");
- const exp = float_decimal.exp - 1;
-
- if (exp >= 0) {
- try out_stream.writeAll("+");
- if (exp > -10 and exp < 10) {
- try out_stream.writeAll("0");
- }
- try formatInt(exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
- } else {
- try out_stream.writeAll("-");
- if (exp > -10 and exp < 10) {
- try out_stream.writeAll("0");
- }
- try formatInt(-exp, 10, false, FormatOptions{ .width = 0 }, out_stream);
- }
-}
-
-// Print a float of the format x.yyyyy where the number of y is specified by the precision argument.
-// By default floats are printed at full precision (no rounding).
-pub fn formatFloatDecimal(
- value: var,
- options: FormatOptions,
- out_stream: var,
-) !void {
- var x = @as(f64, value);
-
- // Errol doesn't handle these special cases.
- if (math.signbit(x)) {
- try out_stream.writeAll("-");
- x = -x;
- }
-
- if (math.isNan(x)) {
- return out_stream.writeAll("nan");
- }
- if (math.isPositiveInf(x)) {
- return out_stream.writeAll("inf");
- }
- if (x == 0.0) {
- try out_stream.writeAll("0");
-
- if (options.precision) |precision| {
- if (precision != 0) {
- try out_stream.writeAll(".");
- var i: usize = 0;
- while (i < precision) : (i += 1) {
- try out_stream.writeAll("0");
- }
- } else {
- try out_stream.writeAll(".0");
- }
- }
-
- return;
- }
-
- // non-special case, use errol3
- var buffer: [32]u8 = undefined;
- var float_decimal = errol.errol3(x, buffer[0..]);
-
- if (options.precision) |precision| {
- errol.roundToPrecision(&float_decimal, precision, errol.RoundMode.Decimal);
-
- // exp < 0 means the leading is always 0 as errol result is normalized.
- var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
-
- // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
- var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
-
- if (num_digits_whole > 0) {
- // We may have to zero pad, for instance 1e4 requires zero padding.
- try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
-
- var i = num_digits_whole_no_pad;
- while (i < num_digits_whole) : (i += 1) {
- try out_stream.writeAll("0");
- }
- } else {
- try out_stream.writeAll("0");
- }
-
- // {.0} special case doesn't want a trailing '.'
- if (precision == 0) {
- return;
- }
-
- try out_stream.writeAll(".");
-
- // Keep track of fractional count printed for case where we pre-pad then post-pad with 0's.
- var printed: usize = 0;
-
- // Zero-fill until we reach significant digits or run out of precision.
- if (float_decimal.exp <= 0) {
- const zero_digit_count = @intCast(usize, -float_decimal.exp);
- const zeros_to_print = math.min(zero_digit_count, precision);
-
- var i: usize = 0;
- while (i < zeros_to_print) : (i += 1) {
- try out_stream.writeAll("0");
- printed += 1;
- }
-
- if (printed >= precision) {
- return;
- }
- }
-
- // Remaining fractional portion, zero-padding if insufficient.
- assert(precision >= printed);
- if (num_digits_whole_no_pad + precision - printed < float_decimal.digits.len) {
- try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad .. num_digits_whole_no_pad + precision - printed]);
- return;
- } else {
- try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
- printed += float_decimal.digits.len - num_digits_whole_no_pad;
-
- while (printed < precision) : (printed += 1) {
- try out_stream.writeAll("0");
- }
- }
- } else {
- // exp < 0 means the leading is always 0 as errol result is normalized.
- var num_digits_whole = if (float_decimal.exp > 0) @intCast(usize, float_decimal.exp) else 0;
-
- // the actual slice into the buffer, we may need to zero-pad between num_digits_whole and this.
- var num_digits_whole_no_pad = math.min(num_digits_whole, float_decimal.digits.len);
-
- if (num_digits_whole > 0) {
- // We may have to zero pad, for instance 1e4 requires zero padding.
- try out_stream.writeAll(float_decimal.digits[0..num_digits_whole_no_pad]);
-
- var i = num_digits_whole_no_pad;
- while (i < num_digits_whole) : (i += 1) {
- try out_stream.writeAll("0");
- }
- } else {
- try out_stream.writeAll("0");
- }
-
- // Omit `.` if no fractional portion
- if (float_decimal.exp >= 0 and num_digits_whole_no_pad == float_decimal.digits.len) {
- return;
- }
-
- try out_stream.writeAll(".");
-
- // Zero-fill until we reach significant digits or run out of precision.
- if (float_decimal.exp < 0) {
- const zero_digit_count = @intCast(usize, -float_decimal.exp);
-
- var i: usize = 0;
- while (i < zero_digit_count) : (i += 1) {
- try out_stream.writeAll("0");
- }
- }
-
- try out_stream.writeAll(float_decimal.digits[num_digits_whole_no_pad..]);
- }
-}
-
-pub fn formatBytes(
- value: var,
- options: FormatOptions,
- comptime radix: usize,
- out_stream: var,
-) !void {
- if (value == 0) {
- return out_stream.writeAll("0B");
- }
-
- const mags_si = " kMGTPEZY";
- const mags_iec = " KMGTPEZY";
- const magnitude = switch (radix) {
- 1000 => math.min(math.log2(value) / comptime math.log2(1000), mags_si.len - 1),
- 1024 => math.min(math.log2(value) / 10, mags_iec.len - 1),
- else => unreachable,
- };
- const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, radix), lossyCast(f64, magnitude));
- const suffix = switch (radix) {
- 1000 => mags_si[magnitude],
- 1024 => mags_iec[magnitude],
- else => unreachable,
- };
-
- try formatFloatDecimal(new_value, options, out_stream);
-
- if (suffix == ' ') {
- return out_stream.writeAll("B");
- }
-
- const buf = switch (radix) {
- 1000 => &[_]u8{ suffix, 'B' },
- 1024 => &[_]u8{ suffix, 'i', 'B' },
- else => unreachable,
- };
- return out_stream.writeAll(buf);
-}
-
-pub fn formatInt(
- value: var,
- base: u8,
- uppercase: bool,
- options: FormatOptions,
- out_stream: var,
-) !void {
- const int_value = if (@TypeOf(value) == comptime_int) blk: {
- const Int = math.IntFittingRange(value, value);
- break :blk @as(Int, value);
- } else
- value;
-
- if (@TypeOf(int_value).is_signed) {
- return formatIntSigned(int_value, base, uppercase, options, out_stream);
- } else {
- return formatIntUnsigned(int_value, base, uppercase, options, out_stream);
- }
-}
-
-fn formatIntSigned(
- value: var,
- base: u8,
- uppercase: bool,
- options: FormatOptions,
- out_stream: var,
-) !void {
- const new_options = FormatOptions{
- .width = if (options.width) |w| (if (w == 0) 0 else w - 1) else null,
- .precision = options.precision,
- .fill = options.fill,
- };
- const bit_count = @typeInfo(@TypeOf(value)).Int.bits;
- const Uint = std.meta.IntType(false, bit_count);
- if (value < 0) {
- try out_stream.writeAll("-");
- const new_value = math.absCast(value);
- return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
- } else if (options.width == null or options.width.? == 0) {
- return formatIntUnsigned(@intCast(Uint, value), base, uppercase, options, out_stream);
- } else {
- try out_stream.writeAll("+");
- const new_value = @intCast(Uint, value);
- return formatIntUnsigned(new_value, base, uppercase, new_options, out_stream);
- }
-}
-
-fn formatIntUnsigned(
- value: var,
- base: u8,
- uppercase: bool,
- options: FormatOptions,
- out_stream: var,
-) !void {
- assert(base >= 2);
- var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined;
- const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count);
- const MinInt = std.meta.IntType(@TypeOf(value).is_signed, min_int_bits);
- var a: MinInt = value;
- var index: usize = buf.len;
-
- while (true) {
- const digit = a % base;
- index -= 1;
- buf[index] = digitToChar(@intCast(u8, digit), uppercase);
- a /= base;
- if (a == 0) break;
- }
-
- const digits_buf = buf[index..];
- const width = options.width orelse 0;
- const padding = if (width > digits_buf.len) (width - digits_buf.len) else 0;
-
- if (padding > index) {
- const zero_byte: u8 = options.fill;
- var leftover_padding = padding - index;
- while (true) {
- try out_stream.writeAll(@as(*const [1]u8, &zero_byte)[0..]);
- leftover_padding -= 1;
- if (leftover_padding == 0) break;
- }
- mem.set(u8, buf[0..index], options.fill);
- return out_stream.writeAll(&buf);
- } else {
- const padded_buf = buf[index - padding ..];
- mem.set(u8, padded_buf[0..padding], options.fill);
- return out_stream.writeAll(padded_buf);
- }
-}
-
-pub fn formatIntBuf(out_buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) usize {
- var fbs = std.io.fixedBufferStream(out_buf);
- formatInt(value, base, uppercase, options, fbs.outStream()) catch unreachable;
- return fbs.pos;
-}
-
-pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T {
- if (!T.is_signed) return parseUnsigned(T, buf, radix);
- if (buf.len == 0) return @as(T, 0);
- if (buf[0] == '-') {
- return math.negate(try parseUnsigned(T, buf[1..], radix));
- } else if (buf[0] == '+') {
- return parseUnsigned(T, buf[1..], radix);
- } else {
- return parseUnsigned(T, buf, radix);
- }
-}
-
-test "parseInt" {
- std.testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10);
- std.testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10);
- std.testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter);
- std.testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter);
- std.testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter);
- std.testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255);
- std.testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow);
-}
-
-pub const ParseUnsignedError = error{
- /// The result cannot fit in the type specified
- Overflow,
-
- /// The input had a byte that was not a digit
- InvalidCharacter,
-};
-
-pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsignedError!T {
- var x: T = 0;
-
- for (buf) |c| {
- const digit = try charToDigit(c, radix);
-
- if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
- x = try math.add(T, x, try math.cast(T, digit));
- }
-
- return x;
-}
-
-test "parseUnsigned" {
- std.testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
- std.testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
- std.testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
-
- std.testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
- std.testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16));
-
- std.testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
-
- std.testing.expect((try parseUnsigned(u7, "1", 10)) == 1);
- std.testing.expect((try parseUnsigned(u7, "1000", 2)) == 8);
-
- std.testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10));
- std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8));
-
- std.testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
-
- // these numbers should fit even though the radix itself doesn't fit in the destination type
- std.testing.expect((try parseUnsigned(u1, "0", 10)) == 0);
- std.testing.expect((try parseUnsigned(u1, "1", 10)) == 1);
- std.testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10));
- std.testing.expect((try parseUnsigned(u1, "001", 16)) == 1);
- std.testing.expect((try parseUnsigned(u2, "3", 16)) == 3);
- std.testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
-}
-
-pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
-
-test "parseFloat" {
- _ = @import("fmt/parse_float.zig");
-}
-
-pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
- const value = switch (c) {
- '0'...'9' => c - '0',
- 'A'...'Z' => c - 'A' + 10,
- 'a'...'z' => c - 'a' + 10,
- else => return error.InvalidCharacter,
- };
-
- if (value >= radix) return error.InvalidCharacter;
-
- return value;
-}
-
-fn digitToChar(digit: u8, uppercase: bool) u8 {
- return switch (digit) {
- 0...9 => digit + '0',
- 10...35 => digit + ((if (uppercase) @as(u8, 'A') else @as(u8, 'a')) - 10),
- else => unreachable,
- };
-}
-
-pub const BufPrintError = error{
- /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes.
- BufferTooSmall,
-};
-pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: var) BufPrintError![]u8 {
- var fbs = std.io.fixedBufferStream(buf);
- format(fbs.outStream(), fmt, args) catch |err| switch (err) {
- error.NoSpaceLeft => return error.BufferTooSmall,
- };
- //TODO: should we change one of these return signatures?
- //return fbs.getWritten();
- return buf[0..fbs.pos];
-}
-
-// Count the characters needed for format. Useful for preallocating memory
-pub fn count(comptime fmt: []const u8, args: var) !usize {
- var counting_stream = std.io.countingOutStream(std.io.null_out_stream);
- format(counting_stream.outStream(), fmt, args) catch |err| switch (err) {};
- return std.math.cast(usize, counting_stream.bytes_written);
-}
-
-pub const AllocPrintError = error{OutOfMemory};
-
-pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![]u8 {
- const size = count(fmt, args) catch |err| switch (err) {
- // Output too long. Can't possibly allocate enough memory to display it.
- error.Overflow => return error.OutOfMemory,
- };
- const buf = try allocator.alloc(u8, size);
- return bufPrint(buf, fmt, args) catch |err| switch (err) {
- error.BufferTooSmall => unreachable, // we just counted the size above
- };
-}
-
-pub fn allocPrint0(allocator: *mem.Allocator, comptime fmt: []const u8, args: var) AllocPrintError![:0]u8 {
- const result = try allocPrint(allocator, fmt ++ "\x00", args);
- return result[0 .. result.len - 1 :0];
-}
-
-test "bufPrintInt" {
- var buffer: [100]u8 = undefined;
- const buf = buffer[0..];
-
- std.testing.expectEqualSlices(u8, "-1", bufPrintIntToSlice(buf, @as(i1, -1), 10, false, FormatOptions{}));
-
- std.testing.expectEqualSlices(u8, "-101111000110000101001110", bufPrintIntToSlice(buf, @as(i32, -12345678), 2, false, FormatOptions{}));
- std.testing.expectEqualSlices(u8, "-12345678", bufPrintIntToSlice(buf, @as(i32, -12345678), 10, false, FormatOptions{}));
- std.testing.expectEqualSlices(u8, "-bc614e", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, false, FormatOptions{}));
- std.testing.expectEqualSlices(u8, "-BC614E", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, true, FormatOptions{}));
-
- std.testing.expectEqualSlices(u8, "12345678", bufPrintIntToSlice(buf, @as(u32, 12345678), 10, true, FormatOptions{}));
-
- std.testing.expectEqualSlices(u8, " 666", bufPrintIntToSlice(buf, @as(u32, 666), 10, false, FormatOptions{ .width = 6 }));
- std.testing.expectEqualSlices(u8, " 1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 6 }));
- std.testing.expectEqualSlices(u8, "1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 1 }));
-
- std.testing.expectEqualSlices(u8, "+42", bufPrintIntToSlice(buf, @as(i32, 42), 10, false, FormatOptions{ .width = 3 }));
- std.testing.expectEqualSlices(u8, "-42", bufPrintIntToSlice(buf, @as(i32, -42), 10, false, FormatOptions{ .width = 3 }));
-}
-
-fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) []u8 {
- return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
-}
-
-test "parse u64 digit too big" {
- _ = parseUnsigned(u64, "123a", 10) catch |err| {
- if (err == error.InvalidCharacter) return;
- unreachable;
- };
- unreachable;
-}
-
-test "parse unsigned comptime" {
- comptime {
- std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2);
- }
-}
-
-test "optional" {
- {
- const value: ?i32 = 1234;
- try testFmt("optional: 1234\n", "optional: {}\n", .{value});
- }
- {
- const value: ?i32 = null;
- try testFmt("optional: null\n", "optional: {}\n", .{value});
- }
-}
-
-test "error" {
- {
- const value: anyerror!i32 = 1234;
- try testFmt("error union: 1234\n", "error union: {}\n", .{value});
- }
- {
- const value: anyerror!i32 = error.InvalidChar;
- try testFmt("error union: error.InvalidChar\n", "error union: {}\n", .{value});
- }
-}
-
-test "int.small" {
- {
- const value: u3 = 0b101;
- try testFmt("u3: 5\n", "u3: {}\n", .{value});
- }
-}
-
-test "int.specifier" {
- {
- const value: u8 = 'a';
- try testFmt("u8: a\n", "u8: {c}\n", .{value});
- }
- {
- const value: u8 = 0b1100;
- try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", .{value});
- }
-}
-
-test "int.padded" {
- try testFmt("u8: ' 1'", "u8: '{:4}'", .{@as(u8, 1)});
- try testFmt("u8: 'xxx1'", "u8: '{:x<4}'", .{@as(u8, 1)});
-}
-
-test "buffer" {
- {
- var buf1: [32]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf1);
- try formatType(1234, "", FormatOptions{}, fbs.outStream(), default_max_depth);
- std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
-
- fbs.reset();
- try formatType('a', "c", FormatOptions{}, fbs.outStream(), default_max_depth);
- std.testing.expect(mem.eql(u8, fbs.getWritten(), "a"));
-
- fbs.reset();
- try formatType(0b1100, "b", FormatOptions{}, fbs.outStream(), default_max_depth);
- std.testing.expect(mem.eql(u8, fbs.getWritten(), "1100"));
- }
-}
-
-test "array" {
- {
- const value: [3]u8 = "abc".*;
- try testFmt("array: abc\n", "array: {}\n", .{value});
- try testFmt("array: abc\n", "array: {}\n", .{&value});
-
- var buf: [100]u8 = undefined;
- try testFmt(
- try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@ptrToInt(&value)}),
- "array: {*}\n",
- .{&value},
- );
- }
-}
-
-test "slice" {
- {
- const value: []const u8 = "abc";
- try testFmt("slice: abc\n", "slice: {}\n", .{value});
- }
- {
- const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];
- try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
- }
-
- try testFmt("buf: Test \n", "buf: {s:5}\n", .{"Test"});
- try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", .{"Test"});
-}
-
-test "pointer" {
- {
- const value = @intToPtr(*align(1) i32, 0xdeadbeef);
- try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", .{value});
- try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", .{value});
- }
- {
- const value = @intToPtr(fn () void, 0xdeadbeef);
- try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
- }
- {
- const value = @intToPtr(fn () void, 0xdeadbeef);
- try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", .{value});
- }
-}
-
-test "cstr" {
- try testFmt(
- "cstr: Test C\n",
- "cstr: {s}\n",
- .{@ptrCast([*c]const u8, "Test C")},
- );
- try testFmt(
- "cstr: Test C \n",
- "cstr: {s:10}\n",
- .{@ptrCast([*c]const u8, "Test C")},
- );
-}
-
-test "filesize" {
- try testFmt("file size: 63MiB\n", "file size: {Bi}\n", .{@as(usize, 63 * 1024 * 1024)});
- try testFmt("file size: 66.06MB\n", "file size: {B:.2}\n", .{@as(usize, 63 * 1024 * 1024)});
-}
-
-test "struct" {
- {
- const Struct = struct {
- field: u8,
- };
- const value = Struct{ .field = 42 };
- try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{value});
- try testFmt("struct: Struct{ .field = 42 }\n", "struct: {}\n", .{&value});
- }
- {
- const Struct = struct {
- a: u0,
- b: u1,
- };
- const value = Struct{ .a = 0, .b = 1 };
- try testFmt("struct: Struct{ .a = 0, .b = 1 }\n", "struct: {}\n", .{value});
- }
-}
-
-test "enum" {
- const Enum = enum {
- One,
- Two,
- };
- const value = Enum.Two;
- try testFmt("enum: Enum.Two\n", "enum: {}\n", .{value});
- try testFmt("enum: Enum.Two\n", "enum: {}\n", .{&value});
-}
-
-test "non-exhaustive enum" {
- const Enum = enum(u16) {
- One = 0x000f,
- Two = 0xbeef,
- _,
- };
- try testFmt("enum: Enum(15)\n", "enum: {}\n", .{Enum.One});
- try testFmt("enum: Enum(48879)\n", "enum: {}\n", .{Enum.Two});
- try testFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
- try testFmt("enum: Enum(f)\n", "enum: {x}\n", .{Enum.One});
- try testFmt("enum: Enum(beef)\n", "enum: {x}\n", .{Enum.Two});
- try testFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
-}
-
-test "float.scientific" {
- try testFmt("f32: 1.34000003e+00", "f32: {e}", .{@as(f32, 1.34)});
- try testFmt("f32: 1.23400001e+01", "f32: {e}", .{@as(f32, 12.34)});
- try testFmt("f64: -1.234e+11", "f64: {e}", .{@as(f64, -12.34e10)});
- try testFmt("f64: 9.99996e-40", "f64: {e}", .{@as(f64, 9.999960e-40)});
-}
-
-test "float.scientific.precision" {
- try testFmt("f64: 1.40971e-42", "f64: {e:.5}", .{@as(f64, 1.409706e-42)});
- try testFmt("f64: 1.00000e-09", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 814313563)))});
- try testFmt("f64: 7.81250e-03", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1006632960)))});
- // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
- // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
- try testFmt("f64: 1.00001e+05", "f64: {e:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1203982400)))});
-}
-
-test "float.special" {
- try testFmt("f64: nan", "f64: {}", .{math.nan_f64});
- // negative nan is not defined by IEE 754,
- // and ARM thus normalizes it to positive nan
- if (builtin.arch != builtin.Arch.arm) {
- try testFmt("f64: -nan", "f64: {}", .{-math.nan_f64});
- }
- try testFmt("f64: inf", "f64: {}", .{math.inf_f64});
- try testFmt("f64: -inf", "f64: {}", .{-math.inf_f64});
-}
-
-test "float.decimal" {
- try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)});
- try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)});
- try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)});
- try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)});
- // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
- // -11.12339... is rounded back up to -11.1234
- try testFmt("f32: -11.1234", "f32: {d:.4}", .{@as(f32, -11.1234)});
- try testFmt("f32: 91.12345", "f32: {d:.5}", .{@as(f32, 91.12345)});
- try testFmt("f64: 91.1234567890", "f64: {d:.10}", .{@as(f64, 91.12345678901235)});
- try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 0.0)});
- try testFmt("f64: 6", "f64: {d:.0}", .{@as(f64, 5.700)});
- try testFmt("f64: 10.0", "f64: {d:.1}", .{@as(f64, 9.999)});
- try testFmt("f64: 1.000", "f64: {d:.3}", .{@as(f64, 1.0)});
- try testFmt("f64: 0.00030000", "f64: {d:.8}", .{@as(f64, 0.0003)});
- try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 1.40130e-45)});
- try testFmt("f64: 0.00000", "f64: {d:.5}", .{@as(f64, 9.999960e-40)});
-}
-
-test "float.libc.sanity" {
- try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 916964781)))});
- try testFmt("f64: 0.00001", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 925353389)))});
- try testFmt("f64: 0.10000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1036831278)))});
- try testFmt("f64: 1.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1065353133)))});
- try testFmt("f64: 10.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1092616192)))});
-
- // libc differences
- //
- // This is 0.015625 exactly according to gdb. We thus round down,
- // however glibc rounds up for some reason. This occurs for all
- // floats of the form x.yyyy25 on a precision point.
- try testFmt("f64: 0.01563", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1015021568)))});
- // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
- // also rounds to 630 so I'm inclined to believe libc is not
- // optimal here.
- try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", .{@as(f64, @bitCast(f32, @as(u32, 1518338049)))});
-}
-
-test "custom" {
- const Vec2 = struct {
- const SelfType = @This();
- x: f32,
- y: f32,
-
- pub fn format(
- self: SelfType,
- comptime fmt: []const u8,
- options: FormatOptions,
- out_stream: var,
- ) !void {
- if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
- return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
- } else if (comptime std.mem.eql(u8, fmt, "d")) {
- return std.fmtstream.format(out_stream, "{d:.3}x{d:.3}", .{ self.x, self.y });
- } else {
- @compileError("Unknown format character: '" ++ fmt ++ "'");
- }
- }
- };
-
- var buf1: [32]u8 = undefined;
- var value = Vec2{
- .x = 10.2,
- .y = 2.22,
- };
- try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value});
- try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value});
-
- // same thing but not passing a pointer
- try testFmt("point: (10.200,2.220)\n", "point: {}\n", .{value});
- try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value});
-}
-
-test "struct" {
- const S = struct {
- a: u32,
- b: anyerror,
- };
-
- const inst = S{
- .a = 456,
- .b = error.Unused,
- };
-
- try testFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
-}
-
-test "union" {
- const TU = union(enum) {
- float: f32,
- int: u32,
- };
-
- const UU = union {
- float: f32,
- int: u32,
- };
-
- const EU = extern union {
- float: f32,
- int: u32,
- };
-
- const tu_inst = TU{ .int = 123 };
- const uu_inst = UU{ .int = 456 };
- const eu_inst = EU{ .float = 321.123 };
-
- try testFmt("TU{ .int = 123 }", "{}", .{tu_inst});
-
- var buf: [100]u8 = undefined;
- const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
- std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
-
- const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
- std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
-}
-
-test "enum" {
- const E = enum {
- One,
- Two,
- Three,
- };
-
- const inst = E.Two;
-
- try testFmt("E.Two", "{}", .{inst});
-}
-
-test "struct.self-referential" {
- const S = struct {
- const SelfType = @This();
- a: ?*SelfType,
- };
-
- var inst = S{
- .a = null,
- };
- inst.a = &inst;
-
- try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
-}
-
-test "struct.zero-size" {
- const A = struct {
- fn foo() void {}
- };
- const B = struct {
- a: A,
- c: i32,
- };
-
- const a = A{};
- const b = B{ .a = a, .c = 0 };
-
- try testFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
-}
-
-test "bytes.hex" {
- const some_bytes = "\xCA\xFE\xBA\xBE";
- try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{some_bytes});
- try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{some_bytes});
- //Test Slices
- try testFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{some_bytes[0..2]});
- try testFmt("lowercase: babe\n", "lowercase: {x}\n", .{some_bytes[2..]});
- const bytes_with_zeros = "\x00\x0E\xBA\xBE";
- try testFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{bytes_with_zeros});
-}
-
-fn testFmt(expected: []const u8, comptime template: []const u8, args: var) !void {
- var buf: [100]u8 = undefined;
- const result = try bufPrint(buf[0..], template, args);
- if (mem.eql(u8, result, expected)) return;
-
- std.debug.warn("\n====== expected this output: =========\n", .{});
- std.debug.warn("{}", .{expected});
- std.debug.warn("\n======== instead found this: =========\n", .{});
- std.debug.warn("{}", .{result});
- std.debug.warn("\n======================================\n", .{});
- return error.TestFailed;
-}
-
-pub fn trim(buf: []const u8) []const u8 {
- var start: usize = 0;
- while (start < buf.len and isWhiteSpace(buf[start])) : (start += 1) {}
-
- var end: usize = buf.len;
- while (true) {
- if (end > start) {
- const new_end = end - 1;
- if (isWhiteSpace(buf[new_end])) {
- end = new_end;
- continue;
- }
- }
- break;
- }
- return buf[start..end];
-}
-
-test "trim" {
- std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
- std.testing.expect(mem.eql(u8, "", trim(" ")));
- std.testing.expect(mem.eql(u8, "", trim("")));
- std.testing.expect(mem.eql(u8, "abc", trim(" abc")));
- std.testing.expect(mem.eql(u8, "abc", trim("abc ")));
-}
-
-pub fn isWhiteSpace(byte: u8) bool {
- return switch (byte) {
- ' ', '\t', '\n', '\r' => true,
- else => false,
- };
-}
-
-pub fn hexToBytes(out: []u8, input: []const u8) !void {
- if (out.len * 2 < input.len)
- return error.InvalidLength;
-
- var in_i: usize = 0;
- while (in_i != input.len) : (in_i += 2) {
- const hi = try charToDigit(input[in_i], 16);
- const lo = try charToDigit(input[in_i + 1], 16);
- out[in_i / 2] = (hi << 4) | lo;
- }
-}
-
-test "hexToBytes" {
- const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
- var pb: [32]u8 = undefined;
- try hexToBytes(pb[0..], test_hex_str);
- try testFmt(test_hex_str, "{X}", .{pb});
-}
-
-test "formatIntValue with comptime_int" {
- const value: comptime_int = 123456789123456789;
-
- var buf: [20]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- try formatIntValue(value, "", FormatOptions{}, fbs.outStream());
- std.testing.expect(mem.eql(u8, fbs.getWritten(), "123456789123456789"));
-}
-
-test "formatType max_depth" {
- const Vec2 = struct {
- const SelfType = @This();
- x: f32,
- y: f32,
-
- pub fn format(
- self: SelfType,
- comptime fmt: []const u8,
- options: FormatOptions,
- out_stream: var,
- ) !void {
- if (fmt.len == 0) {
- return std.fmtstream.format(out_stream, "({d:.3},{d:.3})", .{ self.x, self.y });
- } else {
- @compileError("Unknown format string: '" ++ fmt ++ "'");
- }
- }
- };
- const E = enum {
- One,
- Two,
- Three,
- };
- const TU = union(enum) {
- const SelfType = @This();
- float: f32,
- int: u32,
- ptr: ?*SelfType,
- };
- const S = struct {
- const SelfType = @This();
- a: ?*SelfType,
- tu: TU,
- e: E,
- vec: Vec2,
- };
-
- var inst = S{
- .a = null,
- .tu = TU{ .ptr = null },
- .e = E.Two,
- .vec = Vec2{ .x = 10.2, .y = 2.22 },
- };
- inst.a = &inst;
- inst.tu.ptr = &inst.tu;
-
- var buf: [1000]u8 = undefined;
- var fbs = std.io.fixedBufferStream(&buf);
- try formatType(inst, "", FormatOptions{}, fbs.outStream(), 0);
- std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));
-
- fbs.reset();
- try formatType(inst, "", FormatOptions{}, fbs.outStream(), 1);
- std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
-
- fbs.reset();
- try formatType(inst, "", FormatOptions{}, fbs.outStream(), 2);
- std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
-
- fbs.reset();
- try formatType(inst, "", FormatOptions{}, fbs.outStream(), 3);
- std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
-}
-
-test "positional" {
- try testFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
- try testFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) });
- try testFmt("0 0", "{0} {0}", .{@as(usize, 0)});
- try testFmt("0 1", "{} {1}", .{ @as(usize, 0), @as(usize, 1) });
- try testFmt("1 0 0 1", "{1} {} {0} {}", .{ @as(usize, 0), @as(usize, 1) });
-}
-
-test "positional with specifier" {
- try testFmt("10.0", "{0d:.1}", .{@as(f64, 9.999)});
-}
-
-test "positional/alignment/width/precision" {
- try testFmt("10.0", "{0d: >3.1}", .{@as(f64, 9.999)});
-}
-
-test "vector" {
- // https://github.com/ziglang/zig/issues/3317
- if (builtin.arch == .mipsel) return error.SkipZigTest;
-
- const vbool: @Vector(4, bool) = [_]bool{ true, false, true, false };
- const vi64: @Vector(4, i64) = [_]i64{ -2, -1, 0, 1 };
- const vu64: @Vector(4, u64) = [_]u64{ 1000, 2000, 3000, 4000 };
-
- try testFmt("{ true, false, true, false }", "{}", .{vbool});
- try testFmt("{ -2, -1, 0, 1 }", "{}", .{vi64});
- try testFmt("{ - 2, - 1, + 0, + 1 }", "{d:5}", .{vi64});
- try testFmt("{ 1000, 2000, 3000, 4000 }", "{}", .{vu64});
- try testFmt("{ 3e8, 7d0, bb8, fa0 }", "{x}", .{vu64});
- try testFmt("{ 1kB, 2kB, 3kB, 4kB }", "{B}", .{vu64});
- try testFmt("{ 1000B, 1.953125KiB, 2.9296875KiB, 3.90625KiB }", "{Bi}", .{vu64});
-}
-
-test "enum-literal" {
- try testFmt(".hello_world", "{}", .{.hello_world});
-}
diff --git a/lib/std/http/headers.zig b/lib/std/http/headers.zig
index cb232a3e3..1e1e71e3e 100644
--- a/lib/std/http/headers.zig
+++ b/lib/std/http/headers.zig
@@ -349,7 +349,7 @@ pub const Headers = struct {
pub fn format(
self: Self,
comptime fmt: []const u8,
- options: std.fmtstream.FormatOptions,
+ options: std.fmt.FormatOptions,
out_stream: var,
) !void {
for (self.toSlice()) |entry| {
@@ -591,5 +591,5 @@ test "Headers.format" {
\\foo: bar
\\cookie: somevalue
\\
- , try std.fmtstream.bufPrint(buf[0..], "{}", .{h}));
+ , try std.fmt.bufPrint(buf[0..], "{}", .{h}));
}
diff --git a/lib/std/io/out_stream.zig b/lib/std/io/out_stream.zig
index 876a3b470..bf3ae791a 100644
--- a/lib/std/io/out_stream.zig
+++ b/lib/std/io/out_stream.zig
@@ -25,7 +25,7 @@ pub fn OutStream(
}
pub fn print(self: Self, comptime format: []const u8, args: var) Error!void {
- return std.fmtstream.format(self, format, args);
+ return std.fmt.format(self, format, args);
}
pub fn writeByte(self: Self, byte: u8) Error!void {
diff --git a/lib/std/json.zig b/lib/std/json.zig
index f3a081107..f5a72d86d 100644
--- a/lib/std/json.zig
+++ b/lib/std/json.zig
@@ -2257,10 +2257,10 @@ pub fn stringify(
const T = @TypeOf(value);
switch (@typeInfo(T)) {
.Float, .ComptimeFloat => {
- return std.fmtstream.formatFloatScientific(value, std.fmtstream.FormatOptions{}, out_stream);
+ return std.fmt.formatFloatScientific(value, std.fmt.FormatOptions{}, out_stream);
},
.Int, .ComptimeInt => {
- return std.fmtstream.formatIntValue(value, "", std.fmtstream.FormatOptions{}, out_stream);
+ return std.fmt.formatIntValue(value, "", std.fmt.FormatOptions{}, out_stream);
},
.Bool => {
return out_stream.writeAll(if (value) "true" else "false");
@@ -2350,16 +2350,16 @@ pub fn stringify(
// then it may be represented as a six-character sequence: a reverse solidus, followed
// by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point.
try out_stream.writeAll("\\u");
- try std.fmtstream.formatIntValue(codepoint, "x", std.fmtstream.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
+ try std.fmt.formatIntValue(codepoint, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
} else {
// To escape an extended character that is not in the Basic Multilingual Plane,
// the character is represented as a 12-character sequence, encoding the UTF-16 surrogate pair.
const high = @intCast(u16, (codepoint - 0x10000) >> 10) + 0xD800;
const low = @intCast(u16, codepoint & 0x3FF) + 0xDC00;
try out_stream.writeAll("\\u");
- try std.fmtstream.formatIntValue(high, "x", std.fmtstream.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
+ try std.fmt.formatIntValue(high, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
try out_stream.writeAll("\\u");
- try std.fmtstream.formatIntValue(low, "x", std.fmtstream.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
+ try std.fmt.formatIntValue(low, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream);
}
i += ulen - 1;
},
diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig
index cef2bae98..95d0764f6 100644
--- a/lib/std/math/big/int.zig
+++ b/lib/std/math/big/int.zig
@@ -518,7 +518,7 @@ pub const Int = struct {
pub fn format(
self: Int,
comptime fmt: []const u8,
- options: std.fmtstream.FormatOptions,
+ options: std.fmt.FormatOptions,
out_stream: var,
) FmtError!void {
self.assertWritable();
diff --git a/lib/std/net.zig b/lib/std/net.zig
index a1225654f..c2328b9bd 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -268,14 +268,14 @@ pub const Address = extern union {
pub fn format(
self: Address,
comptime fmt: []const u8,
- options: std.fmtstream.FormatOptions,
+ options: std.fmt.FormatOptions,
out_stream: var,
) !void {
switch (self.any.family) {
os.AF_INET => {
const port = mem.bigToNative(u16, self.in.port);
const bytes = @ptrCast(*const [4]u8, &self.in.addr);
- try std.fmtstream.format(out_stream, "{}.{}.{}.{}:{}", .{
+ try std.fmt.format(out_stream, "{}.{}.{}.{}:{}", .{
bytes[0],
bytes[1],
bytes[2],
@@ -286,7 +286,7 @@ pub const Address = extern union {
os.AF_INET6 => {
const port = mem.bigToNative(u16, self.in6.port);
if (mem.eql(u8, self.in6.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {
- try std.fmtstream.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{
+ try std.fmt.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{
self.in6.addr[12],
self.in6.addr[13],
self.in6.addr[14],
@@ -317,19 +317,19 @@ pub const Address = extern union {
}
continue;
}
- try std.fmtstream.format(out_stream, "{x}", .{native_endian_parts[i]});
+ try std.fmt.format(out_stream, "{x}", .{native_endian_parts[i]});
if (i != native_endian_parts.len - 1) {
try out_stream.writeAll(":");
}
}
- try std.fmtstream.format(out_stream, "]:{}", .{port});
+ try std.fmt.format(out_stream, "]:{}", .{port});
},
os.AF_UNIX => {
if (!has_unix_sockets) {
unreachable;
}
- try std.fmtstream.format(out_stream, "{}", .{&self.un.path});
+ try std.fmt.format(out_stream, "{}", .{&self.un.path});
},
else => unreachable,
}
@@ -438,7 +438,7 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
const name_c = try std.cstr.addNullByte(allocator, name);
defer allocator.free(name_c);
- const port_c = try std.fmtstream.allocPrint(allocator, "{}\x00", .{port});
+ const port_c = try std.fmt.allocPrint(allocator, "{}\x00", .{port});
defer allocator.free(port_c);
const hints = os.addrinfo{
diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig
index 0dc3b3020..087f965c4 100644
--- a/lib/std/net/test.zig
+++ b/lib/std/net/test.zig
@@ -29,7 +29,7 @@ test "parse and render IPv6 addresses" {
};
for (ips) |ip, i| {
var addr = net.Address.parseIp6(ip, 0) catch unreachable;
- var newIp = std.fmtstream.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
+ var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
std.testing.expect(std.mem.eql(u8, printed[i], newIp[1 .. newIp.len - 3]));
}
@@ -51,7 +51,7 @@ test "parse and render IPv4 addresses" {
"127.0.0.1",
}) |ip| {
var addr = net.Address.parseIp4(ip, 0) catch unreachable;
- var newIp = std.fmtstream.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
+ var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable;
std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2]));
}
diff --git a/lib/std/os.zig b/lib/std/os.zig
index baea4cecc..76a5dc2be 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -3049,7 +3049,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP
defer close(fd);
var procfs_buf: ["/proc/self/fd/-2147483648".len:0]u8 = undefined;
- const proc_path = std.fmtstream.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", .{fd}) catch unreachable;
+ const proc_path = std.fmt.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", .{fd}) catch unreachable;
return readlinkC(@ptrCast([*:0]const u8, proc_path.ptr), out_buffer);
}
diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig
index 5d9a678ce..5c16483ec 100644
--- a/lib/std/os/uefi.zig
+++ b/lib/std/os/uefi.zig
@@ -27,11 +27,11 @@ pub const Guid = extern struct {
pub fn format(
self: @This(),
comptime f: []const u8,
- options: std.fmtstream.FormatOptions,
+ options: std.fmt.FormatOptions,
out_stream: var,
) Errors!void {
if (f.len == 0) {
- return std.fmtstream.format(out_stream, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
+ return std.fmt.format(out_stream, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
self.time_low,
self.time_mid,
self.time_high_and_version,
diff --git a/lib/std/progress.zig b/lib/std/progress.zig
index ebb983cdc..0264d99c9 100644
--- a/lib/std/progress.zig
+++ b/lib/std/progress.zig
@@ -130,11 +130,11 @@ pub const Progress = struct {
var end: usize = 0;
if (self.columns_written > 0) {
// restore cursor position
- end += (std.fmtstream.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len;
+ end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{}D", .{self.columns_written}) catch unreachable).len;
self.columns_written = 0;
// clear rest of line
- end += (std.fmtstream.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len;
+ end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len;
}
if (!self.done) {
@@ -185,7 +185,7 @@ pub const Progress = struct {
}
fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: var) void {
- if (std.fmtstream.bufPrint(self.output_buffer[end.*..], format, args)) |written| {
+ if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| {
const amt = written.len;
end.* += amt;
self.columns_written += amt;
diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig
index c5a96df66..974247e2a 100644
--- a/lib/std/special/build_runner.zig
+++ b/lib/std/special/build_runner.zig
@@ -2,7 +2,7 @@ const root = @import("@build");
const std = @import("std");
const builtin = @import("builtin");
const io = std.io;
-const fmtstream = std.fmtstream;
+const fmt = std.fmt;
const Builder = std.build.Builder;
const mem = std.mem;
const process = std.process;
@@ -153,7 +153,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
const allocator = builder.allocator;
for (builder.top_level_steps.toSliceConst()) |top_level_step| {
const name = if (&top_level_step.step == builder.default_step)
- try fmtstream.allocPrint(allocator, "{} (default)", .{top_level_step.step.name})
+ try fmt.allocPrint(allocator, "{} (default)", .{top_level_step.step.name})
else
top_level_step.step.name;
try out_stream.print(" {s:22} {}\n", .{ name, top_level_step.description });
@@ -175,7 +175,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
try out_stream.print(" (none)\n", .{});
} else {
for (builder.available_options_list.toSliceConst()) |option| {
- const name = try fmtstream.allocPrint(allocator, " -D{}=[{}]", .{
+ const name = try fmt.allocPrint(allocator, " -D{}=[{}]", .{
option.name,
Builder.typeIdName(option.type_id),
});
diff --git a/lib/std/std.zig b/lib/std/std.zig
index b7fe709c7..9277370ca 100644
--- a/lib/std/std.zig
+++ b/lib/std/std.zig
@@ -38,7 +38,6 @@ pub const elf = @import("elf.zig");
pub const event = @import("event.zig");
pub const fifo = @import("fifo.zig");
pub const fmt = @import("fmt.zig");
-pub const fmtstream = @import("fmtstream.zig");
pub const fs = @import("fs.zig");
pub const hash = @import("hash.zig");
pub const hash_map = @import("hash_map.zig");
diff --git a/lib/std/target.zig b/lib/std/target.zig
index c117f60cc..8beb7c301 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -972,7 +972,7 @@ pub const Target = struct {
}
pub fn linuxTripleSimple(allocator: *mem.Allocator, cpu_arch: Cpu.Arch, os_tag: Os.Tag, abi: Abi) ![:0]u8 {
- return std.fmtstream.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
+ return std.fmt.allocPrint0(allocator, "{}-{}-{}", .{ @tagName(cpu_arch), @tagName(os_tag), @tagName(abi) });
}
pub fn linuxTriple(self: Target, allocator: *mem.Allocator) ![:0]u8 {
@@ -1158,7 +1158,7 @@ pub const Target = struct {
var result: DynamicLinker = .{};
const S = struct {
fn print(r: *DynamicLinker, comptime fmt: []const u8, args: var) DynamicLinker {
- r.max_byte = @intCast(u8, (std.fmtstream.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1);
+ r.max_byte = @intCast(u8, (std.fmt.bufPrint(&r.buffer, fmt, args) catch unreachable).len - 1);
return r.*;
}
fn copy(r: *DynamicLinker, s: []const u8) DynamicLinker {
diff --git a/lib/std/zig/cross_target.zig b/lib/std/zig/cross_target.zig
index a60833f93..cec3ea05e 100644
--- a/lib/std/zig/cross_target.zig
+++ b/lib/std/zig/cross_target.zig
@@ -573,7 +573,7 @@ pub const CrossTarget = struct {
.Dynamic => "",
};
- return std.fmtstream.allocPrint0(allocator, "{}-{}{}", .{ arch, os, static_suffix });
+ return std.fmt.allocPrint0(allocator, "{}-{}{}", .{ arch, os, static_suffix });
}
pub const Executor = union(enum) {
diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig
index 875ecd424..558b50b5b 100644
--- a/lib/std/zig/system.zig
+++ b/lib/std/zig/system.zig
@@ -130,7 +130,7 @@ pub const NativePaths = struct {
}
pub fn addIncludeDirFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void {
- const item = try std.fmtstream.allocPrint0(self.include_dirs.allocator, fmt, args);
+ const item = try std.fmt.allocPrint0(self.include_dirs.allocator, fmt, args);
errdefer self.include_dirs.allocator.free(item);
try self.include_dirs.append(item);
}
@@ -140,7 +140,7 @@ pub const NativePaths = struct {
}
pub fn addLibDirFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void {
- const item = try std.fmtstream.allocPrint0(self.lib_dirs.allocator, fmt, args);
+ const item = try std.fmt.allocPrint0(self.lib_dirs.allocator, fmt, args);
errdefer self.lib_dirs.allocator.free(item);
try self.lib_dirs.append(item);
}
@@ -150,7 +150,7 @@ pub const NativePaths = struct {
}
pub fn addWarningFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void {
- const item = try std.fmtstream.allocPrint0(self.warnings.allocator, fmt, args);
+ const item = try std.fmt.allocPrint0(self.warnings.allocator, fmt, args);
errdefer self.warnings.allocator.free(item);
try self.warnings.append(item);
}
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
index fdaee7d12..7a45bb3c3 100644
--- a/src-self-hosted/compilation.zig
+++ b/src-self-hosted/compilation.zig
@@ -1051,7 +1051,7 @@ pub const Compilation = struct {
}
fn addCompileError(self: *Compilation, tree_scope: *Scope.AstTree, span: Span, comptime fmt: []const u8, args: var) !void {
- const text = try std.fmtstream.allocPrint(self.gpa(), fmt, args);
+ const text = try std.fmt.allocPrint(self.gpa(), fmt, args);
errdefer self.gpa().free(text);
const msg = try Msg.createFromScope(self, tree_scope, span, text);
@@ -1061,7 +1061,7 @@ pub const Compilation = struct {
}
fn addCompileErrorCli(self: *Compilation, realpath: []const u8, comptime fmt: []const u8, args: var) !void {
- const text = try std.fmtstream.allocPrint(self.gpa(), fmt, args);
+ const text = try std.fmt.allocPrint(self.gpa(), fmt, args);
errdefer self.gpa().free(text);
const msg = try Msg.createFromCli(self, realpath, text);
@@ -1154,7 +1154,7 @@ pub const Compilation = struct {
const tmp_dir = try self.getTmpDir();
const file_prefix = self.getRandomFileName();
- const file_name = try std.fmtstream.allocPrint(self.gpa(), "{}{}", .{ file_prefix[0..], suffix });
+ const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", .{ file_prefix[0..], suffix });
defer self.gpa().free(file_name);
const full_path = try fs.path.join(self.gpa(), &[_][]const u8{ tmp_dir, file_name[0..] });
diff --git a/src-self-hosted/dep_tokenizer.zig b/src-self-hosted/dep_tokenizer.zig
index 233b67817..c73719ebe 100644
--- a/src-self-hosted/dep_tokenizer.zig
+++ b/src-self-hosted/dep_tokenizer.zig
@@ -893,7 +893,7 @@ fn printSection(out: var, label: []const u8, bytes: []const u8) !void {
fn printLabel(out: var, label: []const u8, bytes: []const u8) !void {
var buf: [80]u8 = undefined;
- var text = try std.fmtstream.bufPrint(buf[0..], "{} {} bytes ", .{ label, bytes.len });
+ var text = try std.fmt.bufPrint(buf[0..], "{} {} bytes ", .{ label, bytes.len });
try out.write(text);
var i: usize = text.len;
const end = 79;
@@ -979,13 +979,13 @@ fn hexDump16(out: var, offset: usize, bytes: []const u8) !void {
fn printDecValue(out: var, value: u64, width: u8) !void {
var buffer: [20]u8 = undefined;
- const len = std.fmtstream.formatIntBuf(buffer[0..], value, 10, false, width);
+ const len = std.fmt.formatIntBuf(buffer[0..], value, 10, false, width);
try out.write(buffer[0..len]);
}
fn printHexValue(out: var, value: u64, width: u8) !void {
var buffer: [16]u8 = undefined;
- const len = std.fmtstream.formatIntBuf(buffer[0..], value, 16, false, width);
+ const len = std.fmt.formatIntBuf(buffer[0..], value, 16, false, width);
try out.write(buffer[0..len]);
}
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
index 3b65fb172..0f9736456 100644
--- a/src-self-hosted/libc_installation.zig
+++ b/src-self-hosted/libc_installation.zig
@@ -543,7 +543,7 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
const allocator = args.allocator;
const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe;
- const arg1 = try std.fmtstream.allocPrint(allocator, "-print-file-name={}", .{args.search_basename});
+ const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", .{args.search_basename});
defer allocator.free(arg1);
const argv = [_][]const u8{ cc_exe, arg1 };
diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig
index b63e6c24f..1efa15574 100644
--- a/src-self-hosted/link.zig
+++ b/src-self-hosted/link.zig
@@ -296,13 +296,13 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
const is_library = ctx.comp.kind == .Lib;
- const out_arg = try std.fmtstream.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", .{ctx.out_file_path.toSliceConst()});
+ const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", .{ctx.out_file_path.toSliceConst()});
try ctx.args.append(@ptrCast([*:0]const u8, out_arg.ptr));
if (ctx.comp.haveLibC()) {
- try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmtstream.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr));
- try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmtstream.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr));
- try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmtstream.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr));
+ try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr));
+ try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr));
+ try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr));
}
if (ctx.link_in_crt) {
@@ -310,20 +310,20 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
const d_str = if (ctx.comp.build_mode == .Debug) "d" else "";
if (ctx.comp.is_static) {
- const cmt_lib_name = try std.fmtstream.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", .{d_str});
+ const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", .{d_str});
try ctx.args.append(@ptrCast([*:0]const u8, cmt_lib_name.ptr));
} else {
- const msvcrt_lib_name = try std.fmtstream.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", .{d_str});
+ const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", .{d_str});
try ctx.args.append(@ptrCast([*:0]const u8, msvcrt_lib_name.ptr));
}
- const vcruntime_lib_name = try std.fmtstream.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", .{
+ const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", .{
lib_str,
d_str,
});
try ctx.args.append(@ptrCast([*:0]const u8, vcruntime_lib_name.ptr));
- const crt_lib_name = try std.fmtstream.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", .{ lib_str, d_str });
+ const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", .{ lib_str, d_str });
try ctx.args.append(@ptrCast([*:0]const u8, crt_lib_name.ptr));
// Visual C++ 2015 Conformance Changes
@@ -383,7 +383,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
.IPhoneOS => try ctx.args.append("-iphoneos_version_min"),
.IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"),
}
- const ver_str = try std.fmtstream.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", .{
+ const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", .{
platform.major,
platform.minor,
platform.micro,
@@ -445,7 +445,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
try ctx.args.append("-lSystem");
} else {
if (mem.indexOfScalar(u8, lib.name, '/') == null) {
- const arg = try std.fmtstream.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name});
+ const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name});
try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
} else {
const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig
index 408c39fe7..ad506425d 100644
--- a/src-self-hosted/print_targets.zig
+++ b/src-self-hosted/print_targets.zig
@@ -138,7 +138,7 @@ pub fn cmdTargets(
for (available_glibcs) |glibc| {
try jws.arrayElem();
- const tmp = try std.fmtstream.allocPrint(allocator, "{}", .{glibc});
+ const tmp = try std.fmt.allocPrint(allocator, "{}", .{glibc});
defer allocator.free(tmp);
try jws.emitString(tmp);
}
diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig
index 98e9fb06d..e87164c9f 100644
--- a/src-self-hosted/test.zig
+++ b/src-self-hosted/test.zig
@@ -81,7 +81,7 @@ pub const TestContext = struct {
msg: []const u8,
) !void {
var file_index_buf: [20]u8 = undefined;
- const file_index = try std.fmtstream.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
+ const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 });
if (std.fs.path.dirname(file1_path)) |dirname| {
@@ -114,10 +114,10 @@ pub const TestContext = struct {
expected_output: []const u8,
) !void {
var file_index_buf: [20]u8 = undefined;
- const file_index = try std.fmtstream.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
+ const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", .{self.file_index.incr()});
const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 });
- const output_file = try std.fmtstream.allocPrint(allocator, "{}-out{}", .{ file1_path, (Target{ .Native = {} }).exeFileExt() });
+ const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", .{ file1_path, (Target{ .Native = {} }).exeFileExt() });
if (std.fs.path.dirname(file1_path)) |dirname| {
try std.fs.cwd().makePath(dirname);
}
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index 7b05a76cb..89d6f94d7 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -89,7 +89,7 @@ const Scope = struct {
var proposed_name = name;
while (scope.contains(proposed_name)) {
scope.mangle_count += 1;
- proposed_name = try std.fmtstream.allocPrint(c.a(), "{}_{}", .{ name, scope.mangle_count });
+ proposed_name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, scope.mangle_count });
}
try scope.variables.push(.{ .name = name, .alias = proposed_name });
return proposed_name;
@@ -246,7 +246,7 @@ pub const Context = struct {
const line = ZigClangSourceManager_getSpellingLineNumber(c.source_manager, spelling_loc);
const column = ZigClangSourceManager_getSpellingColumnNumber(c.source_manager, spelling_loc);
- return std.fmtstream.allocPrint(c.a(), "{}:{}:{}", .{ filename, line, column });
+ return std.fmt.allocPrint(c.a(), "{}:{}:{}", .{ filename, line, column });
}
};
@@ -516,7 +516,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
const arg_name = blk: {
const param_prefix = if (is_const) "" else "arg_";
- const bare_arg_name = try std.fmtstream.allocPrint(c.a(), "{}{}", .{ param_prefix, mangled_param_name });
+ const bare_arg_name = try std.fmt.allocPrint(c.a(), "{}{}", .{ param_prefix, mangled_param_name });
break :blk try block_scope.makeMangledName(c, bare_arg_name);
};
@@ -560,7 +560,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const checked_name = if (isZigPrimitiveType(var_name)) try std.fmtstream.allocPrint(c.a(), "{}_{}", .{var_name, c.getMangle()}) else var_name;
+ const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ var_name, c.getMangle() }) else var_name;
const var_decl_loc = ZigClangVarDecl_getLocation(var_decl);
const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl);
@@ -620,7 +620,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
_ = try appendToken(rp.c, .LParen, "(");
const expr = try transCreateNodeStringLiteral(
rp.c,
- try std.fmtstream.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),
+ try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),
);
_ = try appendToken(rp.c, .RParen, ")");
@@ -677,7 +677,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmtstream.allocPrint(c.a(), "{}_{}", .{typedef_name, c.getMangle()}) else typedef_name;
+ const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ typedef_name, c.getMangle() }) else typedef_name;
if (mem.eql(u8, checked_name, "uint8_t"))
return transTypeDefAsBuiltin(c, typedef_decl, "u8")
@@ -738,7 +738,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
// Record declarations such as `struct {...} x` have no name but they're not
// anonymous hence here isAnonymousStructOrUnion is not needed
if (bare_name.len == 0) {
- bare_name = try std.fmtstream.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
+ bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_unnamed = true;
}
@@ -755,7 +755,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
return null;
}
- const name = try std.fmtstream.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
+ const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name });
_ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name);
const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
@@ -812,7 +812,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
var is_anon = false;
var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
- raw_name = try std.fmtstream.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
+ raw_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_anon = true;
}
const field_name = try appendIdentifier(c, raw_name);
@@ -882,11 +882,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, enum_decl)));
var is_unnamed = false;
if (bare_name.len == 0) {
- bare_name = try std.fmtstream.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
+ bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
is_unnamed = true;
}
- const name = try std.fmtstream.allocPrint(c.a(), "enum_{}", .{bare_name});
+ const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name});
_ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name);
const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name);
node.eq_token = try appendToken(c, .Equal, "=");
@@ -1754,9 +1754,9 @@ fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
// Handle the remaining escapes Zig doesn't support by turning them
// into their respective hex representation
if (std.ascii.isCntrl(c))
- return std.fmtstream.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable
+ return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable
else
- return std.fmtstream.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable;
+ return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable;
},
};
}
@@ -2436,7 +2436,7 @@ fn transCase(
) TransError!*ast.Node {
const block_scope = scope.findBlockScope(rp.c) catch unreachable;
const switch_scope = scope.getSwitch();
- const label = try std.fmtstream.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)});
+ const label = try std.fmt.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)});
_ = try appendToken(rp.c, .Semicolon, ";");
const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: {
@@ -4607,7 +4607,7 @@ fn finishTransFnProto(
_ = try appendToken(rp.c, .LParen, "(");
const expr = try transCreateNodeStringLiteral(
rp.c,
- try std.fmtstream.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),
+ try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}),
);
_ = try appendToken(rp.c, .RParen, ")");
@@ -4866,7 +4866,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
const name = try c.str(raw_name);
// TODO https://github.com/ziglang/zig/issues/3756
// TODO https://github.com/ziglang/zig/issues/1802
- const mangled_name = if (isZigPrimitiveType(name)) try std.fmtstream.allocPrint(c.a(), "{}_{}", .{name, c.getMangle()}) else name;
+ const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }) else name;
if (scope.containsNow(mangled_name)) {
continue;
}
@@ -5151,11 +5151,11 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
switch (lit_bytes[1]) {
'0'...'7' => {
// Octal
- lit_bytes = try std.fmtstream.allocPrint(c.a(), "0o{}", .{lit_bytes});
+ lit_bytes = try std.fmt.allocPrint(c.a(), "0o{}", .{lit_bytes});
},
'X' => {
// Hexadecimal with capital X, valid in C but not in Zig
- lit_bytes = try std.fmtstream.allocPrint(c.a(), "0x{}", .{lit_bytes[2..]});
+ lit_bytes = try std.fmt.allocPrint(c.a(), "0x{}", .{lit_bytes[2..]});
},
else => {},
}
@@ -5186,7 +5186,7 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl
return &cast_node.base;
} else if (tok.id == .FloatLiteral) {
if (lit_bytes[0] == '.')
- lit_bytes = try std.fmtstream.allocPrint(c.a(), "0{}", .{lit_bytes});
+ lit_bytes = try std.fmt.allocPrint(c.a(), "0{}", .{lit_bytes});
if (tok.id.FloatLiteral == .None) {
return transCreateNodeFloat(c, lit_bytes);
}
@@ -5319,7 +5319,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const
num += c - 'A' + 10;
},
else => {
- i += std.fmtstream.formatIntBuf(bytes[i..], num, 16, false, std.fmtstream.FormatOptions{ .fill = '0', .width = 2 });
+ i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
num = 0;
if (c == '\\')
state = .Escape
@@ -5345,7 +5345,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const
};
num += c - '0';
} else {
- i += std.fmtstream.formatIntBuf(bytes[i..], num, 16, false, std.fmtstream.FormatOptions{ .fill = '0', .width = 2 });
+ i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
num = 0;
count = 0;
if (c == '\\')
@@ -5359,7 +5359,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const
}
}
if (state == .Hex or state == .Octal)
- i += std.fmtstream.formatIntBuf(bytes[i..], num, 16, false, std.fmtstream.FormatOptions{ .fill = '0', .width = 2 });
+ i += std.fmt.formatIntBuf(bytes[i..], num, 16, false, std.fmt.FormatOptions{ .fill = '0', .width = 2 });
return bytes[0..i];
}
diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig
index c2b406823..70ed754ce 100644
--- a/src-self-hosted/type.zig
+++ b/src-self-hosted/type.zig
@@ -581,7 +581,7 @@ pub const Type = struct {
errdefer comp.gpa().destroy(self);
const u_or_i = "ui"[@boolToInt(key.is_signed)];
- const name = try std.fmtstream.allocPrint(comp.gpa(), "{c}{}", .{ u_or_i, key.bit_count });
+ const name = try std.fmt.allocPrint(comp.gpa(), "{c}{}", .{ u_or_i, key.bit_count });
errdefer comp.gpa().free(name);
self.base.init(comp, .Int, name);
@@ -764,13 +764,13 @@ pub const Type = struct {
.Non => "",
};
const name = switch (self.key.alignment) {
- .Abi => try std.fmtstream.allocPrint(comp.gpa(), "{}{}{}{}", .{
+ .Abi => try std.fmt.allocPrint(comp.gpa(), "{}{}{}{}", .{
size_str,
mut_str,
vol_str,
self.key.child_type.name,
}),
- .Override => |alignment| try std.fmtstream.allocPrint(comp.gpa(), "{}align<{}> {}{}{}", .{
+ .Override => |alignment| try std.fmt.allocPrint(comp.gpa(), "{}align<{}> {}{}{}", .{
size_str,
alignment,
mut_str,
@@ -845,7 +845,7 @@ pub const Type = struct {
};
errdefer comp.gpa().destroy(self);
- const name = try std.fmtstream.allocPrint(comp.gpa(), "[{}]{}", .{ key.len, key.elem_type.name });
+ const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", .{ key.len, key.elem_type.name });
errdefer comp.gpa().free(name);
self.base.init(comp, .Array, name);
diff --git a/test/src/compare_output.zig b/test/src/compare_output.zig
index c68eb1eeb..ae994a069 100644
--- a/test/src/compare_output.zig
+++ b/test/src/compare_output.zig
@@ -4,7 +4,7 @@ const std = @import("std");
const builtin = std.builtin;
const build = std.build;
const ArrayList = std.ArrayList;
-const fmtstream = std.fmtstream;
+const fmt = std.fmt;
const mem = std.mem;
const fs = std.fs;
const warn = std.debug.warn;
@@ -97,7 +97,7 @@ pub const CompareOutputContext = struct {
switch (case.special) {
Special.Asm => {
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "assemble-and-link {}", .{
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "assemble-and-link {}", .{
case.name,
}) catch unreachable;
if (self.test_filter) |filter| {
@@ -116,7 +116,7 @@ pub const CompareOutputContext = struct {
},
Special.None => {
for (self.modes) |mode| {
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "{} {} ({})", .{
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", .{
"compare-output",
case.name,
@tagName(mode),
@@ -141,7 +141,7 @@ pub const CompareOutputContext = struct {
}
},
Special.RuntimeSafety => {
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "safety {}", .{case.name}) catch unreachable;
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "safety {}", .{case.name}) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/test/src/run_translated_c.zig b/test/src/run_translated_c.zig
index 6304137e4..14b0ce593 100644
--- a/test/src/run_translated_c.zig
+++ b/test/src/run_translated_c.zig
@@ -3,7 +3,7 @@
const std = @import("std");
const build = std.build;
const ArrayList = std.ArrayList;
-const fmtstream = std.fmtstream;
+const fmt = std.fmt;
const mem = std.mem;
const fs = std.fs;
const warn = std.debug.warn;
@@ -76,7 +76,7 @@ pub const RunTranslatedCContext = struct {
pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {
const b = self.b;
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "run-translated-c {}", .{case.name}) catch unreachable;
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "run-translated-c {}", .{case.name}) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/test/src/translate_c.zig b/test/src/translate_c.zig
index 250ec6175..9a6bd0d32 100644
--- a/test/src/translate_c.zig
+++ b/test/src/translate_c.zig
@@ -3,7 +3,7 @@
const std = @import("std");
const build = std.build;
const ArrayList = std.ArrayList;
-const fmtstream = std.fmtstream;
+const fmt = std.fmt;
const mem = std.mem;
const fs = std.fs;
const warn = std.debug.warn;
@@ -99,7 +99,7 @@ pub const TranslateCContext = struct {
const b = self.b;
const translate_c_cmd = "translate-c";
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "{} {}", .{ translate_c_cmd, case.name }) catch unreachable;
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {}", .{ translate_c_cmd, case.name }) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/test/stage1/behavior/enum_with_members.zig b/test/stage1/behavior/enum_with_members.zig
index b299301ce..08b195494 100644
--- a/test/stage1/behavior/enum_with_members.zig
+++ b/test/stage1/behavior/enum_with_members.zig
@@ -1,6 +1,6 @@
const expect = @import("std").testing.expect;
const mem = @import("std").mem;
-const fmtstream = @import("std").fmtstream;
+const fmt = @import("std").fmt;
const ET = union(enum) {
SINT: i32,
@@ -8,8 +8,8 @@ const ET = union(enum) {
pub fn print(a: *const ET, buf: []u8) anyerror!usize {
return switch (a.*) {
- ET.SINT => |x| fmtstream.formatIntBuf(buf, x, 10, false, fmtstream.FormatOptions{}),
- ET.UINT => |x| fmtstream.formatIntBuf(buf, x, 10, false, fmtstream.FormatOptions{}),
+ ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}),
+ ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, false, fmt.FormatOptions{}),
};
}
};
diff --git a/test/tests.zig b/test/tests.zig
index 61f694bed..22dad10e3 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -8,7 +8,7 @@ const Buffer = std.Buffer;
const io = std.io;
const fs = std.fs;
const mem = std.mem;
-const fmtstream = std.fmtstream;
+const fmt = std.fmt;
const ArrayList = std.ArrayList;
const Mode = builtin.Mode;
const LibExeObjStep = build.LibExeObjStep;
@@ -484,7 +484,7 @@ pub const StackTracesContext = struct {
const expect_for_mode = expect[@enumToInt(mode)];
if (expect_for_mode.len == 0) continue;
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "{} {} ({})", .{
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", .{
"stack-trace",
name,
@tagName(mode),
@@ -943,7 +943,7 @@ pub const CompileErrorContext = struct {
pub fn addCase(self: *CompileErrorContext, case: *const TestCase) void {
const b = self.b;
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "compile-error {}", .{
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {}", .{
case.name,
}) catch unreachable;
if (self.test_filter) |filter| {
@@ -1009,7 +1009,7 @@ pub const StandaloneContext = struct {
const b = self.b;
for (self.modes) |mode| {
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "build {} ({})", .{
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})", .{
root_src,
@tagName(mode),
}) catch unreachable;
@@ -1152,7 +1152,7 @@ pub const GenHContext = struct {
const b = self.b;
const mode = builtin.Mode.Debug;
- const annotated_case_name = fmtstream.allocPrint(self.b.allocator, "gen-h {} ({})", .{ case.name, @tagName(mode) }) catch unreachable;
+ const annotated_case_name = fmt.allocPrint(self.b.allocator, "gen-h {} ({})", .{ case.name, @tagName(mode) }) catch unreachable;
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
}
diff --git a/tools/process_headers.zig b/tools/process_headers.zig
index 43950750e..abdc9fabf 100644
--- a/tools/process_headers.zig
+++ b/tools/process_headers.zig
@@ -299,7 +299,7 @@ pub fn main() !void {
std.debug.warn("unrecognized C ABI: {}\n", .{abi_name});
usageAndExit(args[0]);
};
- const generic_name = try std.fmtstream.allocPrint(allocator, "generic-{}", .{abi_name});
+ const generic_name = try std.fmt.allocPrint(allocator, "generic-{}", .{abi_name});
// TODO compiler crashed when I wrote this the canonical way
var libc_targets: []const LibCTarget = undefined;
@@ -440,7 +440,7 @@ pub fn main() !void {
.specific => |a| @tagName(a),
else => @tagName(dest_target.arch),
};
- const out_subpath = try std.fmtstream.allocPrint(allocator, "{}-{}-{}", .{
+ const out_subpath = try std.fmt.allocPrint(allocator, "{}-{}-{}", .{
arch_name,
@tagName(dest_target.os),
@tagName(dest_target.abi),
diff --git a/tools/update_glibc.zig b/tools/update_glibc.zig
index 35351e4d2..84522aabe 100644
--- a/tools/update_glibc.zig
+++ b/tools/update_glibc.zig
@@ -1,6 +1,6 @@
const std = @import("std");
const fs = std.fs;
-const fmtstream = std.fmtstream;
+const fmt = std.fmt;
const assert = std.debug.assert;
// Example abilist path:
@@ -154,7 +154,7 @@ pub fn main() !void {
const fn_set = &target_funcs_gop.kv.value.list;
for (lib_names) |lib_name, lib_name_index| {
- const basename = try fmtstream.allocPrint(allocator, "lib{}.abilist", .{lib_name});
+ const basename = try fmt.allocPrint(allocator, "lib{}.abilist", .{lib_name});
const abi_list_filename = blk: {
if (abi_list.targets[0].abi == .gnuabi64 and std.mem.eql(u8, lib_name, "c")) {
break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "n64", basename });
From 8a22c50c081e4495216ef961a9c1f2db6fbac916 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Fri, 13 Mar 2020 00:55:52 +1100
Subject: [PATCH 096/111] Remove unused static_crt_dir field from libc config
---
src-self-hosted/libc_installation.zig | 25 -------------------------
src-self-hosted/stage2.zig | 12 ------------
src/stage2.cpp | 2 --
src/stage2.h | 2 --
4 files changed, 41 deletions(-)
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
index 0f9736456..c07ef03b5 100644
--- a/src-self-hosted/libc_installation.zig
+++ b/src-self-hosted/libc_installation.zig
@@ -17,7 +17,6 @@ pub const LibCInstallation = struct {
include_dir: ?[:0]const u8 = null,
sys_include_dir: ?[:0]const u8 = null,
crt_dir: ?[:0]const u8 = null,
- static_crt_dir: ?[:0]const u8 = null,
msvc_lib_dir: ?[:0]const u8 = null,
kernel32_lib_dir: ?[:0]const u8 = null,
@@ -98,13 +97,6 @@ pub const LibCInstallation = struct {
try stderr.print("crt_dir may not be empty for {}\n", .{@tagName(Target.current.os.tag)});
return error.ParseError;
}
- if (self.static_crt_dir == null and is_windows and is_gnu) {
- try stderr.print("static_crt_dir may not be empty for {}-{}\n", .{
- @tagName(Target.current.os.tag),
- @tagName(Target.current.abi),
- });
- return error.ParseError;
- }
if (self.msvc_lib_dir == null and is_windows and !is_gnu) {
try stderr.print("msvc_lib_dir may not be empty for {}-{}\n", .{
@tagName(Target.current.os.tag),
@@ -128,7 +120,6 @@ pub const LibCInstallation = struct {
const include_dir = self.include_dir orelse "";
const sys_include_dir = self.sys_include_dir orelse "";
const crt_dir = self.crt_dir orelse "";
- const static_crt_dir = self.static_crt_dir orelse "";
const msvc_lib_dir = self.msvc_lib_dir orelse "";
const kernel32_lib_dir = self.kernel32_lib_dir orelse "";
@@ -147,11 +138,6 @@ pub const LibCInstallation = struct {
\\# Not needed when targeting MacOS.
\\crt_dir={}
\\
- \\# The directory that contains `crtbegin.o`.
- \\# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.
- \\# Only needed when targeting MinGW-w64 on Windows.
- \\static_crt_dir={}
- \\
\\# The directory that contains `vcruntime.lib`.
\\# Only needed when targeting MSVC on Windows.
\\msvc_lib_dir={}
@@ -164,7 +150,6 @@ pub const LibCInstallation = struct {
include_dir,
sys_include_dir,
crt_dir,
- static_crt_dir,
msvc_lib_dir,
kernel32_lib_dir,
});
@@ -186,7 +171,6 @@ pub const LibCInstallation = struct {
var batch = Batch(FindError!void, 3, .auto_async).init();
batch.add(&async self.findNativeIncludeDirPosix(args));
batch.add(&async self.findNativeCrtDirPosix(args));
- batch.add(&async self.findNativeStaticCrtDirPosix(args));
try batch.wait();
} else {
var sdk: *ZigWindowsSDK = undefined;
@@ -428,15 +412,6 @@ pub const LibCInstallation = struct {
});
}
- fn findNativeStaticCrtDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void {
- self.static_crt_dir = try ccPrintFileName(.{
- .allocator = args.allocator,
- .search_basename = "crtbegin.o",
- .want_dirname = .only_dir,
- .verbose = args.verbose,
- });
- }
-
fn findNativeKernel32LibDir(
self: *LibCInstallation,
args: FindNativeOptions,
diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig
index 36941cc3a..b355f8f02 100644
--- a/src-self-hosted/stage2.zig
+++ b/src-self-hosted/stage2.zig
@@ -744,8 +744,6 @@ const Stage2LibCInstallation = extern struct {
sys_include_dir_len: usize,
crt_dir: [*:0]const u8,
crt_dir_len: usize,
- static_crt_dir: [*:0]const u8,
- static_crt_dir_len: usize,
msvc_lib_dir: [*:0]const u8,
msvc_lib_dir_len: usize,
kernel32_lib_dir: [*:0]const u8,
@@ -773,13 +771,6 @@ const Stage2LibCInstallation = extern struct {
self.crt_dir = "";
self.crt_dir_len = 0;
}
- if (libc.static_crt_dir) |s| {
- self.static_crt_dir = s.ptr;
- self.static_crt_dir_len = s.len;
- } else {
- self.static_crt_dir = "";
- self.static_crt_dir_len = 0;
- }
if (libc.msvc_lib_dir) |s| {
self.msvc_lib_dir = s.ptr;
self.msvc_lib_dir_len = s.len;
@@ -807,9 +798,6 @@ const Stage2LibCInstallation = extern struct {
if (self.crt_dir_len != 0) {
libc.crt_dir = self.crt_dir[0..self.crt_dir_len :0];
}
- if (self.static_crt_dir_len != 0) {
- libc.static_crt_dir = self.static_crt_dir[0..self.static_crt_dir_len :0];
- }
if (self.msvc_lib_dir_len != 0) {
libc.msvc_lib_dir = self.msvc_lib_dir[0..self.msvc_lib_dir_len :0];
}
diff --git a/src/stage2.cpp b/src/stage2.cpp
index 7495ffddb..a8d8b7cf9 100644
--- a/src/stage2.cpp
+++ b/src/stage2.cpp
@@ -272,8 +272,6 @@ enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *li
libc->sys_include_dir_len = strlen(libc->sys_include_dir);
libc->crt_dir = "";
libc->crt_dir_len = strlen(libc->crt_dir);
- libc->static_crt_dir = "";
- libc->static_crt_dir_len = strlen(libc->static_crt_dir);
libc->msvc_lib_dir = "";
libc->msvc_lib_dir_len = strlen(libc->msvc_lib_dir);
libc->kernel32_lib_dir = "";
diff --git a/src/stage2.h b/src/stage2.h
index 50f891dca..24fd664b3 100644
--- a/src/stage2.h
+++ b/src/stage2.h
@@ -209,8 +209,6 @@ struct Stage2LibCInstallation {
size_t sys_include_dir_len;
const char *crt_dir;
size_t crt_dir_len;
- const char *static_crt_dir;
- size_t static_crt_dir_len;
const char *msvc_lib_dir;
size_t msvc_lib_dir_len;
const char *kernel32_lib_dir;
From bd0b51477a6cb0dc7ea7739f61a70110d39ba601 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Thu, 12 Mar 2020 19:40:42 +0100
Subject: [PATCH 097/111] Address review comments
---
lib/std/fs/file.zig | 2 +-
lib/std/os.zig | 22 ++++++++++++++--------
2 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig
index 8bb377c99..c3809cd51 100644
--- a/lib/std/fs/file.zig
+++ b/lib/std/fs/file.zig
@@ -104,7 +104,7 @@ pub const File = struct {
/// Shrinks or expands the file.
/// The file offset after this call is undefined.
pub fn setEndPos(self: File, length: u64) SetEndPosError!void {
- try os.truncate(self.handle, length);
+ try os.ftruncate(self.handle, length);
}
pub const SeekError = os.SeekError;
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 62347c2ee..6614453a3 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -439,11 +439,13 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
}
pub const TruncateError = error{
- /// The file descriptor is not open for writing.
- NotFile,
+ FileTooBig,
+ InputOutput,
+ CannotTruncate,
+ FileBusy,
} || UnexpectedError;
-pub fn truncate(fd: fd_t, length: u64) TruncateError!void {
+pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
if (std.Target.current.os.tag == .windows) {
try windows.SetFilePointerEx_BEGIN(fd, length);
@@ -454,18 +456,22 @@ pub fn truncate(fd: fd_t, length: u64) TruncateError!void {
}
while (true) {
- const rc = if (builtin.link_libc) blk: {
+ const rc = if (builtin.link_libc)
if (std.Target.current.os.tag == .linux)
- break :blk system.ftruncate64(fd, @bitCast(off_t, length))
+ system.ftruncate64(fd, @bitCast(off_t, length))
else
- break :blk system.ftruncate(fd, @bitCast(off_t, length));
- } else
+ system.ftruncate(fd, @bitCast(off_t, length))
+ else
system.ftruncate(fd, length);
switch (errno(rc)) {
0 => return,
EINTR => continue,
- EBADF, EINVAL => return error.NotFile,
+ EFBIG => return error.FileTooBig,
+ EIO => return error.InputOutput,
+ EPERM => return error.CannotTruncate,
+ ETXTBSY => return error.FileBusy,
+ EBADF, EINVAL => unreachable,
else => |err| return unexpectedErrno(err),
}
}
From 6dde769279aaa0cc09d13dd0670b74a8dd24f547 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 12 Mar 2020 21:15:58 +0200
Subject: [PATCH 098/111] Simplify stores, use sext for signed ints
---
src/codegen.cpp | 22 ++++++++++---
src/ir.cpp | 53 +++++++++++++++++++++++---------
test/stage1/behavior/atomics.zig | 4 +--
3 files changed, 59 insertions(+), 20 deletions(-)
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 55713c1b8..a9c539224 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5259,8 +5259,13 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
// operand needs widening and truncating
ptr_val = LLVMBuildBitCast(g->builder, ptr_val,
LLVMPointerType(actual_abi_type, 0), "");
- cmp_val = LLVMBuildZExt(g->builder, cmp_val, actual_abi_type, "");
- new_val = LLVMBuildZExt(g->builder, new_val, actual_abi_type, "");
+ if (operand_type->data.integral.is_signed) {
+ cmp_val = LLVMBuildSExt(g->builder, cmp_val, actual_abi_type, "");
+ new_val = LLVMBuildSExt(g->builder, new_val, actual_abi_type, "");
+ } else {
+ cmp_val = LLVMBuildZExt(g->builder, cmp_val, actual_abi_type, "");
+ new_val = LLVMBuildZExt(g->builder, new_val, actual_abi_type, "");
+ }
}
LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
@@ -5877,7 +5882,12 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutableGen *executable
// operand needs widening and truncating
LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, ptr,
LLVMPointerType(actual_abi_type, 0), "");
- LLVMValueRef casted_operand = LLVMBuildZExt(g->builder, operand, actual_abi_type, "");
+ LLVMValueRef casted_operand;
+ if (operand_type->data.integral.is_signed) {
+ casted_operand = LLVMBuildSExt(g->builder, operand, actual_abi_type, "");
+ } else {
+ casted_operand = LLVMBuildZExt(g->builder, operand, actual_abi_type, "");
+ }
LLVMValueRef uncasted_result = ZigLLVMBuildAtomicRMW(g->builder, op, casted_ptr, casted_operand, ordering,
g->is_single_threaded);
return LLVMBuildTrunc(g->builder, uncasted_result, get_llvm_type(g, operand_type), "");
@@ -5929,7 +5939,11 @@ static LLVMValueRef ir_render_atomic_store(CodeGen *g, IrExecutableGen *executab
// operand needs widening
ptr = LLVMBuildBitCast(g->builder, ptr,
LLVMPointerType(actual_abi_type, 0), "");
- value = LLVMBuildZExt(g->builder, value, actual_abi_type, "");
+ if (instruction->value->value->type->data.integral.is_signed) {
+ value = LLVMBuildSExt(g->builder, value, actual_abi_type, "");
+ } else {
+ value = LLVMBuildZExt(g->builder, value, actual_abi_type, "");
+ }
}
LLVMValueRef store_inst = gen_store(g, value, ptr, instruction->ptr->value->type);
LLVMSetOrdering(store_inst, ordering);
diff --git a/src/ir.cpp b/src/ir.cpp
index 4f139895b..ede403c72 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -25197,10 +25197,16 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
ZigType *result_type = get_optional_type(ira->codegen, operand_type);
// special case zero bit types
- if (type_has_one_possible_value(ira->codegen, operand_type) == OnePossibleValueYes) {
- IrInstGen *result = ir_const(ira, &instruction->base.base, result_type);
- set_optional_value_to_null(result->value);
- return result;
+ switch (type_has_one_possible_value(ira->codegen, operand_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_inst_gen;
+ case OnePossibleValueYes: {
+ IrInstGen *result = ir_const(ira, &instruction->base.base, result_type);
+ set_optional_value_to_null(result->value);
+ return result;
+ }
+ case OnePossibleValueNo:
+ break;
}
if (instr_is_comptime(casted_ptr) && casted_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar &&
@@ -28432,8 +28438,13 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
}
// special case zero bit types
- if (type_has_one_possible_value(ira->codegen, operand_type) == OnePossibleValueYes) {
- return ir_const_move(ira, &instruction->base.base, get_the_one_possible_value(ira->codegen, operand_type));
+ switch (type_has_one_possible_value(ira->codegen, operand_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_inst_gen;
+ case OnePossibleValueYes:
+ return ir_const_move(ira, &instruction->base.base, get_the_one_possible_value(ira->codegen, operand_type));
+ case OnePossibleValueNo:
+ break;
}
IrInst *source_inst = &instruction->base.base;
@@ -28450,9 +28461,11 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
if (op2_val == nullptr)
return ira->codegen->invalid_inst_gen;
+ IrInstGen *result = ir_const(ira, source_inst, operand_type);
+ copy_const_val(ira->codegen, result->value, op1_val);
if (op == AtomicRmwOp_xchg) {
- ir_analyze_store_ptr(ira, source_inst, casted_ptr, casted_operand, false);
- return ir_const_move(ira, source_inst, op1_val);
+ copy_const_val(ira->codegen, op1_val, op2_val);
+ return result;
}
if (operand_type->id == ZigTypeIdPointer || operand_type->id == ZigTypeIdOptional) {
@@ -28461,6 +28474,7 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
return ira->codegen->invalid_inst_gen;
}
+ ErrorMsg *msg;
if (op == AtomicRmwOp_min || op == AtomicRmwOp_max) {
IrBinOp bin_op;
if (op == AtomicRmwOp_min)
@@ -28471,9 +28485,12 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
bin_op = IrBinOpCmpLessThan;
IrInstGen *dummy_value = ir_const(ira, source_inst, operand_type);
- ir_eval_bin_op_cmp_scalar(ira, source_inst, op1_val, bin_op, op2_val, dummy_value->value);
+ msg = ir_eval_bin_op_cmp_scalar(ira, source_inst, op1_val, bin_op, op2_val, dummy_value->value);
+ if (msg != nullptr) {
+ return ira->codegen->invalid_inst_gen;
+ }
if (dummy_value->value->data.x_bool)
- ir_analyze_store_ptr(ira, source_inst, casted_ptr, casted_operand, false);
+ copy_const_val(ira->codegen, op1_val, op2_val);
} else {
IrBinOp bin_op;
switch (op) {
@@ -28504,13 +28521,16 @@ static IrInstGen *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstSrcAto
bin_op = IrBinOpBinXor;
break;
}
- ir_eval_math_op_scalar(ira, source_inst, operand_type, op1_val, bin_op, op2_val, op1_val);
+ msg = ir_eval_math_op_scalar(ira, source_inst, operand_type, op1_val, bin_op, op2_val, op1_val);
+ if (msg != nullptr) {
+ return ira->codegen->invalid_inst_gen;
+ }
if (op == AtomicRmwOp_nand) {
bigint_not(&op1_val->data.x_bigint, &op1_val->data.x_bigint,
operand_type->data.integral.bit_count, operand_type->data.integral.is_signed);
}
}
- return ir_const_move(ira, source_inst, op1_val);
+ return result;
}
return ir_build_atomic_rmw_gen(ira, source_inst, casted_ptr, casted_operand, op,
@@ -28586,8 +28606,13 @@ static IrInstGen *ir_analyze_instruction_atomic_store(IrAnalyze *ira, IrInstSrcA
}
// special case zero bit types
- if (type_has_one_possible_value(ira->codegen, operand_type) == OnePossibleValueYes) {
- return ir_const_void(ira, &instruction->base.base);
+ switch (type_has_one_possible_value(ira->codegen, operand_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_inst_gen;
+ case OnePossibleValueYes:
+ return ir_const_void(ira, &instruction->base.base);
+ case OnePossibleValueNo:
+ break;
}
if (instr_is_comptime(casted_value) && instr_is_comptime(casted_ptr)) {
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index 36751e7d2..8870091d7 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -175,8 +175,8 @@ test "atomicrmw with ints" {
fn testAtomicRmwInt() void {
var x: u8 = 1;
- _ = @atomicRmw(u8, &x, .Xchg, 3, .SeqCst);
- expect(x == 3);
+ var res = @atomicRmw(u8, &x, .Xchg, 3, .SeqCst);
+ expect(x == 3 and res == 1);
_ = @atomicRmw(u8, &x, .Add, 3, .SeqCst);
expect(x == 6);
_ = @atomicRmw(u8, &x, .Sub, 1, .SeqCst);
From 205c4139620cddb083cff16e5d9264918f3876c2 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 12 Mar 2020 16:26:14 -0400
Subject: [PATCH 099/111] update musl headers to v1.2.0
---
.../aarch64-linux-musl/bits/alltypes.h | 121 +++++++++-------
.../include/aarch64-linux-musl/bits/endian.h | 5 -
.../include/aarch64-linux-musl/bits/socket.h | 33 -----
.../include/aarch64-linux-musl/bits/syscall.h | 6 +-
.../include/arm-linux-musl/bits/alltypes.h | 122 +++++++++-------
lib/libc/include/arm-linux-musl/bits/endian.h | 5 -
.../include/arm-linux-musl/bits/ipcstat.h | 1 +
lib/libc/include/arm-linux-musl/bits/limits.h | 7 -
lib/libc/include/arm-linux-musl/bits/msg.h | 15 +-
lib/libc/include/arm-linux-musl/bits/sem.h | 10 +-
lib/libc/include/arm-linux-musl/bits/shm.h | 16 ++-
lib/libc/include/arm-linux-musl/bits/stat.h | 6 +-
.../include/arm-linux-musl/bits/syscall.h | 46 +++---
lib/libc/include/generic-musl/aio.h | 4 +
lib/libc/include/generic-musl/alloca.h | 2 -
lib/libc/include/generic-musl/arpa/nameser.h | 1 -
lib/libc/include/generic-musl/bits/dirent.h | 11 ++
lib/libc/include/generic-musl/bits/endian.h | 1 -
lib/libc/include/generic-musl/bits/ioctl.h | 5 +
lib/libc/include/generic-musl/bits/limits.h | 7 -
lib/libc/include/generic-musl/bits/socket.h | 15 --
lib/libc/include/generic-musl/dirent.h | 14 +-
lib/libc/include/generic-musl/dlfcn.h | 4 +
lib/libc/include/generic-musl/endian.h | 46 +++---
lib/libc/include/generic-musl/features.h | 2 +
lib/libc/include/generic-musl/limits.h | 18 ++-
lib/libc/include/generic-musl/mqueue.h | 5 +
lib/libc/include/generic-musl/netinet/icmp6.h | 1 -
.../include/generic-musl/netinet/if_ether.h | 1 +
lib/libc/include/generic-musl/netinet/ip.h | 3 +-
lib/libc/include/generic-musl/netinet/ip6.h | 1 -
lib/libc/include/generic-musl/netinet/tcp.h | 4 +-
lib/libc/include/generic-musl/poll.h | 6 +
lib/libc/include/generic-musl/pthread.h | 10 ++
lib/libc/include/generic-musl/sched.h | 8 ++
lib/libc/include/generic-musl/semaphore.h | 4 +
lib/libc/include/generic-musl/signal.h | 8 ++
lib/libc/include/generic-musl/sys/acct.h | 1 -
lib/libc/include/generic-musl/sys/ioctl.h | 1 +
lib/libc/include/generic-musl/sys/mman.h | 2 +
lib/libc/include/generic-musl/sys/prctl.h | 4 +
lib/libc/include/generic-musl/sys/procfs.h | 7 +-
lib/libc/include/generic-musl/sys/ptrace.h | 29 ++++
lib/libc/include/generic-musl/sys/resource.h | 7 +-
lib/libc/include/generic-musl/sys/select.h | 5 +
lib/libc/include/generic-musl/sys/sem.h | 8 +-
lib/libc/include/generic-musl/sys/socket.h | 69 ++++++++-
lib/libc/include/generic-musl/sys/stat.h | 9 ++
lib/libc/include/generic-musl/sys/statvfs.h | 2 -
lib/libc/include/generic-musl/sys/time.h | 14 ++
lib/libc/include/generic-musl/sys/timeb.h | 6 +
lib/libc/include/generic-musl/sys/timerfd.h | 5 +
lib/libc/include/generic-musl/sys/timex.h | 5 +
.../include/generic-musl/sys/ttydefaults.h | 7 +-
lib/libc/include/generic-musl/sys/wait.h | 10 +-
lib/libc/include/generic-musl/threads.h | 6 +
lib/libc/include/generic-musl/time.h | 28 ++++
lib/libc/include/generic-musl/utime.h | 6 +
lib/libc/include/generic-musl/utmpx.h | 7 +-
.../include/i386-linux-musl/bits/alltypes.h | 134 +++++++++---------
.../include/i386-linux-musl/bits/ipcstat.h | 1 +
.../include/i386-linux-musl/bits/limits.h | 9 +-
lib/libc/include/i386-linux-musl/bits/msg.h | 15 +-
lib/libc/include/i386-linux-musl/bits/sem.h | 10 +-
lib/libc/include/i386-linux-musl/bits/shm.h | 16 ++-
lib/libc/include/i386-linux-musl/bits/stat.h | 6 +-
.../include/i386-linux-musl/bits/syscall.h | 46 +++---
.../include/mips-linux-musl/bits/alltypes.h | 122 +++++++++-------
.../include/mips-linux-musl/bits/endian.h | 5 -
lib/libc/include/mips-linux-musl/bits/hwcap.h | 13 +-
lib/libc/include/mips-linux-musl/bits/ioctl.h | 4 +-
.../include/mips-linux-musl/bits/ipcstat.h | 1 +
.../include/mips-linux-musl/bits/limits.h | 7 -
lib/libc/include/mips-linux-musl/bits/msg.h | 27 ++--
lib/libc/include/mips-linux-musl/bits/sem.h | 16 +++
lib/libc/include/mips-linux-musl/bits/shm.h | 29 ++++
.../include/mips-linux-musl/bits/signal.h | 8 +-
.../include/mips-linux-musl/bits/socket.h | 18 ---
lib/libc/include/mips-linux-musl/bits/stat.h | 12 +-
.../include/mips-linux-musl/bits/syscall.h | 46 +++---
.../include/mips64-linux-musl/bits/alltypes.h | 121 +++++++++-------
.../include/mips64-linux-musl/bits/endian.h | 5 -
.../include/mips64-linux-musl/bits/limits.h | 7 -
.../include/mips64-linux-musl/bits/socket.h | 34 -----
.../include/mips64-linux-musl/bits/syscall.h | 6 +-
.../powerpc-linux-musl/bits/alltypes.h | 121 ++++++++--------
.../include/powerpc-linux-musl/bits/endian.h | 15 --
.../include/powerpc-linux-musl/bits/ioctl.h | 4 +-
.../include/powerpc-linux-musl/bits/ipcstat.h | 1 +
.../include/powerpc-linux-musl/bits/limits.h | 7 -
.../include/powerpc-linux-musl/bits/msg.h | 15 +-
.../include/powerpc-linux-musl/bits/sem.h | 10 +-
.../include/powerpc-linux-musl/bits/shm.h | 16 ++-
.../include/powerpc-linux-musl/bits/signal.h | 2 +-
.../include/powerpc-linux-musl/bits/socket.h | 18 ---
.../include/powerpc-linux-musl/bits/stat.h | 6 +-
.../include/powerpc-linux-musl/bits/syscall.h | 46 +++---
.../powerpc64-linux-musl/bits/alltypes.h | 121 +++++++++-------
.../powerpc64-linux-musl/bits/endian.h | 5 -
.../powerpc64-linux-musl/bits/signal.h | 8 +-
.../powerpc64-linux-musl/bits/socket.h | 34 -----
.../powerpc64-linux-musl/bits/syscall.h | 6 +-
.../riscv64-linux-musl/bits/alltypes.h | 120 ++++++++--------
.../include/riscv64-linux-musl/bits/reg.h | 8 --
.../include/riscv64-linux-musl/bits/signal.h | 9 ++
.../include/riscv64-linux-musl/bits/socket.h | 19 ---
.../include/riscv64-linux-musl/bits/syscall.h | 4 +
.../include/s390x-linux-musl/bits/alltypes.h | 120 ++++++++--------
.../include/s390x-linux-musl/bits/endian.h | 1 -
.../include/s390x-linux-musl/bits/limits.h | 9 +-
.../include/s390x-linux-musl/bits/socket.h | 17 ---
.../include/s390x-linux-musl/bits/syscall.h | 6 +-
.../include/x86_64-linux-musl/bits/alltypes.h | 120 ++++++++--------
.../include/x86_64-linux-musl/bits/limits.h | 9 +-
.../include/x86_64-linux-musl/bits/socket.h | 16 ---
.../include/x86_64-linux-musl/bits/syscall.h | 6 +-
116 files changed, 1300 insertions(+), 1129 deletions(-)
delete mode 100644 lib/libc/include/aarch64-linux-musl/bits/endian.h
delete mode 100644 lib/libc/include/aarch64-linux-musl/bits/socket.h
delete mode 100644 lib/libc/include/arm-linux-musl/bits/endian.h
create mode 100644 lib/libc/include/arm-linux-musl/bits/ipcstat.h
delete mode 100644 lib/libc/include/arm-linux-musl/bits/limits.h
create mode 100644 lib/libc/include/generic-musl/bits/dirent.h
delete mode 100644 lib/libc/include/generic-musl/bits/endian.h
create mode 100644 lib/libc/include/i386-linux-musl/bits/ipcstat.h
delete mode 100644 lib/libc/include/mips-linux-musl/bits/endian.h
create mode 100644 lib/libc/include/mips-linux-musl/bits/ipcstat.h
delete mode 100644 lib/libc/include/mips-linux-musl/bits/limits.h
create mode 100644 lib/libc/include/mips-linux-musl/bits/sem.h
create mode 100644 lib/libc/include/mips-linux-musl/bits/shm.h
delete mode 100644 lib/libc/include/mips64-linux-musl/bits/endian.h
delete mode 100644 lib/libc/include/mips64-linux-musl/bits/limits.h
delete mode 100644 lib/libc/include/powerpc-linux-musl/bits/endian.h
create mode 100644 lib/libc/include/powerpc-linux-musl/bits/ipcstat.h
delete mode 100644 lib/libc/include/powerpc-linux-musl/bits/limits.h
delete mode 100644 lib/libc/include/powerpc64-linux-musl/bits/endian.h
delete mode 100644 lib/libc/include/riscv64-linux-musl/bits/reg.h
delete mode 100644 lib/libc/include/riscv64-linux-musl/bits/socket.h
delete mode 100644 lib/libc/include/s390x-linux-musl/bits/endian.h
delete mode 100644 lib/libc/include/s390x-linux-musl/bits/socket.h
delete mode 100644 lib/libc/include/x86_64-linux-musl/bits/socket.h
diff --git a/lib/libc/include/aarch64-linux-musl/bits/alltypes.h b/lib/libc/include/aarch64-linux-musl/bits/alltypes.h
index 0ee3cb464..fd60fe3a0 100644
--- a/lib/libc/include/aarch64-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/aarch64-linux-musl/bits/alltypes.h
@@ -2,16 +2,13 @@
#define _Int64 long
#define _Reg long
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
+#if __AARCH64EB__
+#define __BYTE_ORDER 4321
+#else
+#define __BYTE_ORDER 1234
#endif
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
@@ -53,52 +50,9 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -135,6 +89,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -270,7 +234,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -366,6 +330,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -401,6 +376,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-linux-musl/bits/endian.h b/lib/libc/include/aarch64-linux-musl/bits/endian.h
deleted file mode 100644
index 3ab24cc93..000000000
--- a/lib/libc/include/aarch64-linux-musl/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if __AARCH64EB__
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-linux-musl/bits/socket.h b/lib/libc/include/aarch64-linux-musl/bits/socket.h
deleted file mode 100644
index b4e9fb6a1..000000000
--- a/lib/libc/include/aarch64-linux-musl/bits/socket.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#include
-
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1, msg_iovlen;
-#else
- int msg_iovlen, __pad1;
-#endif
- void *msg_control;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad2;
- socklen_t msg_controllen;
-#else
- socklen_t msg_controllen;
- int __pad2;
-#endif
- int msg_flags;
-};
-
-struct cmsghdr {
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1;
- socklen_t cmsg_len;
-#else
- socklen_t cmsg_len;
- int __pad1;
-#endif
- int cmsg_level;
- int cmsg_type;
-};
\ No newline at end of file
diff --git a/lib/libc/include/aarch64-linux-musl/bits/syscall.h b/lib/libc/include/aarch64-linux-musl/bits/syscall.h
index 53f296e03..72392b874 100644
--- a/lib/libc/include/aarch64-linux-musl/bits/syscall.h
+++ b/lib/libc/include/aarch64-linux-musl/bits/syscall.h
@@ -287,6 +287,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define SYS_io_setup 0
#define SYS_io_destroy 1
@@ -576,4 +578,6 @@
#define SYS_fsopen 430
#define SYS_fsconfig 431
#define SYS_fsmount 432
-#define SYS_fspick 433
\ No newline at end of file
+#define SYS_fspick 433
+#define SYS_pidfd_open 434
+#define SYS_clone3 435
\ No newline at end of file
diff --git a/lib/libc/include/arm-linux-musl/bits/alltypes.h b/lib/libc/include/arm-linux-musl/bits/alltypes.h
index d1ad5774d..a99e77195 100644
--- a/lib/libc/include/arm-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/arm-linux-musl/bits/alltypes.h
@@ -1,17 +1,15 @@
+#define _REDIR_TIME64 1
#define _Addr int
#define _Int64 long long
#define _Reg int
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
+#if __ARMEB__
+#define __BYTE_ORDER 4321
+#else
+#define __BYTE_ORDER 1234
#endif
+#define __LONG_MAX 0x7fffffffL
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
@@ -37,52 +35,9 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -119,6 +74,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -254,7 +219,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -350,6 +315,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -385,6 +361,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/arm-linux-musl/bits/endian.h b/lib/libc/include/arm-linux-musl/bits/endian.h
deleted file mode 100644
index e4d86deb1..000000000
--- a/lib/libc/include/arm-linux-musl/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if __ARMEB__
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
\ No newline at end of file
diff --git a/lib/libc/include/arm-linux-musl/bits/ipcstat.h b/lib/libc/include/arm-linux-musl/bits/ipcstat.h
new file mode 100644
index 000000000..d055f3e83
--- /dev/null
+++ b/lib/libc/include/arm-linux-musl/bits/ipcstat.h
@@ -0,0 +1 @@
+#define IPC_STAT 0x102
\ No newline at end of file
diff --git a/lib/libc/include/arm-linux-musl/bits/limits.h b/lib/libc/include/arm-linux-musl/bits/limits.h
deleted file mode 100644
index ba9c3aa00..000000000
--- a/lib/libc/include/arm-linux-musl/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 32
-#endif
-
-#define LONG_MAX 0x7fffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
\ No newline at end of file
diff --git a/lib/libc/include/arm-linux-musl/bits/msg.h b/lib/libc/include/arm-linux-musl/bits/msg.h
index e5c8ba752..037fd956d 100644
--- a/lib/libc/include/arm-linux-musl/bits/msg.h
+++ b/lib/libc/include/arm-linux-musl/bits/msg.h
@@ -1,15 +1,18 @@
struct msqid_ds {
struct ipc_perm msg_perm;
- time_t msg_stime;
- int __unused1;
- time_t msg_rtime;
- int __unused2;
- time_t msg_ctime;
- int __unused3;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_ctime_lo;
+ unsigned long __msg_ctime_hi;
unsigned long msg_cbytes;
msgqnum_t msg_qnum;
msglen_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
unsigned long __unused[2];
+ time_t msg_stime;
+ time_t msg_rtime;
+ time_t msg_ctime;
};
\ No newline at end of file
diff --git a/lib/libc/include/arm-linux-musl/bits/sem.h b/lib/libc/include/arm-linux-musl/bits/sem.h
index 9097f9ffd..eaa885a8b 100644
--- a/lib/libc/include/arm-linux-musl/bits/sem.h
+++ b/lib/libc/include/arm-linux-musl/bits/sem.h
@@ -1,9 +1,9 @@
struct semid_ds {
struct ipc_perm sem_perm;
- time_t sem_otime;
- long __unused1;
- time_t sem_ctime;
- long __unused2;
+ unsigned long __sem_otime_lo;
+ unsigned long __sem_otime_hi;
+ unsigned long __sem_ctime_lo;
+ unsigned long __sem_ctime_hi;
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned short sem_nsems;
char __sem_nsems_pad[sizeof(long)-sizeof(short)];
@@ -13,4 +13,6 @@ struct semid_ds {
#endif
long __unused3;
long __unused4;
+ time_t sem_otime;
+ time_t sem_ctime;
};
\ No newline at end of file
diff --git a/lib/libc/include/arm-linux-musl/bits/shm.h b/lib/libc/include/arm-linux-musl/bits/shm.h
index aa5587127..1ecb03ca0 100644
--- a/lib/libc/include/arm-linux-musl/bits/shm.h
+++ b/lib/libc/include/arm-linux-musl/bits/shm.h
@@ -3,17 +3,21 @@
struct shmid_ds {
struct ipc_perm shm_perm;
size_t shm_segsz;
- time_t shm_atime;
- int __unused1;
- time_t shm_dtime;
- int __unused2;
- time_t shm_ctime;
- int __unused3;
+ unsigned long __shm_atime_lo;
+ unsigned long __shm_atime_hi;
+ unsigned long __shm_dtime_lo;
+ unsigned long __shm_dtime_hi;
+ unsigned long __shm_ctime_lo;
+ unsigned long __shm_ctime_hi;
pid_t shm_cpid;
pid_t shm_lpid;
unsigned long shm_nattch;
unsigned long __pad1;
unsigned long __pad2;
+ unsigned long __pad3;
+ time_t shm_atime;
+ time_t shm_dtime;
+ time_t shm_ctime;
};
struct shminfo {
diff --git a/lib/libc/include/arm-linux-musl/bits/stat.h b/lib/libc/include/arm-linux-musl/bits/stat.h
index 78e91b402..3bf02b375 100644
--- a/lib/libc/include/arm-linux-musl/bits/stat.h
+++ b/lib/libc/include/arm-linux-musl/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
+ struct {
+ long tv_sec;
+ long tv_nsec;
+ } __st_atim32, __st_mtim32, __st_ctim32;
+ ino_t st_ino;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
- ino_t st_ino;
};
\ No newline at end of file
diff --git a/lib/libc/include/arm-linux-musl/bits/syscall.h b/lib/libc/include/arm-linux-musl/bits/syscall.h
index 778430b87..5429a867e 100644
--- a/lib/libc/include/arm-linux-musl/bits/syscall.h
+++ b/lib/libc/include/arm-linux-musl/bits/syscall.h
@@ -55,8 +55,8 @@
#define __NR_sethostname 74
#define __NR_setrlimit 75
#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
+#define __NR_gettimeofday_time32 78
+#define __NR_settimeofday_time32 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_symlink 83
@@ -211,14 +211,14 @@
#define __NR_remap_file_pages 253
#define __NR_set_tid_address 256
#define __NR_timer_create 257
-#define __NR_timer_settime 258
-#define __NR_timer_gettime 259
+#define __NR_timer_settime32 258
+#define __NR_timer_gettime32 259
#define __NR_timer_getoverrun 260
#define __NR_timer_delete 261
-#define __NR_clock_settime 262
-#define __NR_clock_gettime 263
-#define __NR_clock_getres 264
-#define __NR_clock_nanosleep 265
+#define __NR_clock_settime32 262
+#define __NR_clock_gettime32 263
+#define __NR_clock_getres_time32 264
+#define __NR_clock_nanosleep_time32 265
#define __NR_statfs64 266
#define __NR_fstatfs64 267
#define __NR_tgkill 268
@@ -308,8 +308,8 @@
#define __NR_timerfd_create 350
#define __NR_eventfd 351
#define __NR_fallocate 352
-#define __NR_timerfd_settime 353
-#define __NR_timerfd_gettime 354
+#define __NR_timerfd_settime32 353
+#define __NR_timerfd_gettime32 354
#define __NR_signalfd4 355
#define __NR_eventfd2 356
#define __NR_epoll_create1 357
@@ -387,6 +387,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define __ARM_NR_breakpoint 0x0f0001
#define __ARM_NR_cacheflush 0x0f0002
@@ -452,8 +454,8 @@
#define SYS_sethostname 74
#define SYS_setrlimit 75
#define SYS_getrusage 77
-#define SYS_gettimeofday 78
-#define SYS_settimeofday 79
+#define SYS_gettimeofday_time32 78
+#define SYS_settimeofday_time32 79
#define SYS_getgroups 80
#define SYS_setgroups 81
#define SYS_symlink 83
@@ -608,14 +610,14 @@
#define SYS_remap_file_pages 253
#define SYS_set_tid_address 256
#define SYS_timer_create 257
-#define SYS_timer_settime 258
-#define SYS_timer_gettime 259
+#define SYS_timer_settime32 258
+#define SYS_timer_gettime32 259
#define SYS_timer_getoverrun 260
#define SYS_timer_delete 261
-#define SYS_clock_settime 262
-#define SYS_clock_gettime 263
-#define SYS_clock_getres 264
-#define SYS_clock_nanosleep 265
+#define SYS_clock_settime32 262
+#define SYS_clock_gettime32 263
+#define SYS_clock_getres_time32 264
+#define SYS_clock_nanosleep_time32 265
#define SYS_statfs64 266
#define SYS_fstatfs64 267
#define SYS_tgkill 268
@@ -705,8 +707,8 @@
#define SYS_timerfd_create 350
#define SYS_eventfd 351
#define SYS_fallocate 352
-#define SYS_timerfd_settime 353
-#define SYS_timerfd_gettime 354
+#define SYS_timerfd_settime32 353
+#define SYS_timerfd_gettime32 354
#define SYS_signalfd4 355
#define SYS_eventfd2 356
#define SYS_epoll_create1 357
@@ -783,4 +785,6 @@
#define SYS_fsopen 430
#define SYS_fsconfig 431
#define SYS_fsmount 432
-#define SYS_fspick 433
\ No newline at end of file
+#define SYS_fspick 433
+#define SYS_pidfd_open 434
+#define SYS_clone3 435
\ No newline at end of file
diff --git a/lib/libc/include/generic-musl/aio.h b/lib/libc/include/generic-musl/aio.h
index 0830b10c2..4588ff2e3 100644
--- a/lib/libc/include/generic-musl/aio.h
+++ b/lib/libc/include/generic-musl/aio.h
@@ -62,6 +62,10 @@ int lio_listio(int, struct aiocb *__restrict const *__restrict, int, struct sige
#define off64_t off_t
#endif
+#if _REDIR_TIME64
+__REDIR(aio_suspend, __aio_suspend_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/alloca.h b/lib/libc/include/generic-musl/alloca.h
index 53dd20479..28390cee6 100644
--- a/lib/libc/include/generic-musl/alloca.h
+++ b/lib/libc/include/generic-musl/alloca.h
@@ -10,9 +10,7 @@ extern "C" {
void *alloca(size_t);
-#ifdef __GNUC__
#define alloca __builtin_alloca
-#endif
#ifdef __cplusplus
}
diff --git a/lib/libc/include/generic-musl/arpa/nameser.h b/lib/libc/include/generic-musl/arpa/nameser.h
index bd411459e..10db66745 100644
--- a/lib/libc/include/generic-musl/arpa/nameser.h
+++ b/lib/libc/include/generic-musl/arpa/nameser.h
@@ -7,7 +7,6 @@ extern "C" {
#include
#include
-#include
#define __NAMESER 19991006
#define NS_PACKETSZ 512
diff --git a/lib/libc/include/generic-musl/bits/dirent.h b/lib/libc/include/generic-musl/bits/dirent.h
new file mode 100644
index 000000000..16f37f698
--- /dev/null
+++ b/lib/libc/include/generic-musl/bits/dirent.h
@@ -0,0 +1,11 @@
+#define _DIRENT_HAVE_D_RECLEN
+#define _DIRENT_HAVE_D_OFF
+#define _DIRENT_HAVE_D_TYPE
+
+struct dirent {
+ ino_t d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[256];
+};
\ No newline at end of file
diff --git a/lib/libc/include/generic-musl/bits/endian.h b/lib/libc/include/generic-musl/bits/endian.h
deleted file mode 100644
index b1a7affbb..000000000
--- a/lib/libc/include/generic-musl/bits/endian.h
+++ /dev/null
@@ -1 +0,0 @@
-#define __BYTE_ORDER __LITTLE_ENDIAN
\ No newline at end of file
diff --git a/lib/libc/include/generic-musl/bits/ioctl.h b/lib/libc/include/generic-musl/bits/ioctl.h
index 3af94ce07..1f814548d 100644
--- a/lib/libc/include/generic-musl/bits/ioctl.h
+++ b/lib/libc/include/generic-musl/bits/ioctl.h
@@ -104,7 +104,12 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
+#if __LONG_MAX == 0x7fffffff
+#define SIOCGSTAMP _IOR(0x89, 6, char[16])
+#define SIOCGSTAMPNS _IOR(0x89, 7, char[16])
+#else
#define SIOCGSTAMP 0x8906
#define SIOCGSTAMPNS 0x8907
+#endif
#include
\ No newline at end of file
diff --git a/lib/libc/include/generic-musl/bits/limits.h b/lib/libc/include/generic-musl/bits/limits.h
index 1be0deba7..e69de29bb 100644
--- a/lib/libc/include/generic-musl/bits/limits.h
+++ b/lib/libc/include/generic-musl/bits/limits.h
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
\ No newline at end of file
diff --git a/lib/libc/include/generic-musl/bits/socket.h b/lib/libc/include/generic-musl/bits/socket.h
index 34aba4d2a..e69de29bb 100644
--- a/lib/libc/include/generic-musl/bits/socket.h
+++ b/lib/libc/include/generic-musl/bits/socket.h
@@ -1,15 +0,0 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen;
- void *msg_control;
- socklen_t msg_controllen;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
\ No newline at end of file
diff --git a/lib/libc/include/generic-musl/dirent.h b/lib/libc/include/generic-musl/dirent.h
index 2be943aa1..665c411a6 100644
--- a/lib/libc/include/generic-musl/dirent.h
+++ b/lib/libc/include/generic-musl/dirent.h
@@ -15,20 +15,10 @@ extern "C" {
#include
+#include
+
typedef struct __dirstream DIR;
-#define _DIRENT_HAVE_D_RECLEN
-#define _DIRENT_HAVE_D_OFF
-#define _DIRENT_HAVE_D_TYPE
-
-struct dirent {
- ino_t d_ino;
- off_t d_off;
- unsigned short d_reclen;
- unsigned char d_type;
- char d_name[256];
-};
-
#define d_fileno d_ino
int closedir(DIR *);
diff --git a/lib/libc/include/generic-musl/dlfcn.h b/lib/libc/include/generic-musl/dlfcn.h
index 871f38585..c38b56c47 100644
--- a/lib/libc/include/generic-musl/dlfcn.h
+++ b/lib/libc/include/generic-musl/dlfcn.h
@@ -35,6 +35,10 @@ int dladdr(const void *, Dl_info *);
int dlinfo(void *, int, void *);
#endif
+#if _REDIR_TIME64
+__REDIR(dlsym, __dlsym_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/endian.h b/lib/libc/include/generic-musl/endian.h
index 35198b06a..12b8d3038 100644
--- a/lib/libc/include/generic-musl/endian.h
+++ b/lib/libc/include/generic-musl/endian.h
@@ -3,25 +3,19 @@
#include
-#define __LITTLE_ENDIAN 1234
-#define __BIG_ENDIAN 4321
+#define __NEED_uint16_t
+#define __NEED_uint32_t
+#define __NEED_uint64_t
+
+#include
+
#define __PDP_ENDIAN 3412
-#if defined(__GNUC__) && defined(__BYTE_ORDER__)
-#define __BYTE_ORDER __BYTE_ORDER__
-#else
-#include
-#endif
-
-#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-
#define BIG_ENDIAN __BIG_ENDIAN
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#define PDP_ENDIAN __PDP_ENDIAN
#define BYTE_ORDER __BYTE_ORDER
-#include
-
static __inline uint16_t __bswap16(uint16_t __x)
{
return __x<<8 | __x>>8;
@@ -40,43 +34,47 @@ static __inline uint64_t __bswap64(uint64_t __x)
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define htobe16(x) __bswap16(x)
#define be16toh(x) __bswap16(x)
-#define betoh16(x) __bswap16(x)
#define htobe32(x) __bswap32(x)
#define be32toh(x) __bswap32(x)
-#define betoh32(x) __bswap32(x)
#define htobe64(x) __bswap64(x)
#define be64toh(x) __bswap64(x)
-#define betoh64(x) __bswap64(x)
#define htole16(x) (uint16_t)(x)
#define le16toh(x) (uint16_t)(x)
-#define letoh16(x) (uint16_t)(x)
#define htole32(x) (uint32_t)(x)
#define le32toh(x) (uint32_t)(x)
-#define letoh32(x) (uint32_t)(x)
#define htole64(x) (uint64_t)(x)
#define le64toh(x) (uint64_t)(x)
-#define letoh64(x) (uint64_t)(x)
#else
#define htobe16(x) (uint16_t)(x)
#define be16toh(x) (uint16_t)(x)
-#define betoh16(x) (uint16_t)(x)
#define htobe32(x) (uint32_t)(x)
#define be32toh(x) (uint32_t)(x)
-#define betoh32(x) (uint32_t)(x)
#define htobe64(x) (uint64_t)(x)
#define be64toh(x) (uint64_t)(x)
-#define betoh64(x) (uint64_t)(x)
#define htole16(x) __bswap16(x)
#define le16toh(x) __bswap16(x)
-#define letoh16(x) __bswap16(x)
#define htole32(x) __bswap32(x)
#define le32toh(x) __bswap32(x)
-#define letoh32(x) __bswap32(x)
#define htole64(x) __bswap64(x)
#define le64toh(x) __bswap64(x)
-#define letoh64(x) __bswap64(x)
#endif
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define betoh16(x) __bswap16(x)
+#define betoh32(x) __bswap32(x)
+#define betoh64(x) __bswap64(x)
+#define letoh16(x) (uint16_t)(x)
+#define letoh32(x) (uint32_t)(x)
+#define letoh64(x) (uint64_t)(x)
+#else
+#define betoh16(x) (uint16_t)(x)
+#define betoh32(x) (uint32_t)(x)
+#define betoh64(x) (uint64_t)(x)
+#define letoh16(x) __bswap16(x)
+#define letoh32(x) __bswap32(x)
+#define letoh64(x) __bswap64(x)
+#endif
#endif
#endif
\ No newline at end of file
diff --git a/lib/libc/include/generic-musl/features.h b/lib/libc/include/generic-musl/features.h
index f649c1773..6b8e6aa25 100644
--- a/lib/libc/include/generic-musl/features.h
+++ b/lib/libc/include/generic-musl/features.h
@@ -35,4 +35,6 @@
#define _Noreturn
#endif
+#define __REDIR(x,y) __typeof__(x) x __asm__(#y)
+
#endif
\ No newline at end of file
diff --git a/lib/libc/include/generic-musl/limits.h b/lib/libc/include/generic-musl/limits.h
index 38ad59e60..78db5b776 100644
--- a/lib/libc/include/generic-musl/limits.h
+++ b/lib/libc/include/generic-musl/limits.h
@@ -3,9 +3,7 @@
#include
-/* Most limits are system-specific */
-
-#include
+#include /* __LONG_MAX */
/* Support signed or unsigned plain-char */
@@ -17,8 +15,6 @@
#define CHAR_MAX 127
#endif
-/* Some universal constants... */
-
#define CHAR_BIT 8
#define SCHAR_MIN (-128)
#define SCHAR_MAX 127
@@ -30,8 +26,10 @@
#define INT_MAX 0x7fffffff
#define UINT_MAX 0xffffffffU
#define LONG_MIN (-LONG_MAX-1)
+#define LONG_MAX __LONG_MAX
#define ULONG_MAX (2UL*LONG_MAX+1)
#define LLONG_MIN (-LLONG_MAX-1)
+#define LLONG_MAX 0x7fffffffffffffffLL
#define ULLONG_MAX (2ULL*LLONG_MAX+1)
#define MB_LEN_MAX 4
@@ -39,9 +37,13 @@
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+#include
+
#define PIPE_BUF 4096
#define FILESIZEBITS 64
+#ifndef NAME_MAX
#define NAME_MAX 255
+#endif
#define PATH_MAX 4096
#define NGROUPS_MAX 32
#define ARG_MAX 131072
@@ -53,6 +55,12 @@
#define TTY_NAME_MAX 32
#define HOST_NAME_MAX 255
+#if LONG_MAX == 0x7fffffffL
+#define LONG_BIT 32
+#else
+#define LONG_BIT 64
+#endif
+
/* Implementation choices... */
#define PTHREAD_KEYS_MAX 128
diff --git a/lib/libc/include/generic-musl/mqueue.h b/lib/libc/include/generic-musl/mqueue.h
index 917b80c2e..1b0a1b16e 100644
--- a/lib/libc/include/generic-musl/mqueue.h
+++ b/lib/libc/include/generic-musl/mqueue.h
@@ -30,6 +30,11 @@ ssize_t mq_timedreceive(mqd_t, char *__restrict, size_t, unsigned *__restrict, c
int mq_timedsend(mqd_t, const char *, size_t, unsigned, const struct timespec *);
int mq_unlink(const char *);
+#if _REDIR_TIME64
+__REDIR(mq_timedreceive, __mq_timedreceive_time64);
+__REDIR(mq_timedsend, __mq_timedsend_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/netinet/icmp6.h b/lib/libc/include/generic-musl/netinet/icmp6.h
index 6419a5a0a..44a2d8b0f 100644
--- a/lib/libc/include/generic-musl/netinet/icmp6.h
+++ b/lib/libc/include/generic-musl/netinet/icmp6.h
@@ -9,7 +9,6 @@ extern "C" {
#include
#include
#include
-#include
#define ICMP6_FILTER 1
diff --git a/lib/libc/include/generic-musl/netinet/if_ether.h b/lib/libc/include/generic-musl/netinet/if_ether.h
index 37d81698e..8be01cd4e 100644
--- a/lib/libc/include/generic-musl/netinet/if_ether.h
+++ b/lib/libc/include/generic-musl/netinet/if_ether.h
@@ -58,6 +58,7 @@
#define ETH_P_ERSPAN 0x88BE
#define ETH_P_PREAUTH 0x88C7
#define ETH_P_TIPC 0x88CA
+#define ETH_P_LLDP 0x88CC
#define ETH_P_MACSEC 0x88E5
#define ETH_P_8021AH 0x88E7
#define ETH_P_MVRP 0x88F5
diff --git a/lib/libc/include/generic-musl/netinet/ip.h b/lib/libc/include/generic-musl/netinet/ip.h
index 95baf6bdb..4a8a746f8 100644
--- a/lib/libc/include/generic-musl/netinet/ip.h
+++ b/lib/libc/include/generic-musl/netinet/ip.h
@@ -7,7 +7,6 @@ extern "C" {
#include
#include
-#include
struct timestamp {
uint8_t len;
@@ -191,6 +190,8 @@ struct ip_timestamp {
#define IP_MSS 576
+#define __UAPI_DEF_IPHDR 0
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/netinet/ip6.h b/lib/libc/include/generic-musl/netinet/ip6.h
index cb1292a64..dfb237795 100644
--- a/lib/libc/include/generic-musl/netinet/ip6.h
+++ b/lib/libc/include/generic-musl/netinet/ip6.h
@@ -7,7 +7,6 @@ extern "C" {
#include
#include
-#include
struct ip6_hdr {
union {
diff --git a/lib/libc/include/generic-musl/netinet/tcp.h b/lib/libc/include/generic-musl/netinet/tcp.h
index 949f70149..f0bdb1923 100644
--- a/lib/libc/include/generic-musl/netinet/tcp.h
+++ b/lib/libc/include/generic-musl/netinet/tcp.h
@@ -38,6 +38,7 @@
#define TCP_FASTOPEN_NO_COOKIE 34
#define TCP_ZEROCOPY_RECEIVE 35
#define TCP_INQ 36
+#define TCP_TX_DELAY 37
#define TCP_CM_INQ TCP_INQ
@@ -97,7 +98,6 @@ enum {
#include
#include
#include
-#include
typedef uint32_t tcp_seq;
@@ -234,6 +234,8 @@ struct tcp_info {
uint64_t tcpi_bytes_retrans;
uint32_t tcpi_dsack_dups;
uint32_t tcpi_reord_seen;
+ uint32_t tcpi_rcv_ooopack;
+ uint32_t tcpi_snd_wnd;
};
#define TCP_MD5SIG_MAXKEYLEN 80
diff --git a/lib/libc/include/generic-musl/poll.h b/lib/libc/include/generic-musl/poll.h
index be58c6417..45078b866 100644
--- a/lib/libc/include/generic-musl/poll.h
+++ b/lib/libc/include/generic-musl/poll.h
@@ -44,6 +44,12 @@ int poll (struct pollfd *, nfds_t, int);
int ppoll(struct pollfd *, nfds_t, const struct timespec *, const sigset_t *);
#endif
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+__REDIR(ppoll, __ppoll_time64);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/pthread.h b/lib/libc/include/generic-musl/pthread.h
index 6bfa3a5ac..e812c675c 100644
--- a/lib/libc/include/generic-musl/pthread.h
+++ b/lib/libc/include/generic-musl/pthread.h
@@ -224,6 +224,16 @@ int pthread_tryjoin_np(pthread_t, void **);
int pthread_timedjoin_np(pthread_t, void **, const struct timespec *);
#endif
+#if _REDIR_TIME64
+__REDIR(pthread_mutex_timedlock, __pthread_mutex_timedlock_time64);
+__REDIR(pthread_cond_timedwait, __pthread_cond_timedwait_time64);
+__REDIR(pthread_rwlock_timedrdlock, __pthread_rwlock_timedrdlock_time64);
+__REDIR(pthread_rwlock_timedwrlock, __pthread_rwlock_timedwrlock_time64);
+#ifdef _GNU_SOURCE
+__REDIR(pthread_timedjoin_np, __pthread_timedjoin_np_time64);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sched.h b/lib/libc/include/generic-musl/sched.h
index 7963785f6..6225d25d5 100644
--- a/lib/libc/include/generic-musl/sched.h
+++ b/lib/libc/include/generic-musl/sched.h
@@ -19,10 +19,14 @@ extern "C" {
struct sched_param {
int sched_priority;
int __reserved1;
+#if _REDIR_TIME64
+ long __reserved2[4];
+#else
struct {
time_t __reserved1;
long __reserved2;
} __reserved2[2];
+#endif
int __reserved3;
};
@@ -133,6 +137,10 @@ __CPU_op_func_S(XOR, ^)
#endif
+#if _REDIR_TIME64
+__REDIR(sched_rr_get_interval, __sched_rr_get_interval_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/semaphore.h b/lib/libc/include/generic-musl/semaphore.h
index 52f956ad2..8f26fb75f 100644
--- a/lib/libc/include/generic-musl/semaphore.h
+++ b/lib/libc/include/generic-musl/semaphore.h
@@ -29,6 +29,10 @@ int sem_trywait(sem_t *);
int sem_unlink(const char *);
int sem_wait(sem_t *);
+#if _REDIR_TIME64
+__REDIR(sem_timedwait, __sem_timedwait_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/signal.h b/lib/libc/include/generic-musl/signal.h
index 37ee858c4..99d473c50 100644
--- a/lib/libc/include/generic-musl/signal.h
+++ b/lib/libc/include/generic-musl/signal.h
@@ -271,6 +271,14 @@ typedef int sig_atomic_t;
void (*signal(int, void (*)(int)))(int);
int raise(int);
+#if _REDIR_TIME64
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
+ || defined(_BSD_SOURCE)
+__REDIR(sigtimedwait, __sigtimedwait_time64);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/acct.h b/lib/libc/include/generic-musl/sys/acct.h
index 02e4c7887..b4161dec6 100644
--- a/lib/libc/include/generic-musl/sys/acct.h
+++ b/lib/libc/include/generic-musl/sys/acct.h
@@ -6,7 +6,6 @@ extern "C" {
#endif
#include
-#include
#include
#include
diff --git a/lib/libc/include/generic-musl/sys/ioctl.h b/lib/libc/include/generic-musl/sys/ioctl.h
index 7d3a88079..28c9b6e24 100644
--- a/lib/libc/include/generic-musl/sys/ioctl.h
+++ b/lib/libc/include/generic-musl/sys/ioctl.h
@@ -4,6 +4,7 @@
extern "C" {
#endif
+#include
#include
#define N_TTY 0
diff --git a/lib/libc/include/generic-musl/sys/mman.h b/lib/libc/include/generic-musl/sys/mman.h
index 85c605b75..9bfd0a107 100644
--- a/lib/libc/include/generic-musl/sys/mman.h
+++ b/lib/libc/include/generic-musl/sys/mman.h
@@ -92,6 +92,8 @@ extern "C" {
#define MADV_DODUMP 17
#define MADV_WIPEONFORK 18
#define MADV_KEEPONFORK 19
+#define MADV_COLD 20
+#define MADV_PAGEOUT 21
#define MADV_HWPOISON 100
#define MADV_SOFT_OFFLINE 101
#endif
diff --git a/lib/libc/include/generic-musl/sys/prctl.h b/lib/libc/include/generic-musl/sys/prctl.h
index 4cc6567f9..c5f79d86d 100644
--- a/lib/libc/include/generic-musl/sys/prctl.h
+++ b/lib/libc/include/generic-musl/sys/prctl.h
@@ -154,6 +154,10 @@ struct prctl_mm_map {
#define PR_PAC_APDBKEY (1UL << 3)
#define PR_PAC_APGAKEY (1UL << 4)
+#define PR_SET_TAGGED_ADDR_CTRL 55
+#define PR_GET_TAGGED_ADDR_CTRL 56
+#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+
int prctl (int, ...);
#ifdef __cplusplus
diff --git a/lib/libc/include/generic-musl/sys/procfs.h b/lib/libc/include/generic-musl/sys/procfs.h
index 6c255d3a8..03db62abf 100644
--- a/lib/libc/include/generic-musl/sys/procfs.h
+++ b/lib/libc/include/generic-musl/sys/procfs.h
@@ -23,10 +23,9 @@ struct elf_prstatus {
pid_t pr_ppid;
pid_t pr_pgrp;
pid_t pr_sid;
- struct timeval pr_utime;
- struct timeval pr_stime;
- struct timeval pr_cutime;
- struct timeval pr_cstime;
+ struct {
+ long tv_sec, tv_usec;
+ } pr_utime, pr_stime, pr_cutime, pr_cstime;
elf_gregset_t pr_reg;
int pr_fpvalid;
};
diff --git a/lib/libc/include/generic-musl/sys/ptrace.h b/lib/libc/include/generic-musl/sys/ptrace.h
index a37ef97bc..1f0c6890f 100644
--- a/lib/libc/include/generic-musl/sys/ptrace.h
+++ b/lib/libc/include/generic-musl/sys/ptrace.h
@@ -41,6 +41,7 @@ extern "C" {
#define PTRACE_SETSIGMASK 0x420b
#define PTRACE_SECCOMP_GET_FILTER 0x420c
#define PTRACE_SECCOMP_GET_METADATA 0x420d
+#define PTRACE_GET_SYSCALL_INFO 0x420e
#define PT_READ_I PTRACE_PEEKTEXT
#define PT_READ_D PTRACE_PEEKDATA
@@ -88,6 +89,11 @@ extern "C" {
#define PTRACE_PEEKSIGINFO_SHARED 1
+#define PTRACE_SYSCALL_INFO_NONE 0
+#define PTRACE_SYSCALL_INFO_ENTRY 1
+#define PTRACE_SYSCALL_INFO_EXIT 2
+#define PTRACE_SYSCALL_INFO_SECCOMP 3
+
#include
struct __ptrace_peeksiginfo_args {
@@ -101,6 +107,29 @@ struct __ptrace_seccomp_metadata {
uint64_t flags;
};
+struct __ptrace_syscall_info {
+ uint8_t op;
+ uint8_t __pad[3];
+ uint32_t arch;
+ uint64_t instruction_pointer;
+ uint64_t stack_pointer;
+ union {
+ struct {
+ uint64_t nr;
+ uint64_t args[6];
+ } entry;
+ struct {
+ int64_t rval;
+ uint8_t is_error;
+ } exit;
+ struct {
+ uint64_t nr;
+ uint64_t args[6];
+ uint32_t ret_data;
+ } seccomp;
+ };
+};
+
long ptrace(int, ...);
#ifdef __cplusplus
diff --git a/lib/libc/include/generic-musl/sys/resource.h b/lib/libc/include/generic-musl/sys/resource.h
index 90def956e..8ef18ec05 100644
--- a/lib/libc/include/generic-musl/sys/resource.h
+++ b/lib/libc/include/generic-musl/sys/resource.h
@@ -90,7 +90,8 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *);
#define RLIMIT_MSGQUEUE 12
#define RLIMIT_NICE 13
#define RLIMIT_RTPRIO 14
-#define RLIMIT_NLIMITS 15
+#define RLIMIT_RTTIME 15
+#define RLIMIT_NLIMITS 16
#define RLIM_NLIMITS RLIMIT_NLIMITS
@@ -104,6 +105,10 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *);
#define rlim64_t rlim_t
#endif
+#if _REDIR_TIME64
+__REDIR(getrusage, __getrusage_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/select.h b/lib/libc/include/generic-musl/sys/select.h
index 1a54ab588..8ebe0c8b0 100644
--- a/lib/libc/include/generic-musl/sys/select.h
+++ b/lib/libc/include/generic-musl/sys/select.h
@@ -35,6 +35,11 @@ int pselect (int, fd_set *__restrict, fd_set *__restrict, fd_set *__restrict, co
#define NFDBITS (8*(int)sizeof(long))
#endif
+#if _REDIR_TIME64
+__REDIR(select, __select_time64);
+__REDIR(pselect, __pselect_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/sem.h b/lib/libc/include/generic-musl/sys/sem.h
index 95e5d9433..41362fab2 100644
--- a/lib/libc/include/generic-musl/sys/sem.h
+++ b/lib/libc/include/generic-musl/sys/sem.h
@@ -25,8 +25,6 @@ extern "C" {
#define SETVAL 16
#define SETALL 17
-#include
-
#include
#define _SEM_SEMUN_UNDEFINED 1
@@ -62,6 +60,12 @@ int semop(int, struct sembuf *, size_t);
int semtimedop(int, struct sembuf *, size_t, const struct timespec *);
#endif
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+__REDIR(semtimedop, __semtimedop_time64);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/socket.h b/lib/libc/include/generic-musl/sys/socket.h
index 2c82ee12b..957d3da9f 100644
--- a/lib/libc/include/generic-musl/sys/socket.h
+++ b/lib/libc/include/generic-musl/sys/socket.h
@@ -19,6 +19,40 @@ extern "C" {
#include
+struct msghdr {
+ void *msg_name;
+ socklen_t msg_namelen;
+ struct iovec *msg_iov;
+#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN
+ int __pad1;
+#endif
+ int msg_iovlen;
+#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN
+ int __pad1;
+#endif
+ void *msg_control;
+#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN
+ int __pad2;
+#endif
+ socklen_t msg_controllen;
+#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN
+ int __pad2;
+#endif
+ int msg_flags;
+};
+
+struct cmsghdr {
+#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __BIG_ENDIAN
+ int __pad1;
+#endif
+ socklen_t cmsg_len;
+#if __LONG_MAX > 0x7fffffff && __BYTE_ORDER == __LITTLE_ENDIAN
+ int __pad1;
+#endif
+ int cmsg_level;
+ int cmsg_type;
+};
+
#ifdef _GNU_SOURCE
struct ucred {
pid_t pid;
@@ -182,8 +216,6 @@ struct linger {
#define SO_PEERCRED 17
#define SO_RCVLOWAT 18
#define SO_SNDLOWAT 19
-#define SO_RCVTIMEO 20
-#define SO_SNDTIMEO 21
#define SO_ACCEPTCONN 30
#define SO_PEERSEC 31
#define SO_SNDBUFFORCE 32
@@ -192,6 +224,28 @@ struct linger {
#define SO_DOMAIN 39
#endif
+#ifndef SO_RCVTIMEO
+#if __LONG_MAX == 0x7fffffff
+#define SO_RCVTIMEO 66
+#define SO_SNDTIMEO 67
+#else
+#define SO_RCVTIMEO 20
+#define SO_SNDTIMEO 21
+#endif
+#endif
+
+#ifndef SO_TIMESTAMP
+#if __LONG_MAX == 0x7fffffff
+#define SO_TIMESTAMP 63
+#define SO_TIMESTAMPNS 64
+#define SO_TIMESTAMPING 65
+#else
+#define SO_TIMESTAMP 29
+#define SO_TIMESTAMPNS 35
+#define SO_TIMESTAMPING 37
+#endif
+#endif
+
#define SO_SECURITY_AUTHENTICATION 22
#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
#define SO_SECURITY_ENCRYPTION_NETWORK 24
@@ -203,14 +257,10 @@ struct linger {
#define SO_GET_FILTER SO_ATTACH_FILTER
#define SO_PEERNAME 28
-#define SO_TIMESTAMP 29
#define SCM_TIMESTAMP SO_TIMESTAMP
-
#define SO_PASSSEC 34
-#define SO_TIMESTAMPNS 35
#define SCM_TIMESTAMPNS SO_TIMESTAMPNS
#define SO_MARK 36
-#define SO_TIMESTAMPING 37
#define SCM_TIMESTAMPING SO_TIMESTAMPING
#define SO_RXQ_OVFL 40
#define SO_WIFI_STATUS 41
@@ -238,6 +288,7 @@ struct linger {
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME
#define SO_BINDTOIFINDEX 62
+#define SO_DETACH_REUSEPORT_BPF 68
#ifndef SOL_SOCKET
#define SOL_SOCKET 1
@@ -350,6 +401,12 @@ int setsockopt (int, int, int, const void *, socklen_t);
int sockatmark (int);
+#if _REDIR_TIME64
+#ifdef _GNU_SOURCE
+__REDIR(recvmmsg, __recvmmsg_time64);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/stat.h b/lib/libc/include/generic-musl/sys/stat.h
index 521b873af..e8a375344 100644
--- a/lib/libc/include/generic-musl/sys/stat.h
+++ b/lib/libc/include/generic-musl/sys/stat.h
@@ -110,6 +110,15 @@ int lchmod(const char *, mode_t);
#define off64_t off_t
#endif
+#if _REDIR_TIME64
+__REDIR(stat, __stat_time64);
+__REDIR(fstat, __fstat_time64);
+__REDIR(lstat, __lstat_time64);
+__REDIR(fstatat, __fstatat_time64);
+__REDIR(futimens, __futimens_time64);
+__REDIR(utimensat, __utimensat_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/statvfs.h b/lib/libc/include/generic-musl/sys/statvfs.h
index b2fb003b3..0da838f1e 100644
--- a/lib/libc/include/generic-musl/sys/statvfs.h
+++ b/lib/libc/include/generic-musl/sys/statvfs.h
@@ -11,8 +11,6 @@ extern "C" {
#define __NEED_fsfilcnt_t
#include
-#include
-
struct statvfs {
unsigned long f_bsize, f_frsize;
fsblkcnt_t f_blocks, f_bfree, f_bavail;
diff --git a/lib/libc/include/generic-musl/sys/time.h b/lib/libc/include/generic-musl/sys/time.h
index cb3022c77..301c098ab 100644
--- a/lib/libc/include/generic-musl/sys/time.h
+++ b/lib/libc/include/generic-musl/sys/time.h
@@ -56,6 +56,20 @@ int adjtime (const struct timeval *, struct timeval *);
(void)0 )
#endif
+#if _REDIR_TIME64
+__REDIR(gettimeofday, __gettimeofday_time64);
+__REDIR(getitimer, __getitimer_time64);
+__REDIR(setitimer, __setitimer_time64);
+__REDIR(utimes, __utimes_time64);
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+__REDIR(futimes, __futimes_time64);
+__REDIR(futimesat, __futimesat_time64);
+__REDIR(lutimes, __lutimes_time64);
+__REDIR(settimeofday, __settimeofday_time64);
+__REDIR(adjtime, __adjtime64);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/timeb.h b/lib/libc/include/generic-musl/sys/timeb.h
index acbde569f..6da1226b1 100644
--- a/lib/libc/include/generic-musl/sys/timeb.h
+++ b/lib/libc/include/generic-musl/sys/timeb.h
@@ -4,6 +4,8 @@
extern "C" {
#endif
+#include
+
#define __NEED_time_t
#include
@@ -16,6 +18,10 @@ struct timeb {
int ftime(struct timeb *);
+#if _REDIR_TIME64
+__REDIR(ftime, __ftime64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/timerfd.h b/lib/libc/include/generic-musl/sys/timerfd.h
index 3bea27f45..ff158861c 100644
--- a/lib/libc/include/generic-musl/sys/timerfd.h
+++ b/lib/libc/include/generic-musl/sys/timerfd.h
@@ -20,6 +20,11 @@ int timerfd_create(int, int);
int timerfd_settime(int, int, const struct itimerspec *, struct itimerspec *);
int timerfd_gettime(int, struct itimerspec *);
+#if _REDIR_TIME64
+__REDIR(timerfd_settime, __timerfd_settime64);
+__REDIR(timerfd_gettime, __timerfd_gettime64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/timex.h b/lib/libc/include/generic-musl/sys/timex.h
index fc42fc653..cab33a954 100644
--- a/lib/libc/include/generic-musl/sys/timex.h
+++ b/lib/libc/include/generic-musl/sys/timex.h
@@ -91,6 +91,11 @@ struct timex {
int adjtimex(struct timex *);
int clock_adjtime(clockid_t, struct timex *);
+#if _REDIR_TIME64
+__REDIR(adjtimex, __adjtimex_time64);
+__REDIR(clock_adjtime, __clock_adjtime64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/sys/ttydefaults.h b/lib/libc/include/generic-musl/sys/ttydefaults.h
index 232487331..602a4af79 100644
--- a/lib/libc/include/generic-musl/sys/ttydefaults.h
+++ b/lib/libc/include/generic-musl/sys/ttydefaults.h
@@ -6,16 +6,11 @@
#define TTYDEF_LFLAG (ECHO | ICANON | ISIG | IEXTEN | ECHOE|ECHOKE|ECHOCTL)
#define TTYDEF_CFLAG (CREAD | CS7 | PARENB | HUPCL)
#define TTYDEF_SPEED (B9600)
-#define CTRL(x) (x&037)
+#define CTRL(x) ((x)&037)
#define CEOF CTRL('d')
-#ifdef _POSIX_VDISABLE
-#define CEOL _POSIX_VDISABLE
-#define CSTATUS _POSIX_VDISABLE
-#else
#define CEOL '\0'
#define CSTATUS '\0'
-#endif
#define CERASE 0177
#define CINTR CTRL('c')
diff --git a/lib/libc/include/generic-musl/sys/wait.h b/lib/libc/include/generic-musl/sys/wait.h
index 352fdcadf..0ad11ab54 100644
--- a/lib/libc/include/generic-musl/sys/wait.h
+++ b/lib/libc/include/generic-musl/sys/wait.h
@@ -13,7 +13,8 @@ extern "C" {
typedef enum {
P_ALL = 0,
P_PID = 1,
- P_PGID = 2
+ P_PGID = 2,
+ P_PIDFD = 3
} idtype_t;
pid_t wait (int *);
@@ -53,6 +54,13 @@ pid_t wait4 (pid_t, int *, int, struct rusage *);
#define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu)
#define WIFCONTINUED(s) ((s) == 0xffff)
+#if _REDIR_TIME64
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+__REDIR(wait3, __wait3_time64);
+__REDIR(wait4, __wait4_time64);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/threads.h b/lib/libc/include/generic-musl/threads.h
index 51ef3bad7..cecff6647 100644
--- a/lib/libc/include/generic-musl/threads.h
+++ b/lib/libc/include/generic-musl/threads.h
@@ -80,6 +80,12 @@ void tss_delete(tss_t);
int tss_set(tss_t, void *);
void *tss_get(tss_t);
+#if _REDIR_TIME64
+__REDIR(thrd_sleep, __thrd_sleep_time64);
+__REDIR(mtx_timedlock, __mtx_timedlock_time64);
+__REDIR(cnd_timedwait, __cnd_timedwait_time64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/time.h b/lib/libc/include/generic-musl/time.h
index 755c6ad7a..5a9f61eb4 100644
--- a/lib/libc/include/generic-musl/time.h
+++ b/lib/libc/include/generic-musl/time.h
@@ -130,6 +130,34 @@ int stime(const time_t *);
time_t timegm(struct tm *);
#endif
+#if _REDIR_TIME64
+__REDIR(time, __time64);
+__REDIR(difftime, __difftime64);
+__REDIR(mktime, __mktime64);
+__REDIR(gmtime, __gmtime64);
+__REDIR(localtime, __localtime64);
+__REDIR(ctime, __ctime64);
+__REDIR(timespec_get, __timespec_get_time64);
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
+ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
+ || defined(_BSD_SOURCE)
+__REDIR(gmtime_r, __gmtime64_r);
+__REDIR(localtime_r, __localtime64_r);
+__REDIR(ctime_r, __ctime64_r);
+__REDIR(nanosleep, __nanosleep_time64);
+__REDIR(clock_getres, __clock_getres_time64);
+__REDIR(clock_gettime, __clock_gettime64);
+__REDIR(clock_settime, __clock_settime64);
+__REDIR(clock_nanosleep, __clock_nanosleep_time64);
+__REDIR(timer_settime, __timer_settime64);
+__REDIR(timer_gettime, __timer_gettime64);
+#endif
+#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
+__REDIR(stime, __stime64);
+__REDIR(timegm, __timegm_time64);
+#endif
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/utime.h b/lib/libc/include/generic-musl/utime.h
index 89c2bc801..1ad5c49c5 100644
--- a/lib/libc/include/generic-musl/utime.h
+++ b/lib/libc/include/generic-musl/utime.h
@@ -5,6 +5,8 @@
extern "C" {
#endif
+#include
+
#define __NEED_time_t
#include
@@ -16,6 +18,10 @@ struct utimbuf {
int utime (const char *, const struct utimbuf *);
+#if _REDIR_TIME64
+__REDIR(utime, __utime64);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/libc/include/generic-musl/utmpx.h b/lib/libc/include/generic-musl/utmpx.h
index 769101a2f..29fa60d2f 100644
--- a/lib/libc/include/generic-musl/utmpx.h
+++ b/lib/libc/include/generic-musl/utmpx.h
@@ -16,6 +16,7 @@ extern "C" {
struct utmpx {
short ut_type;
+ short __ut_pad1;
pid_t ut_pid;
char ut_line[32];
char ut_id[4];
@@ -25,7 +26,11 @@ struct utmpx {
short __e_termination;
short __e_exit;
} ut_exit;
- long ut_session;
+#if __BYTE_ORDER == 1234
+ int ut_session, __ut_pad2;
+#else
+ int __ut_pad2, ut_session;
+#endif
struct timeval ut_tv;
unsigned ut_addr_v6[4];
char __unused[20];
diff --git a/lib/libc/include/i386-linux-musl/bits/alltypes.h b/lib/libc/include/i386-linux-musl/bits/alltypes.h
index b4a1272fe..c330f5dd0 100644
--- a/lib/libc/include/i386-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/i386-linux-musl/bits/alltypes.h
@@ -1,30 +1,10 @@
+#define _REDIR_TIME64 1
#define _Addr int
#define _Int64 long long
#define _Reg int
-#if __GNUC__ >= 3
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
-#endif
-
-#else
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef struct __va_list * va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef struct __va_list * __isoc_va_list;
-#define __DEFINED___isoc_va_list
-#endif
-
-#endif
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffL
#ifndef __cplusplus
#ifdef __WCHAR_TYPE__
@@ -85,52 +65,9 @@ typedef struct { alignas(8) long long __ll; long double __ld; } max_align_t;
#endif
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -167,6 +104,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -302,7 +249,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -398,6 +345,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -433,6 +391,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/i386-linux-musl/bits/ipcstat.h b/lib/libc/include/i386-linux-musl/bits/ipcstat.h
new file mode 100644
index 000000000..d055f3e83
--- /dev/null
+++ b/lib/libc/include/i386-linux-musl/bits/ipcstat.h
@@ -0,0 +1 @@
+#define IPC_STAT 0x102
\ No newline at end of file
diff --git a/lib/libc/include/i386-linux-musl/bits/limits.h b/lib/libc/include/i386-linux-musl/bits/limits.h
index 208e36bcd..fc11433d9 100644
--- a/lib/libc/include/i386-linux-musl/bits/limits.h
+++ b/lib/libc/include/i386-linux-musl/bits/limits.h
@@ -1,8 +1 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define PAGESIZE 4096
-#define LONG_BIT 32
-#endif
-
-#define LONG_MAX 0x7fffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
\ No newline at end of file
+#define PAGESIZE 4096
\ No newline at end of file
diff --git a/lib/libc/include/i386-linux-musl/bits/msg.h b/lib/libc/include/i386-linux-musl/bits/msg.h
index e5c8ba752..037fd956d 100644
--- a/lib/libc/include/i386-linux-musl/bits/msg.h
+++ b/lib/libc/include/i386-linux-musl/bits/msg.h
@@ -1,15 +1,18 @@
struct msqid_ds {
struct ipc_perm msg_perm;
- time_t msg_stime;
- int __unused1;
- time_t msg_rtime;
- int __unused2;
- time_t msg_ctime;
- int __unused3;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_ctime_lo;
+ unsigned long __msg_ctime_hi;
unsigned long msg_cbytes;
msgqnum_t msg_qnum;
msglen_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
unsigned long __unused[2];
+ time_t msg_stime;
+ time_t msg_rtime;
+ time_t msg_ctime;
};
\ No newline at end of file
diff --git a/lib/libc/include/i386-linux-musl/bits/sem.h b/lib/libc/include/i386-linux-musl/bits/sem.h
index e63d0732b..f4936d6f5 100644
--- a/lib/libc/include/i386-linux-musl/bits/sem.h
+++ b/lib/libc/include/i386-linux-musl/bits/sem.h
@@ -1,11 +1,13 @@
struct semid_ds {
struct ipc_perm sem_perm;
- time_t sem_otime;
- long __unused1;
- time_t sem_ctime;
- long __unused2;
+ unsigned long __sem_otime_lo;
+ unsigned long __sem_otime_hi;
+ unsigned long __sem_ctime_lo;
+ unsigned long __sem_ctime_hi;
unsigned short sem_nsems;
char __sem_nsems_pad[sizeof(long)-sizeof(short)];
long __unused3;
long __unused4;
+ time_t sem_otime;
+ time_t sem_ctime;
};
\ No newline at end of file
diff --git a/lib/libc/include/i386-linux-musl/bits/shm.h b/lib/libc/include/i386-linux-musl/bits/shm.h
index aa5587127..1ecb03ca0 100644
--- a/lib/libc/include/i386-linux-musl/bits/shm.h
+++ b/lib/libc/include/i386-linux-musl/bits/shm.h
@@ -3,17 +3,21 @@
struct shmid_ds {
struct ipc_perm shm_perm;
size_t shm_segsz;
- time_t shm_atime;
- int __unused1;
- time_t shm_dtime;
- int __unused2;
- time_t shm_ctime;
- int __unused3;
+ unsigned long __shm_atime_lo;
+ unsigned long __shm_atime_hi;
+ unsigned long __shm_dtime_lo;
+ unsigned long __shm_dtime_hi;
+ unsigned long __shm_ctime_lo;
+ unsigned long __shm_ctime_hi;
pid_t shm_cpid;
pid_t shm_lpid;
unsigned long shm_nattch;
unsigned long __pad1;
unsigned long __pad2;
+ unsigned long __pad3;
+ time_t shm_atime;
+ time_t shm_dtime;
+ time_t shm_ctime;
};
struct shminfo {
diff --git a/lib/libc/include/i386-linux-musl/bits/stat.h b/lib/libc/include/i386-linux-musl/bits/stat.h
index 78e91b402..3bf02b375 100644
--- a/lib/libc/include/i386-linux-musl/bits/stat.h
+++ b/lib/libc/include/i386-linux-musl/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
+ struct {
+ long tv_sec;
+ long tv_nsec;
+ } __st_atim32, __st_mtim32, __st_ctim32;
+ ino_t st_ino;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
- ino_t st_ino;
};
\ No newline at end of file
diff --git a/lib/libc/include/i386-linux-musl/bits/syscall.h b/lib/libc/include/i386-linux-musl/bits/syscall.h
index 482f1d1d1..c9bfc7f95 100644
--- a/lib/libc/include/i386-linux-musl/bits/syscall.h
+++ b/lib/libc/include/i386-linux-musl/bits/syscall.h
@@ -76,8 +76,8 @@
#define __NR_setrlimit 75
#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
+#define __NR_gettimeofday_time32 78
+#define __NR_settimeofday_time32 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_select 82
@@ -257,14 +257,14 @@
#define __NR_remap_file_pages 257
#define __NR_set_tid_address 258
#define __NR_timer_create 259
-#define __NR_timer_settime (__NR_timer_create+1)
-#define __NR_timer_gettime (__NR_timer_create+2)
+#define __NR_timer_settime32 (__NR_timer_create+1)
+#define __NR_timer_gettime32 (__NR_timer_create+2)
#define __NR_timer_getoverrun (__NR_timer_create+3)
#define __NR_timer_delete (__NR_timer_create+4)
-#define __NR_clock_settime (__NR_timer_create+5)
-#define __NR_clock_gettime (__NR_timer_create+6)
-#define __NR_clock_getres (__NR_timer_create+7)
-#define __NR_clock_nanosleep (__NR_timer_create+8)
+#define __NR_clock_settime32 (__NR_timer_create+5)
+#define __NR_clock_gettime32 (__NR_timer_create+6)
+#define __NR_clock_getres_time32 (__NR_timer_create+7)
+#define __NR_clock_nanosleep_time32 (__NR_timer_create+8)
#define __NR_statfs64 268
#define __NR_fstatfs64 269
#define __NR_tgkill 270
@@ -322,8 +322,8 @@
#define __NR_timerfd_create 322
#define __NR_eventfd 323
#define __NR_fallocate 324
-#define __NR_timerfd_settime 325
-#define __NR_timerfd_gettime 326
+#define __NR_timerfd_settime32 325
+#define __NR_timerfd_gettime32 326
#define __NR_signalfd4 327
#define __NR_eventfd2 328
#define __NR_epoll_create1 329
@@ -424,6 +424,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define SYS_restart_syscall 0
#define SYS_exit 1
@@ -503,8 +505,8 @@
#define SYS_setrlimit 75
#define SYS_getrlimit 76 /* Back compatible 2Gig limited rlimit */
#define SYS_getrusage 77
-#define SYS_gettimeofday 78
-#define SYS_settimeofday 79
+#define SYS_gettimeofday_time32 78
+#define SYS_settimeofday_time32 79
#define SYS_getgroups 80
#define SYS_setgroups 81
#define SYS_select 82
@@ -682,14 +684,14 @@
#define SYS_remap_file_pages 257
#define SYS_set_tid_address 258
#define SYS_timer_create 259
-#define SYS_timer_settime (__NR_timer_create+1)
-#define SYS_timer_gettime (__NR_timer_create+2)
+#define SYS_timer_settime32 (__NR_timer_create+1)
+#define SYS_timer_gettime32 (__NR_timer_create+2)
#define SYS_timer_getoverrun (__NR_timer_create+3)
#define SYS_timer_delete (__NR_timer_create+4)
-#define SYS_clock_settime (__NR_timer_create+5)
-#define SYS_clock_gettime (__NR_timer_create+6)
-#define SYS_clock_getres (__NR_timer_create+7)
-#define SYS_clock_nanosleep (__NR_timer_create+8)
+#define SYS_clock_settime32 (__NR_timer_create+5)
+#define SYS_clock_gettime32 (__NR_timer_create+6)
+#define SYS_clock_getres_time32 (__NR_timer_create+7)
+#define SYS_clock_nanosleep_time32 (__NR_timer_create+8)
#define SYS_statfs64 268
#define SYS_fstatfs64 269
#define SYS_tgkill 270
@@ -747,8 +749,8 @@
#define SYS_timerfd_create 322
#define SYS_eventfd 323
#define SYS_fallocate 324
-#define SYS_timerfd_settime 325
-#define SYS_timerfd_gettime 326
+#define SYS_timerfd_settime32 325
+#define SYS_timerfd_gettime32 326
#define SYS_signalfd4 327
#define SYS_eventfd2 328
#define SYS_epoll_create1 329
@@ -848,4 +850,6 @@
#define SYS_fsopen 430
#define SYS_fsconfig 431
#define SYS_fsmount 432
-#define SYS_fspick 433
\ No newline at end of file
+#define SYS_fspick 433
+#define SYS_pidfd_open 434
+#define SYS_clone3 435
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/alltypes.h b/lib/libc/include/mips-linux-musl/bits/alltypes.h
index d0f00474b..c714577aa 100644
--- a/lib/libc/include/mips-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/mips-linux-musl/bits/alltypes.h
@@ -1,17 +1,15 @@
+#define _REDIR_TIME64 1
#define _Addr int
#define _Int64 long long
#define _Reg int
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
+#if _MIPSEL || __MIPSEL || __MIPSEL__
+#define __BYTE_ORDER 1234
+#else
+#define __BYTE_ORDER 4321
#endif
+#define __LONG_MAX 0x7fffffffL
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
@@ -37,52 +35,9 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -119,6 +74,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -254,7 +219,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -350,6 +315,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -385,6 +361,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/endian.h b/lib/libc/include/mips-linux-musl/bits/endian.h
deleted file mode 100644
index e888a1939..000000000
--- a/lib/libc/include/mips-linux-musl/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if _MIPSEL || __MIPSEL || __MIPSEL__
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#else
-#define __BYTE_ORDER __BIG_ENDIAN
-#endif
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/hwcap.h b/lib/libc/include/mips-linux-musl/bits/hwcap.h
index 0cc1faa9f..bcdd936f1 100644
--- a/lib/libc/include/mips-linux-musl/bits/hwcap.h
+++ b/lib/libc/include/mips-linux-musl/bits/hwcap.h
@@ -1,3 +1,14 @@
#define HWCAP_MIPS_R6 (1 << 0)
#define HWCAP_MIPS_MSA (1 << 1)
-#define HWCAP_MIPS_CRC32 (1 << 2)
\ No newline at end of file
+#define HWCAP_MIPS_CRC32 (1 << 2)
+#define HWCAP_MIPS_MIPS16 (1 << 3)
+#define HWCAP_MIPS_MDMX (1 << 4)
+#define HWCAP_MIPS_MIPS3D (1 << 5)
+#define HWCAP_MIPS_SMARTMIPS (1 << 6)
+#define HWCAP_MIPS_DSP (1 << 7)
+#define HWCAP_MIPS_DSP2 (1 << 8)
+#define HWCAP_MIPS_DSP3 (1 << 9)
+#define HWCAP_MIPS_MIPS16E2 (1 << 10)
+#define HWCAP_LOONGSON_MMI (1 << 11)
+#define HWCAP_LOONGSON_EXT (1 << 12)
+#define HWCAP_LOONGSON_EXT2 (1 << 13)
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/ioctl.h b/lib/libc/include/mips-linux-musl/bits/ioctl.h
index ce20d2e76..c4fbd0d8d 100644
--- a/lib/libc/include/mips-linux-musl/bits/ioctl.h
+++ b/lib/libc/include/mips-linux-musl/bits/ioctl.h
@@ -110,5 +110,5 @@
#define SIOCATMARK _IOR('s', 7, int)
#define SIOCSPGRP _IOW('s', 8, pid_t)
#define SIOCGPGRP _IOR('s', 9, pid_t)
-#define SIOCGSTAMP 0x8906
-#define SIOCGSTAMPNS 0x8907
\ No newline at end of file
+#define SIOCGSTAMP _IOR(0x89, 6, char[16])
+#define SIOCGSTAMPNS _IOR(0x89, 7, char[16])
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/ipcstat.h b/lib/libc/include/mips-linux-musl/bits/ipcstat.h
new file mode 100644
index 000000000..d055f3e83
--- /dev/null
+++ b/lib/libc/include/mips-linux-musl/bits/ipcstat.h
@@ -0,0 +1 @@
+#define IPC_STAT 0x102
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/limits.h b/lib/libc/include/mips-linux-musl/bits/limits.h
deleted file mode 100644
index ba9c3aa00..000000000
--- a/lib/libc/include/mips-linux-musl/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 32
-#endif
-
-#define LONG_MAX 0x7fffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/msg.h b/lib/libc/include/mips-linux-musl/bits/msg.h
index f310867d1..9e428cabd 100644
--- a/lib/libc/include/mips-linux-musl/bits/msg.h
+++ b/lib/libc/include/mips-linux-musl/bits/msg.h
@@ -1,19 +1,19 @@
struct msqid_ds {
struct ipc_perm msg_perm;
#if _MIPSEL || __MIPSEL || __MIPSEL__
- time_t msg_stime;
- int __unused1;
- time_t msg_rtime;
- int __unused2;
- time_t msg_ctime;
- int __unused3;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_ctime_lo;
+ unsigned long __msg_ctime_hi;
#else
- int __unused1;
- time_t msg_stime;
- int __unused2;
- time_t msg_rtime;
- int __unused3;
- time_t msg_ctime;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_ctime_hi;
+ unsigned long __msg_ctime_lo;
#endif
unsigned long msg_cbytes;
msgqnum_t msg_qnum;
@@ -21,4 +21,7 @@ struct msqid_ds {
pid_t msg_lspid;
pid_t msg_lrpid;
unsigned long __unused[2];
+ time_t msg_stime;
+ time_t msg_rtime;
+ time_t msg_ctime;
};
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/sem.h b/lib/libc/include/mips-linux-musl/bits/sem.h
new file mode 100644
index 000000000..87b05d488
--- /dev/null
+++ b/lib/libc/include/mips-linux-musl/bits/sem.h
@@ -0,0 +1,16 @@
+struct semid_ds {
+ struct ipc_perm sem_perm;
+ unsigned long __sem_otime_lo;
+ unsigned long __sem_ctime_lo;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned short sem_nsems;
+ char __sem_nsems_pad[sizeof(long)-sizeof(short)];
+#else
+ char __sem_nsems_pad[sizeof(long)-sizeof(short)];
+ unsigned short sem_nsems;
+#endif
+ unsigned long __sem_otime_hi;
+ unsigned long __sem_ctime_hi;
+ time_t sem_otime;
+ time_t sem_ctime;
+};
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/shm.h b/lib/libc/include/mips-linux-musl/bits/shm.h
new file mode 100644
index 000000000..4e5357d24
--- /dev/null
+++ b/lib/libc/include/mips-linux-musl/bits/shm.h
@@ -0,0 +1,29 @@
+#define SHMLBA 4096
+
+struct shmid_ds {
+ struct ipc_perm shm_perm;
+ size_t shm_segsz;
+ unsigned long __shm_atime_lo;
+ unsigned long __shm_dtime_lo;
+ unsigned long __shm_ctime_lo;
+ pid_t shm_cpid;
+ pid_t shm_lpid;
+ unsigned long shm_nattch;
+ unsigned short __shm_atime_hi;
+ unsigned short __shm_dtime_hi;
+ unsigned short __shm_ctime_hi;
+ unsigned short __pad1;
+ time_t shm_atime;
+ time_t shm_dtime;
+ time_t shm_ctime;
+};
+
+struct shminfo {
+ unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4];
+};
+
+struct shm_info {
+ int __used_ids;
+ unsigned long shm_tot, shm_rss, shm_swp;
+ unsigned long __swap_attempts, __swap_successes;
+};
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/signal.h b/lib/libc/include/mips-linux-musl/bits/signal.h
index 8a7d5852e..f9a6ea657 100644
--- a/lib/libc/include/mips-linux-musl/bits/signal.h
+++ b/lib/libc/include/mips-linux-musl/bits/signal.h
@@ -19,14 +19,18 @@ typedef struct {
} fpregset_t;
struct sigcontext {
unsigned sc_regmask, sc_status;
- unsigned long long sc_pc, sc_regs[32], sc_fpregs[32];
+ unsigned long long sc_pc;
+ gregset_t sc_regs;
+ fpregset_t sc_fpregs;
unsigned sc_ownedfp, sc_fpc_csr, sc_fpc_eir, sc_used_math, sc_dsp;
unsigned long long sc_mdhi, sc_mdlo;
unsigned long sc_hi1, sc_lo1, sc_hi2, sc_lo2, sc_hi3, sc_lo3;
};
typedef struct {
unsigned regmask, status;
- unsigned long long pc, gregs[32], fpregs[32];
+ unsigned long long pc;
+ gregset_t gregs;
+ fpregset_t fpregs;
unsigned ownedfp, fpc_csr, fpc_eir, used_math, dsp;
unsigned long long mdhi, mdlo;
unsigned long hi1, lo1, hi2, lo2, hi3, lo3;
diff --git a/lib/libc/include/mips-linux-musl/bits/socket.h b/lib/libc/include/mips-linux-musl/bits/socket.h
index dd4c03b7f..751f71fc4 100644
--- a/lib/libc/include/mips-linux-musl/bits/socket.h
+++ b/lib/libc/include/mips-linux-musl/bits/socket.h
@@ -1,19 +1,3 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen;
- void *msg_control;
- socklen_t msg_controllen;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
-
#define SOCK_STREAM 2
#define SOCK_DGRAM 1
@@ -32,8 +16,6 @@ struct cmsghdr {
#define SO_RCVBUF 0x1002
#define SO_SNDLOWAT 0x1003
#define SO_RCVLOWAT 0x1004
-#define SO_RCVTIMEO 0x1006
-#define SO_SNDTIMEO 0x1005
#define SO_ERROR 0x1007
#define SO_TYPE 0x1008
#define SO_ACCEPTCONN 0x1009
diff --git a/lib/libc/include/mips-linux-musl/bits/stat.h b/lib/libc/include/mips-linux-musl/bits/stat.h
index 5e9d7ce47..f247f6983 100644
--- a/lib/libc/include/mips-linux-musl/bits/stat.h
+++ b/lib/libc/include/mips-linux-musl/bits/stat.h
@@ -12,11 +12,15 @@ struct stat {
dev_t st_rdev;
long __st_padding2[2];
off_t st_size;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
+ struct {
+ long tv_sec;
+ long tv_nsec;
+ } __st_atim32, __st_mtim32, __st_ctim32;
blksize_t st_blksize;
long __st_padding3;
blkcnt_t st_blocks;
- long __st_padding4[14];
+ struct timespec st_atim;
+ struct timespec st_mtim;
+ struct timespec st_ctim;
+ long __st_padding4[2];
};
\ No newline at end of file
diff --git a/lib/libc/include/mips-linux-musl/bits/syscall.h b/lib/libc/include/mips-linux-musl/bits/syscall.h
index 67bd95fa5..3f2666e56 100644
--- a/lib/libc/include/mips-linux-musl/bits/syscall.h
+++ b/lib/libc/include/mips-linux-musl/bits/syscall.h
@@ -76,8 +76,8 @@
#define __NR_setrlimit 4075
#define __NR_getrlimit 4076
#define __NR_getrusage 4077
-#define __NR_gettimeofday 4078
-#define __NR_settimeofday 4079
+#define __NR_gettimeofday_time32 4078
+#define __NR_settimeofday_time32 4079
#define __NR_getgroups 4080
#define __NR_setgroups 4081
#define __NR_reserved82 4082
@@ -256,14 +256,14 @@
#define __NR_statfs64 4255
#define __NR_fstatfs64 4256
#define __NR_timer_create 4257
-#define __NR_timer_settime 4258
-#define __NR_timer_gettime 4259
+#define __NR_timer_settime32 4258
+#define __NR_timer_gettime32 4259
#define __NR_timer_getoverrun 4260
#define __NR_timer_delete 4261
-#define __NR_clock_settime 4262
-#define __NR_clock_gettime 4263
-#define __NR_clock_getres 4264
-#define __NR_clock_nanosleep 4265
+#define __NR_clock_settime32 4262
+#define __NR_clock_gettime32 4263
+#define __NR_clock_getres_time32 4264
+#define __NR_clock_nanosleep_time32 4265
#define __NR_tgkill 4266
#define __NR_utimes 4267
#define __NR_mbind 4268
@@ -319,8 +319,8 @@
#define __NR_eventfd 4319
#define __NR_fallocate 4320
#define __NR_timerfd_create 4321
-#define __NR_timerfd_gettime 4322
-#define __NR_timerfd_settime 4323
+#define __NR_timerfd_gettime32 4322
+#define __NR_timerfd_settime32 4323
#define __NR_signalfd4 4324
#define __NR_eventfd2 4325
#define __NR_epoll_create1 4326
@@ -406,6 +406,8 @@
#define __NR_fsconfig 4431
#define __NR_fsmount 4432
#define __NR_fspick 4433
+#define __NR_pidfd_open 4434
+#define __NR_clone3 4435
#define SYS_syscall 4000
#define SYS_exit 4001
@@ -485,8 +487,8 @@
#define SYS_setrlimit 4075
#define SYS_getrlimit 4076
#define SYS_getrusage 4077
-#define SYS_gettimeofday 4078
-#define SYS_settimeofday 4079
+#define SYS_gettimeofday_time32 4078
+#define SYS_settimeofday_time32 4079
#define SYS_getgroups 4080
#define SYS_setgroups 4081
#define SYS_reserved82 4082
@@ -665,14 +667,14 @@
#define SYS_statfs64 4255
#define SYS_fstatfs64 4256
#define SYS_timer_create 4257
-#define SYS_timer_settime 4258
-#define SYS_timer_gettime 4259
+#define SYS_timer_settime32 4258
+#define SYS_timer_gettime32 4259
#define SYS_timer_getoverrun 4260
#define SYS_timer_delete 4261
-#define SYS_clock_settime 4262
-#define SYS_clock_gettime 4263
-#define SYS_clock_getres 4264
-#define SYS_clock_nanosleep 4265
+#define SYS_clock_settime32 4262
+#define SYS_clock_gettime32 4263
+#define SYS_clock_getres_time32 4264
+#define SYS_clock_nanosleep_time32 4265
#define SYS_tgkill 4266
#define SYS_utimes 4267
#define SYS_mbind 4268
@@ -728,8 +730,8 @@
#define SYS_eventfd 4319
#define SYS_fallocate 4320
#define SYS_timerfd_create 4321
-#define SYS_timerfd_gettime 4322
-#define SYS_timerfd_settime 4323
+#define SYS_timerfd_gettime32 4322
+#define SYS_timerfd_settime32 4323
#define SYS_signalfd4 4324
#define SYS_eventfd2 4325
#define SYS_epoll_create1 4326
@@ -814,4 +816,6 @@
#define SYS_fsopen 4430
#define SYS_fsconfig 4431
#define SYS_fsmount 4432
-#define SYS_fspick 4433
\ No newline at end of file
+#define SYS_fspick 4433
+#define SYS_pidfd_open 4434
+#define SYS_clone3 4435
\ No newline at end of file
diff --git a/lib/libc/include/mips64-linux-musl/bits/alltypes.h b/lib/libc/include/mips64-linux-musl/bits/alltypes.h
index 207896448..9745553d1 100644
--- a/lib/libc/include/mips64-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/mips64-linux-musl/bits/alltypes.h
@@ -2,16 +2,13 @@
#define _Int64 long
#define _Reg long
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
+#if _MIPSEL || __MIPSEL || __MIPSEL__
+#define __BYTE_ORDER 1234
+#else
+#define __BYTE_ORDER 4321
#endif
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
@@ -38,57 +35,14 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#endif
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
#if defined(__NEED_nlink_t) && !defined(__DEFINED_nlink_t)
typedef unsigned nlink_t;
#define __DEFINED_nlink_t
#endif
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -125,6 +79,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -260,7 +224,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -356,6 +320,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -391,6 +366,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/mips64-linux-musl/bits/endian.h b/lib/libc/include/mips64-linux-musl/bits/endian.h
deleted file mode 100644
index e888a1939..000000000
--- a/lib/libc/include/mips64-linux-musl/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if _MIPSEL || __MIPSEL || __MIPSEL__
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#else
-#define __BYTE_ORDER __BIG_ENDIAN
-#endif
\ No newline at end of file
diff --git a/lib/libc/include/mips64-linux-musl/bits/limits.h b/lib/libc/include/mips64-linux-musl/bits/limits.h
deleted file mode 100644
index ac11a8d7b..000000000
--- a/lib/libc/include/mips64-linux-musl/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
\ No newline at end of file
diff --git a/lib/libc/include/mips64-linux-musl/bits/socket.h b/lib/libc/include/mips64-linux-musl/bits/socket.h
index 87d555b12..420708452 100644
--- a/lib/libc/include/mips64-linux-musl/bits/socket.h
+++ b/lib/libc/include/mips64-linux-musl/bits/socket.h
@@ -1,37 +1,3 @@
-#include
-
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1, msg_iovlen;
-#else
- int msg_iovlen, __pad1;
-#endif
- void *msg_control;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad2;
- socklen_t msg_controllen;
-#else
- socklen_t msg_controllen;
- int __pad2;
-#endif
- int msg_flags;
-};
-
-struct cmsghdr {
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1;
- socklen_t cmsg_len;
-#else
- socklen_t cmsg_len;
- int __pad1;
-#endif
- int cmsg_level;
- int cmsg_type;
-};
-
#define SOCK_STREAM 2
#define SOCK_DGRAM 1
#define SOL_SOCKET 65535
diff --git a/lib/libc/include/mips64-linux-musl/bits/syscall.h b/lib/libc/include/mips64-linux-musl/bits/syscall.h
index e14881035..b3d86fe1d 100644
--- a/lib/libc/include/mips64-linux-musl/bits/syscall.h
+++ b/lib/libc/include/mips64-linux-musl/bits/syscall.h
@@ -336,6 +336,8 @@
#define __NR_fsconfig 5431
#define __NR_fsmount 5432
#define __NR_fspick 5433
+#define __NR_pidfd_open 5434
+#define __NR_clone3 5435
#define SYS_read 5000
#define SYS_write 5001
@@ -674,4 +676,6 @@
#define SYS_fsopen 5430
#define SYS_fsconfig 5431
#define SYS_fsmount 5432
-#define SYS_fspick 5433
\ No newline at end of file
+#define SYS_fspick 5433
+#define SYS_pidfd_open 5434
+#define SYS_clone3 5435
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/alltypes.h b/lib/libc/include/powerpc-linux-musl/bits/alltypes.h
index f94f3e2f4..f655b43e3 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/alltypes.h
@@ -1,17 +1,10 @@
+#define _REDIR_TIME64 1
#define _Addr int
#define _Int64 long long
#define _Reg int
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
-#endif
-
+#define __BYTE_ORDER 4321
+#define __LONG_MAX 0x7fffffffL
#ifndef __cplusplus
#ifdef __WCHAR_TYPE__
@@ -45,52 +38,9 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -127,6 +77,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -262,7 +222,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -358,6 +318,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -393,6 +364,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/endian.h b/lib/libc/include/powerpc-linux-musl/bits/endian.h
deleted file mode 100644
index ca2af1ed5..000000000
--- a/lib/libc/include/powerpc-linux-musl/bits/endian.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifdef __BIG_ENDIAN__
- #if __BIG_ENDIAN__
- #define __BYTE_ORDER __BIG_ENDIAN
- #endif
-#endif /* __BIG_ENDIAN__ */
-
-#ifdef __LITTLE_ENDIAN__
- #if __LITTLE_ENDIAN__
- #define __BYTE_ORDER __LITTLE_ENDIAN
- #endif
-#endif /* __LITTLE_ENDIAN__ */
-
-#ifndef __BYTE_ORDER
- #define __BYTE_ORDER __BIG_ENDIAN
-#endif
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/ioctl.h b/lib/libc/include/powerpc-linux-musl/bits/ioctl.h
index 98eff9a7d..bce4b1932 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/ioctl.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/ioctl.h
@@ -116,5 +116,5 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906
-#define SIOCGSTAMPNS 0x8907
\ No newline at end of file
+#define SIOCGSTAMP _IOR(0x89, 6, char[16])
+#define SIOCGSTAMPNS _IOR(0x89, 7, char[16])
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/ipcstat.h b/lib/libc/include/powerpc-linux-musl/bits/ipcstat.h
new file mode 100644
index 000000000..d055f3e83
--- /dev/null
+++ b/lib/libc/include/powerpc-linux-musl/bits/ipcstat.h
@@ -0,0 +1 @@
+#define IPC_STAT 0x102
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/limits.h b/lib/libc/include/powerpc-linux-musl/bits/limits.h
deleted file mode 100644
index ba9c3aa00..000000000
--- a/lib/libc/include/powerpc-linux-musl/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 32
-#endif
-
-#define LONG_MAX 0x7fffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/msg.h b/lib/libc/include/powerpc-linux-musl/bits/msg.h
index 1bbca229c..9232e0380 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/msg.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/msg.h
@@ -1,15 +1,18 @@
struct msqid_ds {
struct ipc_perm msg_perm;
- int __unused1;
- time_t msg_stime;
- int __unused2;
- time_t msg_rtime;
- int __unused3;
- time_t msg_ctime;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_ctime_hi;
+ unsigned long __msg_ctime_lo;
unsigned long msg_cbytes;
msgqnum_t msg_qnum;
msglen_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
unsigned long __unused[2];
+ time_t msg_stime;
+ time_t msg_rtime;
+ time_t msg_ctime;
};
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/sem.h b/lib/libc/include/powerpc-linux-musl/bits/sem.h
index fefd211aa..715a0ac85 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/sem.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/sem.h
@@ -1,10 +1,12 @@
struct semid_ds {
struct ipc_perm sem_perm;
- int __unused1;
- time_t sem_otime;
- int __unused2;
- time_t sem_ctime;
+ unsigned long __sem_otime_hi;
+ unsigned long __sem_otime_lo;
+ unsigned long __sem_ctime_hi;
+ unsigned long __sem_ctime_lo;
unsigned short __sem_nsems_pad, sem_nsems;
long __unused3;
long __unused4;
+ time_t sem_otime;
+ time_t sem_ctime;
};
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/shm.h b/lib/libc/include/powerpc-linux-musl/bits/shm.h
index ef46d7f10..e45c2ab19 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/shm.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/shm.h
@@ -2,19 +2,21 @@
struct shmid_ds {
struct ipc_perm shm_perm;
- int __unused1;
- time_t shm_atime;
- int __unused2;
- time_t shm_dtime;
- int __unused3;
- time_t shm_ctime;
- int __unused4;
+ unsigned long __shm_atime_hi;
+ unsigned long __shm_atime_lo;
+ unsigned long __shm_dtime_hi;
+ unsigned long __shm_dtime_lo;
+ unsigned long __shm_ctime_hi;
+ unsigned long __shm_ctime_lo;
size_t shm_segsz;
pid_t shm_cpid;
pid_t shm_lpid;
unsigned long shm_nattch;
unsigned long __pad1;
unsigned long __pad2;
+ time_t shm_atime;
+ time_t shm_dtime;
+ time_t shm_ctime;
};
struct shminfo {
diff --git a/lib/libc/include/powerpc-linux-musl/bits/signal.h b/lib/libc/include/powerpc-linux-musl/bits/signal.h
index 12e000131..48051afb6 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/signal.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/signal.h
@@ -28,7 +28,7 @@ struct sigcontext {
int signal;
unsigned long handler;
unsigned long oldmask;
- void *regs;
+ struct pt_regs *regs;
};
typedef struct {
diff --git a/lib/libc/include/powerpc-linux-musl/bits/socket.h b/lib/libc/include/powerpc-linux-musl/bits/socket.h
index ba5e2b50d..4225b9177 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/socket.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/socket.h
@@ -1,19 +1,3 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen;
- void *msg_control;
- socklen_t msg_controllen;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
-
#define SO_DEBUG 1
#define SO_REUSEADDR 2
#define SO_TYPE 3
@@ -31,8 +15,6 @@ struct cmsghdr {
#define SO_REUSEPORT 15
#define SO_RCVLOWAT 16
#define SO_SNDLOWAT 17
-#define SO_RCVTIMEO 18
-#define SO_SNDTIMEO 19
#define SO_PASSCRED 20
#define SO_PEERCRED 21
#define SO_ACCEPTCONN 30
diff --git a/lib/libc/include/powerpc-linux-musl/bits/stat.h b/lib/libc/include/powerpc-linux-musl/bits/stat.h
index e5298772d..fa6d8dfdb 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/stat.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/stat.h
@@ -13,8 +13,12 @@ struct stat {
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
+ struct {
+ long tv_sec;
+ long tv_nsec;
+ } __st_atim32, __st_mtim32, __st_ctim32;
+ unsigned __unused[2];
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
- unsigned __unused[2];
};
\ No newline at end of file
diff --git a/lib/libc/include/powerpc-linux-musl/bits/syscall.h b/lib/libc/include/powerpc-linux-musl/bits/syscall.h
index 888868ad5..ce2818352 100644
--- a/lib/libc/include/powerpc-linux-musl/bits/syscall.h
+++ b/lib/libc/include/powerpc-linux-musl/bits/syscall.h
@@ -76,8 +76,8 @@
#define __NR_setrlimit 75
#define __NR_getrlimit 76
#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
+#define __NR_gettimeofday_time32 78
+#define __NR_settimeofday_time32 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_select 82
@@ -238,14 +238,14 @@
#define __NR_epoll_wait 238
#define __NR_remap_file_pages 239
#define __NR_timer_create 240
-#define __NR_timer_settime 241
-#define __NR_timer_gettime 242
+#define __NR_timer_settime32 241
+#define __NR_timer_gettime32 242
#define __NR_timer_getoverrun 243
#define __NR_timer_delete 244
-#define __NR_clock_settime 245
-#define __NR_clock_gettime 246
-#define __NR_clock_getres 247
-#define __NR_clock_nanosleep 248
+#define __NR_clock_settime32 245
+#define __NR_clock_gettime32 246
+#define __NR_clock_getres_time32 247
+#define __NR_clock_nanosleep_time32 248
#define __NR_swapcontext 249
#define __NR_tgkill 250
#define __NR_utimes 251
@@ -307,8 +307,8 @@
#define __NR_sync_file_range2 308
#define __NR_fallocate 309
#define __NR_subpage_prot 310
-#define __NR_timerfd_settime 311
-#define __NR_timerfd_gettime 312
+#define __NR_timerfd_settime32 311
+#define __NR_timerfd_gettime32 312
#define __NR_signalfd4 313
#define __NR_eventfd2 314
#define __NR_epoll_create1 315
@@ -413,6 +413,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define SYS_restart_syscall 0
#define SYS_exit 1
@@ -492,8 +494,8 @@
#define SYS_setrlimit 75
#define SYS_getrlimit 76
#define SYS_getrusage 77
-#define SYS_gettimeofday 78
-#define SYS_settimeofday 79
+#define SYS_gettimeofday_time32 78
+#define SYS_settimeofday_time32 79
#define SYS_getgroups 80
#define SYS_setgroups 81
#define SYS_select 82
@@ -654,14 +656,14 @@
#define SYS_epoll_wait 238
#define SYS_remap_file_pages 239
#define SYS_timer_create 240
-#define SYS_timer_settime 241
-#define SYS_timer_gettime 242
+#define SYS_timer_settime32 241
+#define SYS_timer_gettime32 242
#define SYS_timer_getoverrun 243
#define SYS_timer_delete 244
-#define SYS_clock_settime 245
-#define SYS_clock_gettime 246
-#define SYS_clock_getres 247
-#define SYS_clock_nanosleep 248
+#define SYS_clock_settime32 245
+#define SYS_clock_gettime32 246
+#define SYS_clock_getres_time32 247
+#define SYS_clock_nanosleep_time32 248
#define SYS_swapcontext 249
#define SYS_tgkill 250
#define SYS_utimes 251
@@ -723,8 +725,8 @@
#define SYS_sync_file_range2 308
#define SYS_fallocate 309
#define SYS_subpage_prot 310
-#define SYS_timerfd_settime 311
-#define SYS_timerfd_gettime 312
+#define SYS_timerfd_settime32 311
+#define SYS_timerfd_gettime32 312
#define SYS_signalfd4 313
#define SYS_eventfd2 314
#define SYS_epoll_create1 315
@@ -828,4 +830,6 @@
#define SYS_fsopen 430
#define SYS_fsconfig 431
#define SYS_fsmount 432
-#define SYS_fspick 433
\ No newline at end of file
+#define SYS_fspick 433
+#define SYS_pidfd_open 434
+#define SYS_clone3 435
\ No newline at end of file
diff --git a/lib/libc/include/powerpc64-linux-musl/bits/alltypes.h b/lib/libc/include/powerpc64-linux-musl/bits/alltypes.h
index b650fe8f9..6177874ff 100644
--- a/lib/libc/include/powerpc64-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/powerpc64-linux-musl/bits/alltypes.h
@@ -2,16 +2,13 @@
#define _Int64 long
#define _Reg long
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
+#if __BIG_ENDIAN__
+#define __BYTE_ORDER 4321
+#else
+#define __BYTE_ORDER 1234
#endif
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
@@ -37,52 +34,9 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -119,6 +73,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -254,7 +218,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -350,6 +314,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -385,6 +360,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/powerpc64-linux-musl/bits/endian.h b/lib/libc/include/powerpc64-linux-musl/bits/endian.h
deleted file mode 100644
index 4f3a41f0c..000000000
--- a/lib/libc/include/powerpc64-linux-musl/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if __BIG_ENDIAN__
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
\ No newline at end of file
diff --git a/lib/libc/include/powerpc64-linux-musl/bits/signal.h b/lib/libc/include/powerpc64-linux-musl/bits/signal.h
index c312b0d45..de82cf9ec 100644
--- a/lib/libc/include/powerpc64-linux-musl/bits/signal.h
+++ b/lib/libc/include/powerpc64-linux-musl/bits/signal.h
@@ -9,11 +9,7 @@
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
typedef unsigned long greg_t, gregset_t[48];
-
-typedef struct {
- double fpregs[32];
- double fpscr;
-} fpregset_t;
+typedef double fpregset_t[33];
typedef struct {
#ifdef __GNUC__
@@ -36,7 +32,7 @@ typedef struct sigcontext {
int _pad0;
unsigned long handler;
unsigned long oldmask;
- void *regs;
+ struct pt_regs *regs;
gregset_t gp_regs;
fpregset_t fp_regs;
vrregset_t *v_regs;
diff --git a/lib/libc/include/powerpc64-linux-musl/bits/socket.h b/lib/libc/include/powerpc64-linux-musl/bits/socket.h
index d453d65ce..1fa551d93 100644
--- a/lib/libc/include/powerpc64-linux-musl/bits/socket.h
+++ b/lib/libc/include/powerpc64-linux-musl/bits/socket.h
@@ -1,37 +1,3 @@
-#include
-
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1, msg_iovlen;
-#else
- int msg_iovlen, __pad1;
-#endif
- void *msg_control;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad2;
- socklen_t msg_controllen;
-#else
- socklen_t msg_controllen;
- int __pad2;
-#endif
- int msg_flags;
-};
-
-struct cmsghdr {
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1;
- socklen_t cmsg_len;
-#else
- socklen_t cmsg_len;
- int __pad1;
-#endif
- int cmsg_level;
- int cmsg_type;
-};
-
#define SO_DEBUG 1
#define SO_REUSEADDR 2
#define SO_TYPE 3
diff --git a/lib/libc/include/powerpc64-linux-musl/bits/syscall.h b/lib/libc/include/powerpc64-linux-musl/bits/syscall.h
index 38b826314..4592aac64 100644
--- a/lib/libc/include/powerpc64-linux-musl/bits/syscall.h
+++ b/lib/libc/include/powerpc64-linux-musl/bits/syscall.h
@@ -385,6 +385,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define SYS_restart_syscall 0
#define SYS_exit 1
@@ -772,4 +774,6 @@
#define SYS_fsopen 430
#define SYS_fsconfig 431
#define SYS_fsmount 432
-#define SYS_fspick 433
\ No newline at end of file
+#define SYS_fspick 433
+#define SYS_pidfd_open 434
+#define SYS_clone3 435
\ No newline at end of file
diff --git a/lib/libc/include/riscv64-linux-musl/bits/alltypes.h b/lib/libc/include/riscv64-linux-musl/bits/alltypes.h
index c326d3277..8db53c829 100644
--- a/lib/libc/include/riscv64-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/riscv64-linux-musl/bits/alltypes.h
@@ -2,16 +2,8 @@
#define _Int64 long
#define _Reg long
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
-#endif
-
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
@@ -48,52 +40,9 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -130,6 +79,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -265,7 +224,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -361,6 +320,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -396,6 +366,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/riscv64-linux-musl/bits/reg.h b/lib/libc/include/riscv64-linux-musl/bits/reg.h
deleted file mode 100644
index b449472ae..000000000
--- a/lib/libc/include/riscv64-linux-musl/bits/reg.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#undef __WORDSIZE
-#define __WORDSIZE 64
-#define REG_PC 0
-#define REG_RA 1
-#define REG_SP 2
-#define REG_TP 4
-#define REG_S0 8
-#define REG_A0 10
\ No newline at end of file
diff --git a/lib/libc/include/riscv64-linux-musl/bits/signal.h b/lib/libc/include/riscv64-linux-musl/bits/signal.h
index 5eddfd18b..87ae2ee7d 100644
--- a/lib/libc/include/riscv64-linux-musl/bits/signal.h
+++ b/lib/libc/include/riscv64-linux-musl/bits/signal.h
@@ -35,6 +35,15 @@ typedef struct mcontext_t {
union __riscv_mc_fp_state __fpregs;
} mcontext_t;
+#if defined(_GNU_SOURCE)
+#define REG_PC 0
+#define REG_RA 1
+#define REG_SP 2
+#define REG_TP 4
+#define REG_S0 8
+#define REG_A0 10
+#endif
+
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
typedef unsigned long greg_t;
typedef unsigned long gregset_t[32];
diff --git a/lib/libc/include/riscv64-linux-musl/bits/socket.h b/lib/libc/include/riscv64-linux-musl/bits/socket.h
deleted file mode 100644
index dfedbe836..000000000
--- a/lib/libc/include/riscv64-linux-musl/bits/socket.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#include
-
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen, __pad1;
- void *msg_control;
- socklen_t msg_controllen;
- int __pad2;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int __pad1;
- int cmsg_level;
- int cmsg_type;
-};
\ No newline at end of file
diff --git a/lib/libc/include/riscv64-linux-musl/bits/syscall.h b/lib/libc/include/riscv64-linux-musl/bits/syscall.h
index 423de02ab..808207fb4 100644
--- a/lib/libc/include/riscv64-linux-musl/bits/syscall.h
+++ b/lib/libc/include/riscv64-linux-musl/bits/syscall.h
@@ -287,6 +287,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define __NR_sysriscv __NR_arch_specific_syscall
#define __NR_riscv_flush_icache (__NR_sysriscv + 15)
@@ -579,5 +581,7 @@
#define SYS_fsconfig 431
#define SYS_fsmount 432
#define SYS_fspick 433
+#define SYS_pidfd_open 434
+#define SYS_clone3 435
#define SYS_sysriscv __NR_arch_specific_syscall
#define SYS_riscv_flush_icache (__NR_sysriscv + 15)
\ No newline at end of file
diff --git a/lib/libc/include/s390x-linux-musl/bits/alltypes.h b/lib/libc/include/s390x-linux-musl/bits/alltypes.h
index e831219e0..55dbfa500 100644
--- a/lib/libc/include/s390x-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/s390x-linux-musl/bits/alltypes.h
@@ -2,16 +2,8 @@
#define _Int64 long
#define _Reg long
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
-#endif
-
+#define __BYTE_ORDER 4321
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
@@ -37,52 +29,9 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -119,6 +68,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -254,7 +213,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -350,6 +309,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -385,6 +355,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/s390x-linux-musl/bits/endian.h b/lib/libc/include/s390x-linux-musl/bits/endian.h
deleted file mode 100644
index 19063e742..000000000
--- a/lib/libc/include/s390x-linux-musl/bits/endian.h
+++ /dev/null
@@ -1 +0,0 @@
-#define __BYTE_ORDER __BIG_ENDIAN
\ No newline at end of file
diff --git a/lib/libc/include/s390x-linux-musl/bits/limits.h b/lib/libc/include/s390x-linux-musl/bits/limits.h
index e98429585..fc11433d9 100644
--- a/lib/libc/include/s390x-linux-musl/bits/limits.h
+++ b/lib/libc/include/s390x-linux-musl/bits/limits.h
@@ -1,8 +1 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define PAGESIZE 4096
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
\ No newline at end of file
+#define PAGESIZE 4096
\ No newline at end of file
diff --git a/lib/libc/include/s390x-linux-musl/bits/socket.h b/lib/libc/include/s390x-linux-musl/bits/socket.h
deleted file mode 100644
index decce2073..000000000
--- a/lib/libc/include/s390x-linux-musl/bits/socket.h
+++ /dev/null
@@ -1,17 +0,0 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int __pad1, msg_iovlen;
- void *msg_control;
- int __pad2;
- socklen_t msg_controllen;
- int msg_flags;
-};
-
-struct cmsghdr {
- int __pad1;
- socklen_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
\ No newline at end of file
diff --git a/lib/libc/include/s390x-linux-musl/bits/syscall.h b/lib/libc/include/s390x-linux-musl/bits/syscall.h
index e2436d95c..790f51373 100644
--- a/lib/libc/include/s390x-linux-musl/bits/syscall.h
+++ b/lib/libc/include/s390x-linux-musl/bits/syscall.h
@@ -350,6 +350,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define SYS_exit 1
#define SYS_fork 2
@@ -702,4 +704,6 @@
#define SYS_fsopen 430
#define SYS_fsconfig 431
#define SYS_fsmount 432
-#define SYS_fspick 433
\ No newline at end of file
+#define SYS_fspick 433
+#define SYS_pidfd_open 434
+#define SYS_clone3 435
\ No newline at end of file
diff --git a/lib/libc/include/x86_64-linux-musl/bits/alltypes.h b/lib/libc/include/x86_64-linux-musl/bits/alltypes.h
index ec6a904f5..7418a4823 100644
--- a/lib/libc/include/x86_64-linux-musl/bits/alltypes.h
+++ b/lib/libc/include/x86_64-linux-musl/bits/alltypes.h
@@ -2,16 +2,8 @@
#define _Int64 long
#define _Reg long
-#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
-typedef __builtin_va_list va_list;
-#define __DEFINED_va_list
-#endif
-
-#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
-typedef __builtin_va_list __isoc_va_list;
-#define __DEFINED___isoc_va_list
-#endif
-
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
#if defined(__NEED_wchar_t) && !defined(__DEFINED_wchar_t)
@@ -50,52 +42,9 @@ typedef struct { long long __ll; long double __ld; } max_align_t;
#define __DEFINED_max_align_t
#endif
-
-#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
-typedef long time_t;
-#define __DEFINED_time_t
-#endif
-
-#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
-typedef long suseconds_t;
-#define __DEFINED_suseconds_t
-#endif
-
-
-#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-#define __DEFINED_pthread_attr_t
-#endif
-
-#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-#define __DEFINED_pthread_mutex_t
-#endif
-
-#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
-typedef struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-#define __DEFINED_mtx_t
-#endif
-
-#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-#define __DEFINED_pthread_cond_t
-#endif
-
-#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
-typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-#define __DEFINED_cnd_t
-#endif
-
-#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
-typedef struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-#define __DEFINED_pthread_rwlock_t
-#endif
-
-#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
-typedef struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
-#define __DEFINED_pthread_barrier_t
-#endif
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#define __USE_TIME_BITS64 1
#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)
typedef unsigned _Addr size_t;
@@ -132,6 +81,16 @@ typedef _Reg register_t;
#define __DEFINED_register_t
#endif
+#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
+typedef _Int64 time_t;
+#define __DEFINED_time_t
+#endif
+
+#if defined(__NEED_suseconds_t) && !defined(__DEFINED_suseconds_t)
+typedef _Int64 suseconds_t;
+#define __DEFINED_suseconds_t
+#endif
+
#if defined(__NEED_int8_t) && !defined(__DEFINED_int8_t)
typedef signed char int8_t;
@@ -267,7 +226,7 @@ struct timeval { time_t tv_sec; suseconds_t tv_usec; };
#endif
#if defined(__NEED_struct_timespec) && !defined(__DEFINED_struct_timespec)
-struct timespec { time_t tv_sec; long tv_nsec; };
+struct timespec { time_t tv_sec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER==4321); long tv_nsec; int :8*(sizeof(time_t)-sizeof(long))*(__BYTE_ORDER!=4321); };
#define __DEFINED_struct_timespec
#endif
@@ -363,6 +322,17 @@ typedef struct _IO_FILE FILE;
#endif
+#if defined(__NEED_va_list) && !defined(__DEFINED_va_list)
+typedef __builtin_va_list va_list;
+#define __DEFINED_va_list
+#endif
+
+#if defined(__NEED___isoc_va_list) && !defined(__DEFINED___isoc_va_list)
+typedef __builtin_va_list __isoc_va_list;
+#define __DEFINED___isoc_va_list
+#endif
+
+
#if defined(__NEED_mbstate_t) && !defined(__DEFINED_mbstate_t)
typedef struct __mbstate_t { unsigned __opaque1, __opaque2; } mbstate_t;
#define __DEFINED_mbstate_t
@@ -398,6 +368,42 @@ typedef unsigned short sa_family_t;
#endif
+#if defined(__NEED_pthread_attr_t) && !defined(__DEFINED_pthread_attr_t)
+typedef struct { union { int __i[sizeof(long)==8?14:9]; volatile int __vi[sizeof(long)==8?14:9]; unsigned long __s[sizeof(long)==8?7:9]; } __u; } pthread_attr_t;
+#define __DEFINED_pthread_attr_t
+#endif
+
+#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } pthread_mutex_t;
+#define __DEFINED_pthread_mutex_t
+#endif
+
+#if defined(__NEED_mtx_t) && !defined(__DEFINED_mtx_t)
+typedef struct { union { int __i[sizeof(long)==8?10:6]; volatile int __vi[sizeof(long)==8?10:6]; volatile void *volatile __p[sizeof(long)==8?5:6]; } __u; } mtx_t;
+#define __DEFINED_mtx_t
+#endif
+
+#if defined(__NEED_pthread_cond_t) && !defined(__DEFINED_pthread_cond_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } pthread_cond_t;
+#define __DEFINED_pthread_cond_t
+#endif
+
+#if defined(__NEED_cnd_t) && !defined(__DEFINED_cnd_t)
+typedef struct { union { int __i[12]; volatile int __vi[12]; void *__p[12*sizeof(int)/sizeof(void*)]; } __u; } cnd_t;
+#define __DEFINED_cnd_t
+#endif
+
+#if defined(__NEED_pthread_rwlock_t) && !defined(__DEFINED_pthread_rwlock_t)
+typedef struct { union { int __i[sizeof(long)==8?14:8]; volatile int __vi[sizeof(long)==8?14:8]; void *__p[sizeof(long)==8?7:8]; } __u; } pthread_rwlock_t;
+#define __DEFINED_pthread_rwlock_t
+#endif
+
+#if defined(__NEED_pthread_barrier_t) && !defined(__DEFINED_pthread_barrier_t)
+typedef struct { union { int __i[sizeof(long)==8?8:5]; volatile int __vi[sizeof(long)==8?8:5]; void *__p[sizeof(long)==8?4:5]; } __u; } pthread_barrier_t;
+#define __DEFINED_pthread_barrier_t
+#endif
+
+
#undef _Addr
#undef _Int64
#undef _Reg
\ No newline at end of file
diff --git a/lib/libc/include/x86_64-linux-musl/bits/limits.h b/lib/libc/include/x86_64-linux-musl/bits/limits.h
index e98429585..fc11433d9 100644
--- a/lib/libc/include/x86_64-linux-musl/bits/limits.h
+++ b/lib/libc/include/x86_64-linux-musl/bits/limits.h
@@ -1,8 +1 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define PAGESIZE 4096
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
\ No newline at end of file
+#define PAGESIZE 4096
\ No newline at end of file
diff --git a/lib/libc/include/x86_64-linux-musl/bits/socket.h b/lib/libc/include/x86_64-linux-musl/bits/socket.h
deleted file mode 100644
index 0372d7dd0..000000000
--- a/lib/libc/include/x86_64-linux-musl/bits/socket.h
+++ /dev/null
@@ -1,16 +0,0 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen, __pad1;
- void *msg_control;
- socklen_t msg_controllen, __pad2;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int __pad1;
- int cmsg_level;
- int cmsg_type;
-};
\ No newline at end of file
diff --git a/lib/libc/include/x86_64-linux-musl/bits/syscall.h b/lib/libc/include/x86_64-linux-musl/bits/syscall.h
index fed8f0384..e4dbe4b06 100644
--- a/lib/libc/include/x86_64-linux-musl/bits/syscall.h
+++ b/lib/libc/include/x86_64-linux-musl/bits/syscall.h
@@ -343,6 +343,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define SYS_read 0
#define SYS_write 1
@@ -688,4 +690,6 @@
#define SYS_fsopen 430
#define SYS_fsconfig 431
#define SYS_fsmount 432
-#define SYS_fspick 433
\ No newline at end of file
+#define SYS_fspick 433
+#define SYS_pidfd_open 434
+#define SYS_clone3 435
\ No newline at end of file
From 71d776c3be91f6b4e982b45fbfe03e3696a397f5 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 12 Mar 2020 22:42:01 +0200
Subject: [PATCH 100/111] add note to disabled tests, improve comptime cmpxchg
---
lib/std/atomic/stack.zig | 10 +++++-----
lib/std/event/channel.zig | 9 +++------
src/ir.cpp | 18 +++++++++++-------
test/stage1/behavior/atomics.zig | 6 ++++--
4 files changed, 23 insertions(+), 20 deletions(-)
diff --git a/lib/std/atomic/stack.zig b/lib/std/atomic/stack.zig
index 07cb16e45..092dce15b 100644
--- a/lib/std/atomic/stack.zig
+++ b/lib/std/atomic/stack.zig
@@ -38,8 +38,8 @@ pub fn Stack(comptime T: type) type {
node.next = self.root;
self.root = node;
} else {
- while (@atomicRmw(bool, &self.lock, .Xchg, true, .SeqCst) != false) {}
- defer assert(@atomicRmw(bool, &self.lock, .Xchg, false, .SeqCst) == true);
+ while (@atomicRmw(bool, &self.lock, .Xchg, true, .SeqCst)) {}
+ defer assert(@atomicRmw(bool, &self.lock, .Xchg, false, .SeqCst));
node.next = self.root;
self.root = node;
@@ -52,8 +52,8 @@ pub fn Stack(comptime T: type) type {
self.root = root.next;
return root;
} else {
- while (@atomicRmw(bool, &self.lock, .Xchg, true, .SeqCst) != false) {}
- defer assert(@atomicRmw(bool, &self.lock, .Xchg, false, .SeqCst) == true);
+ while (@atomicRmw(bool, &self.lock, .Xchg, true, .SeqCst)) {}
+ defer assert(@atomicRmw(bool, &self.lock, .Xchg, false, .SeqCst));
const root = self.root orelse return null;
self.root = root.next;
@@ -164,7 +164,7 @@ fn startPuts(ctx: *Context) u8 {
fn startGets(ctx: *Context) u8 {
while (true) {
- const last = @atomicLoad(bool, &ctx.puts_done, .SeqCst) == true;
+ const last = @atomicLoad(bool, &ctx.puts_done, .SeqCst);
while (ctx.stack.pop()) |node| {
std.time.sleep(1); // let the os scheduler be our fuzz
diff --git a/lib/std/event/channel.zig b/lib/std/event/channel.zig
index 355bd7829..83c77bcac 100644
--- a/lib/std/event/channel.zig
+++ b/lib/std/event/channel.zig
@@ -169,8 +169,7 @@ pub fn Channel(comptime T: type) type {
lock: while (true) {
// set the lock flag
- const prev_lock = @atomicRmw(bool, &self.dispatch_lock, .Xchg, true, .SeqCst);
- if (prev_lock != 0) return;
+ if (@atomicRmw(bool, &self.dispatch_lock, .Xchg, true, .SeqCst)) return;
// clear the need_dispatch flag since we're about to do it
@atomicStore(bool, &self.need_dispatch, false, .SeqCst);
@@ -250,11 +249,9 @@ pub fn Channel(comptime T: type) type {
}
// clear need-dispatch flag
- const need_dispatch = @atomicRmw(bool, &self.need_dispatch, .Xchg, false, .SeqCst);
- if (need_dispatch) continue;
+ if (@atomicRmw(bool, &self.need_dispatch, .Xchg, false, .SeqCst)) continue;
- const my_lock = @atomicRmw(bool, &self.dispatch_lock, .Xchg, false, .SeqCst);
- assert(my_lock);
+ assert(@atomicRmw(bool, &self.dispatch_lock, .Xchg, false, .SeqCst));
// we have to check again now that we unlocked
if (@atomicLoad(bool, &self.need_dispatch, .SeqCst)) continue :lock;
diff --git a/src/ir.cpp b/src/ir.cpp
index ede403c72..5facc3eb4 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -25215,21 +25215,25 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
if (ptr_val == nullptr)
return ira->codegen->invalid_inst_gen;
- ZigValue *op1_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.base.source_node);
- if (op1_val == nullptr)
+ ZigValue *stored_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.base.source_node);
+ if (stored_val == nullptr)
return ira->codegen->invalid_inst_gen;
- ZigValue *op2_val = ir_resolve_const(ira, casted_cmp_value, UndefBad);
- if (op2_val == nullptr)
+ ZigValue *expected_val = ir_resolve_const(ira, casted_cmp_value, UndefBad);
+ if (expected_val == nullptr)
return ira->codegen->invalid_inst_gen;
- bool eql = const_values_equal(ira->codegen, op1_val, op2_val);
+ ZigValue *new_val = ir_resolve_const(ira, casted_new_value, UndefBad);
+ if (new_val == nullptr)
+ return ira->codegen->invalid_inst_gen;
+
+ bool eql = const_values_equal(ira->codegen, stored_val, expected_val);
IrInstGen *result = ir_const(ira, &instruction->base.base, result_type);
if (eql) {
- ir_analyze_store_ptr(ira, &instruction->base.base, casted_ptr, casted_new_value, false);
+ copy_const_val(ira->codegen, stored_val, new_val);
set_optional_value_to_null(result->value);
} else {
- set_optional_payload(result->value, op1_val);
+ set_optional_payload(result->value, stored_val);
}
return result;
}
diff --git a/test/stage1/behavior/atomics.zig b/test/stage1/behavior/atomics.zig
index 8870091d7..3e6d0b3d0 100644
--- a/test/stage1/behavior/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -149,6 +149,7 @@ fn testAtomicStore() void {
}
test "atomicrmw with floats" {
+ // TODO https://github.com/ziglang/zig/issues/4457
if (builtin.arch == .aarch64 or builtin.arch == .arm or builtin.arch == .riscv64)
return error.SkipZigTest;
testAtomicRmwFloat();
@@ -167,8 +168,6 @@ fn testAtomicRmwFloat() void {
}
test "atomicrmw with ints" {
- if (builtin.arch == .mipsel)
- return error.SkipZigTest;
testAtomicRmwInt();
comptime testAtomicRmwInt();
}
@@ -189,6 +188,9 @@ fn testAtomicRmwInt() void {
expect(x == 0xff);
_ = @atomicRmw(u8, &x, .Xor, 2, .SeqCst);
expect(x == 0xfd);
+
+ // TODO https://github.com/ziglang/zig/issues/4724
+ if (builtin.arch == .mipsel) return;
_ = @atomicRmw(u8, &x, .Max, 1, .SeqCst);
expect(x == 0xfd);
_ = @atomicRmw(u8, &x, .Min, 1, .SeqCst);
From edd6643a26c1c54160babc9568dec9a8f7ed36d6 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 12 Mar 2020 17:17:57 -0400
Subject: [PATCH 101/111] update musl src files to v1.2.0
---
lib/libc/musl/COPYRIGHT | 4 +-
lib/libc/musl/arch/aarch64/bits/alltypes.h.in | 20 +-
lib/libc/musl/arch/aarch64/bits/endian.h | 5 -
lib/libc/musl/arch/aarch64/bits/limits.h | 7 -
lib/libc/musl/arch/aarch64/bits/socket.h | 33 --
lib/libc/musl/arch/aarch64/bits/syscall.h.in | 2 +
lib/libc/musl/arch/aarch64/reloc.h | 2 -
lib/libc/musl/arch/arm/bits/alltypes.h.in | 21 +-
lib/libc/musl/arch/arm/bits/endian.h | 5 -
lib/libc/musl/arch/arm/bits/ipcstat.h | 2 +-
lib/libc/musl/arch/arm/bits/limits.h | 7 -
lib/libc/musl/arch/arm/bits/msg.h | 15 +-
lib/libc/musl/arch/arm/bits/sem.h | 10 +-
lib/libc/musl/arch/arm/bits/shm.h | 16 +-
lib/libc/musl/arch/arm/bits/stat.h | 6 +-
lib/libc/musl/arch/arm/bits/syscall.h.in | 22 +-
lib/libc/musl/arch/arm/reloc.h | 2 -
lib/libc/musl/arch/arm/syscall_arch.h | 4 +-
lib/libc/musl/arch/generic/bits/dirent.h | 11 +
lib/libc/musl/arch/generic/bits/ioctl.h | 5 +
lib/libc/musl/arch/generic/bits/limits.h | 0
lib/libc/musl/arch/generic/bits/socket.h | 15 -
lib/libc/musl/arch/i386/bits/alltypes.h.in | 21 +-
lib/libc/musl/arch/i386/bits/endian.h | 1 -
lib/libc/musl/arch/i386/bits/ipcstat.h | 2 +-
lib/libc/musl/arch/i386/bits/limits.h | 7 -
lib/libc/musl/arch/i386/bits/msg.h | 15 +-
lib/libc/musl/arch/i386/bits/sem.h | 10 +-
lib/libc/musl/arch/i386/bits/shm.h | 16 +-
lib/libc/musl/arch/i386/bits/stat.h | 6 +-
lib/libc/musl/arch/i386/bits/syscall.h.in | 22 +-
lib/libc/musl/arch/i386/syscall_arch.h | 4 +-
lib/libc/musl/arch/mips/bits/alltypes.h.in | 21 +-
lib/libc/musl/arch/mips/bits/endian.h | 5 -
lib/libc/musl/arch/mips/bits/hwcap.h | 11 +
lib/libc/musl/arch/mips/bits/ioctl.h | 4 +-
lib/libc/musl/arch/mips/bits/ipcstat.h | 2 +-
lib/libc/musl/arch/mips/bits/limits.h | 7 -
lib/libc/musl/arch/mips/bits/msg.h | 27 +-
lib/libc/musl/arch/mips/bits/sem.h | 10 +-
lib/libc/musl/arch/mips/bits/shm.h | 15 +-
lib/libc/musl/arch/mips/bits/signal.h | 8 +-
lib/libc/musl/arch/mips/bits/socket.h | 18 -
lib/libc/musl/arch/mips/bits/stat.h | 12 +-
lib/libc/musl/arch/mips/bits/syscall.h.in | 22 +-
lib/libc/musl/arch/mips/reloc.h | 2 -
lib/libc/musl/arch/mips/syscall_arch.h | 4 +-
lib/libc/musl/arch/mips64/bits/alltypes.h.in | 20 +-
lib/libc/musl/arch/mips64/bits/endian.h | 5 -
lib/libc/musl/arch/mips64/bits/limits.h | 7 -
lib/libc/musl/arch/mips64/bits/socket.h | 34 --
lib/libc/musl/arch/mips64/bits/syscall.h.in | 2 +
lib/libc/musl/arch/mips64/reloc.h | 10 +-
lib/libc/musl/arch/powerpc/bits/alltypes.h.in | 16 +-
lib/libc/musl/arch/powerpc/bits/endian.h | 15 -
lib/libc/musl/arch/powerpc/bits/ioctl.h | 4 +-
lib/libc/musl/arch/powerpc/bits/ipcstat.h | 2 +-
lib/libc/musl/arch/powerpc/bits/limits.h | 7 -
lib/libc/musl/arch/powerpc/bits/msg.h | 15 +-
lib/libc/musl/arch/powerpc/bits/sem.h | 10 +-
lib/libc/musl/arch/powerpc/bits/shm.h | 16 +-
lib/libc/musl/arch/powerpc/bits/signal.h | 2 +-
lib/libc/musl/arch/powerpc/bits/socket.h | 18 -
lib/libc/musl/arch/powerpc/bits/stat.h | 6 +-
lib/libc/musl/arch/powerpc/bits/syscall.h.in | 22 +-
.../musl/arch/powerpc64/bits/alltypes.h.in | 20 +-
lib/libc/musl/arch/powerpc64/bits/endian.h | 5 -
lib/libc/musl/arch/powerpc64/bits/limits.h | 7 -
lib/libc/musl/arch/powerpc64/bits/signal.h | 8 +-
lib/libc/musl/arch/powerpc64/bits/socket.h | 34 --
.../musl/arch/powerpc64/bits/syscall.h.in | 2 +
lib/libc/musl/arch/powerpc64/reloc.h | 2 -
lib/libc/musl/arch/riscv64/atomic_arch.h | 2 +-
lib/libc/musl/arch/riscv64/bits/alltypes.h.in | 15 +-
lib/libc/musl/arch/riscv64/bits/endian.h | 1 -
lib/libc/musl/arch/riscv64/bits/limits.h | 7 -
lib/libc/musl/arch/riscv64/bits/reg.h | 6 -
lib/libc/musl/arch/riscv64/bits/signal.h | 9 +
lib/libc/musl/arch/riscv64/bits/socket.h | 19 -
lib/libc/musl/arch/riscv64/bits/syscall.h.in | 2 +
lib/libc/musl/arch/s390x/bits/alltypes.h.in | 15 +-
lib/libc/musl/arch/s390x/bits/endian.h | 1 -
lib/libc/musl/arch/s390x/bits/limits.h | 7 -
lib/libc/musl/arch/s390x/bits/socket.h | 17 -
lib/libc/musl/arch/s390x/bits/syscall.h.in | 2 +
lib/libc/musl/arch/s390x/reloc.h | 2 -
lib/libc/musl/arch/x86_64/bits/alltypes.h.in | 15 +-
lib/libc/musl/arch/x86_64/bits/endian.h | 1 -
lib/libc/musl/arch/x86_64/bits/limits.h | 7 -
lib/libc/musl/arch/x86_64/bits/socket.h | 16 -
lib/libc/musl/arch/x86_64/bits/syscall.h.in | 2 +
lib/libc/musl/compat/time32/__xstat.c | 24 ++
lib/libc/musl/compat/time32/adjtime32.c | 21 ++
lib/libc/musl/compat/time32/adjtimex_time32.c | 10 +
.../musl/compat/time32/aio_suspend_time32.c | 11 +
lib/libc/musl/compat/time32/clock_adjtime32.c | 70 ++++
.../musl/compat/time32/clock_getres_time32.c | 13 +
lib/libc/musl/compat/time32/clock_gettime32.c | 18 +
.../compat/time32/clock_nanosleep_time32.c | 15 +
lib/libc/musl/compat/time32/clock_settime32.c | 9 +
.../musl/compat/time32/cnd_timedwait_time32.c | 9 +
lib/libc/musl/compat/time32/ctime32.c | 7 +
lib/libc/musl/compat/time32/ctime32_r.c | 7 +
lib/libc/musl/compat/time32/difftime32.c | 7 +
lib/libc/musl/compat/time32/fstat_time32.c | 17 +
lib/libc/musl/compat/time32/fstatat_time32.c | 17 +
lib/libc/musl/compat/time32/ftime32.c | 25 ++
lib/libc/musl/compat/time32/futimens_time32.c | 10 +
lib/libc/musl/compat/time32/futimes_time32.c | 12 +
.../musl/compat/time32/futimesat_time32.c | 12 +
.../musl/compat/time32/getitimer_time32.c | 15 +
.../musl/compat/time32/getrusage_time32.c | 39 ++
.../musl/compat/time32/gettimeofday_time32.c | 19 +
lib/libc/musl/compat/time32/gmtime32.c | 7 +
lib/libc/musl/compat/time32/gmtime32_r.c | 7 +
lib/libc/musl/compat/time32/localtime32.c | 7 +
lib/libc/musl/compat/time32/localtime32_r.c | 7 +
lib/libc/musl/compat/time32/lstat_time32.c | 17 +
lib/libc/musl/compat/time32/lutimes_time32.c | 12 +
lib/libc/musl/compat/time32/mktime32.c | 16 +
.../compat/time32/mq_timedreceive_time32.c | 9 +
.../musl/compat/time32/mq_timedsend_time32.c | 9 +
.../musl/compat/time32/mtx_timedlock_time32.c | 9 +
.../musl/compat/time32/nanosleep_time32.c | 15 +
lib/libc/musl/compat/time32/ppoll_time32.c | 10 +
lib/libc/musl/compat/time32/pselect_time32.c | 9 +
.../time32/pthread_cond_timedwait_time32.c | 9 +
.../time32/pthread_mutex_timedlock_time32.c | 9 +
.../pthread_rwlock_timedrdlock_time32.c | 9 +
.../pthread_rwlock_timedwrlock_time32.c | 9 +
.../time32/pthread_timedjoin_np_time32.c | 10 +
lib/libc/musl/compat/time32/recvmmsg_time32.c | 10 +
.../time32/sched_rr_get_interval_time32.c | 13 +
lib/libc/musl/compat/time32/select_time32.c | 10 +
.../musl/compat/time32/sem_timedwait_time32.c | 9 +
.../musl/compat/time32/semtimedop_time32.c | 10 +
.../musl/compat/time32/setitimer_time32.c | 25 ++
.../musl/compat/time32/settimeofday_time32.c | 10 +
.../musl/compat/time32/sigtimedwait_time32.c | 9 +
lib/libc/musl/compat/time32/stat_time32.c | 17 +
lib/libc/musl/compat/time32/stime32.c | 8 +
.../musl/compat/time32/thrd_sleep_time32.c | 16 +
lib/libc/musl/compat/time32/time32.c | 15 +
lib/libc/musl/compat/time32/time32.h | 91 +++++
lib/libc/musl/compat/time32/time32gm.c | 15 +
lib/libc/musl/compat/time32/timer_gettime32.c | 15 +
lib/libc/musl/compat/time32/timer_settime32.c | 25 ++
.../musl/compat/time32/timerfd_gettime32.c | 16 +
.../musl/compat/time32/timerfd_settime32.c | 26 ++
.../musl/compat/time32/timespec_get_time32.c | 18 +
lib/libc/musl/compat/time32/utime_time32.c | 14 +
.../musl/compat/time32/utimensat_time32.c | 11 +
lib/libc/musl/compat/time32/utimes_time32.c | 11 +
lib/libc/musl/compat/time32/wait3_time32.c | 40 ++
lib/libc/musl/compat/time32/wait4_time32.c | 40 ++
lib/libc/musl/include/aio.h | 4 +
lib/libc/musl/include/alloca.h | 2 -
lib/libc/musl/include/alltypes.h.in | 19 +-
lib/libc/musl/include/arpa/nameser.h | 1 -
lib/libc/musl/include/dirent.h | 14 +-
lib/libc/musl/include/dlfcn.h | 4 +
lib/libc/musl/include/endian.h | 46 ++-
lib/libc/musl/include/features.h | 2 +
lib/libc/musl/include/limits.h | 18 +-
lib/libc/musl/include/mqueue.h | 5 +
lib/libc/musl/include/netinet/icmp6.h | 1 -
lib/libc/musl/include/netinet/if_ether.h | 1 +
lib/libc/musl/include/netinet/ip.h | 3 +-
lib/libc/musl/include/netinet/ip6.h | 1 -
lib/libc/musl/include/netinet/tcp.h | 4 +-
lib/libc/musl/include/poll.h | 6 +
lib/libc/musl/include/pthread.h | 10 +
lib/libc/musl/include/sched.h | 8 +
lib/libc/musl/include/semaphore.h | 4 +
lib/libc/musl/include/signal.h | 8 +
lib/libc/musl/include/sys/acct.h | 1 -
lib/libc/musl/include/sys/ioctl.h | 1 +
lib/libc/musl/include/sys/mman.h | 2 +
lib/libc/musl/include/sys/prctl.h | 4 +
lib/libc/musl/include/sys/procfs.h | 7 +-
lib/libc/musl/include/sys/ptrace.h | 29 ++
lib/libc/musl/include/sys/resource.h | 7 +-
lib/libc/musl/include/sys/select.h | 5 +
lib/libc/musl/include/sys/sem.h | 8 +-
lib/libc/musl/include/sys/socket.h | 69 +++-
lib/libc/musl/include/sys/stat.h | 9 +
lib/libc/musl/include/sys/statvfs.h | 2 -
lib/libc/musl/include/sys/time.h | 14 +
lib/libc/musl/include/sys/timeb.h | 6 +
lib/libc/musl/include/sys/timerfd.h | 5 +
lib/libc/musl/include/sys/timex.h | 5 +
lib/libc/musl/include/sys/ttydefaults.h | 7 +-
lib/libc/musl/include/sys/wait.h | 10 +-
lib/libc/musl/include/threads.h | 6 +
lib/libc/musl/include/time.h | 28 ++
lib/libc/musl/include/utime.h | 6 +
lib/libc/musl/include/utmpx.h | 7 +-
lib/libc/musl/src/aio/aio_suspend.c | 2 +
lib/libc/musl/src/complex/cacosh.c | 5 +-
lib/libc/musl/src/complex/cacoshf.c | 5 +-
lib/libc/musl/src/complex/cacoshl.c | 5 +-
lib/libc/musl/src/complex/catanf.c | 14 +-
lib/libc/musl/src/complex/catanl.c | 14 +-
lib/libc/musl/src/ctype/alpha.h | 159 ++++----
lib/libc/musl/src/ctype/casemap.h | 297 +++++++++++++++
lib/libc/musl/src/ctype/nonspacing.h | 90 ++---
lib/libc/musl/src/ctype/punct.h | 162 ++++----
lib/libc/musl/src/ctype/towctrans.c | 348 +++---------------
lib/libc/musl/src/ctype/wcwidth.c | 2 +-
lib/libc/musl/src/ctype/wide.h | 26 +-
lib/libc/musl/src/fenv/riscv64/fenv.S | 5 +-
lib/libc/musl/src/internal/dynlink.h | 1 -
lib/libc/musl/src/internal/floatscan.c | 5 +-
lib/libc/musl/src/internal/syscall.h | 46 +++
lib/libc/musl/src/internal/version.h | 2 +-
lib/libc/musl/src/ldso/__dlsym.c | 4 +
lib/libc/musl/src/ldso/arm/dlsym_time64.S | 3 +
lib/libc/musl/src/ldso/i386/dlsym_time64.S | 3 +
lib/libc/musl/src/ldso/m68k/dlsym_time64.S | 3 +
.../musl/src/ldso/microblaze/dlsym_time64.S | 3 +
lib/libc/musl/src/ldso/mips/dlsym_time64.S | 3 +
lib/libc/musl/src/ldso/mipsn32/dlsym_time64.S | 3 +
lib/libc/musl/src/ldso/or1k/dlsym_time64.S | 3 +
lib/libc/musl/src/ldso/powerpc/dlsym_time64.S | 3 +
lib/libc/musl/src/ldso/sh/dlsym_time64.S | 3 +
lib/libc/musl/src/linux/clock_adjtime.c | 57 ++-
lib/libc/musl/src/linux/wait4.c | 34 +-
lib/libc/musl/src/math/i386/acos.s | 16 +-
lib/libc/musl/src/math/i386/acosf.s | 17 +-
lib/libc/musl/src/math/i386/acosl.s | 15 +-
lib/libc/musl/src/math/i386/asin.s | 32 +-
lib/libc/musl/src/math/i386/asinf.s | 24 +-
lib/libc/musl/src/math/i386/asinl.s | 13 +-
lib/libc/musl/src/math/i386/atan.s | 2 +
lib/libc/musl/src/math/i386/atan2.s | 3 +-
lib/libc/musl/src/math/i386/atan2f.s | 3 +-
lib/libc/musl/src/math/i386/atanf.s | 2 +
lib/libc/musl/src/math/i386/exp2.s | 1 -
lib/libc/musl/src/math/i386/exp2f.s | 1 -
lib/libc/musl/src/math/i386/exp2l.s | 2 +-
.../musl/src/math/i386/{exp.s => exp_ld.s} | 55 +--
lib/libc/musl/src/math/i386/expf.s | 1 -
lib/libc/musl/src/math/i386/expm1.s | 1 -
lib/libc/musl/src/math/i386/expm1f.s | 1 -
lib/libc/musl/src/math/i386/expm1l.s | 2 +-
lib/libc/musl/src/math/i386/log.s | 2 +
lib/libc/musl/src/math/i386/log10.s | 2 +
lib/libc/musl/src/math/i386/log10f.s | 2 +
lib/libc/musl/src/math/i386/log1p.s | 4 +
lib/libc/musl/src/math/i386/log1pf.s | 4 +
lib/libc/musl/src/math/i386/log2.s | 2 +
lib/libc/musl/src/math/i386/log2f.s | 2 +
lib/libc/musl/src/math/i386/logf.s | 2 +
lib/libc/musl/src/math/mips/fabs.c | 16 +
lib/libc/musl/src/math/mips/fabsf.c | 16 +
lib/libc/musl/src/math/mips/sqrt.c | 16 +
lib/libc/musl/src/math/mips/sqrtf.c | 16 +
lib/libc/musl/src/math/powerpc/fabs.c | 2 +-
lib/libc/musl/src/math/powerpc/fma.c | 2 +-
lib/libc/musl/src/math/x32/lrintl.s | 4 +-
lib/libc/musl/src/misc/getrusage.c | 30 +-
lib/libc/musl/src/misc/ioctl.c | 136 ++++++-
lib/libc/musl/src/misc/pty.c | 4 +-
lib/libc/musl/src/network/getsockopt.c | 9 +
lib/libc/musl/src/network/recvmmsg.c | 14 +-
lib/libc/musl/src/network/recvmsg.c | 47 +++
lib/libc/musl/src/network/setsockopt.c | 9 +
lib/libc/musl/src/signal/arm/sigsetjmp.s | 5 +-
lib/libc/musl/src/stat/__xstat.c | 4 +
lib/libc/musl/src/stat/fchmodat.c | 3 +-
lib/libc/musl/src/stat/fstat.c | 2 +
lib/libc/musl/src/stat/fstatat.c | 18 +
lib/libc/musl/src/stat/lstat.c | 2 +
lib/libc/musl/src/stat/stat.c | 2 +
lib/libc/musl/src/stdio/tempnam.c | 5 +-
lib/libc/musl/src/stdio/tmpnam.c | 5 +-
lib/libc/musl/src/stdio/ungetc.c | 2 +-
lib/libc/musl/src/string/arm/memcpy.c | 2 +-
lib/libc/musl/src/string/arm/memcpy_le.S | 13 +-
lib/libc/musl/src/time/__map_file.c | 3 +-
280 files changed, 2888 insertions(+), 1381 deletions(-)
delete mode 100644 lib/libc/musl/arch/aarch64/bits/endian.h
delete mode 100644 lib/libc/musl/arch/aarch64/bits/limits.h
delete mode 100644 lib/libc/musl/arch/aarch64/bits/socket.h
delete mode 100644 lib/libc/musl/arch/arm/bits/endian.h
delete mode 100644 lib/libc/musl/arch/arm/bits/limits.h
create mode 100644 lib/libc/musl/arch/generic/bits/dirent.h
create mode 100644 lib/libc/musl/arch/generic/bits/limits.h
delete mode 100644 lib/libc/musl/arch/i386/bits/endian.h
delete mode 100644 lib/libc/musl/arch/mips/bits/endian.h
delete mode 100644 lib/libc/musl/arch/mips/bits/limits.h
delete mode 100644 lib/libc/musl/arch/mips64/bits/endian.h
delete mode 100644 lib/libc/musl/arch/mips64/bits/limits.h
delete mode 100644 lib/libc/musl/arch/powerpc/bits/endian.h
delete mode 100644 lib/libc/musl/arch/powerpc/bits/limits.h
delete mode 100644 lib/libc/musl/arch/powerpc64/bits/endian.h
delete mode 100644 lib/libc/musl/arch/powerpc64/bits/limits.h
delete mode 100644 lib/libc/musl/arch/riscv64/bits/endian.h
delete mode 100644 lib/libc/musl/arch/riscv64/bits/limits.h
delete mode 100644 lib/libc/musl/arch/riscv64/bits/socket.h
delete mode 100644 lib/libc/musl/arch/s390x/bits/endian.h
delete mode 100644 lib/libc/musl/arch/s390x/bits/socket.h
delete mode 100644 lib/libc/musl/arch/x86_64/bits/endian.h
delete mode 100644 lib/libc/musl/arch/x86_64/bits/socket.h
create mode 100644 lib/libc/musl/compat/time32/__xstat.c
create mode 100644 lib/libc/musl/compat/time32/adjtime32.c
create mode 100644 lib/libc/musl/compat/time32/adjtimex_time32.c
create mode 100644 lib/libc/musl/compat/time32/aio_suspend_time32.c
create mode 100644 lib/libc/musl/compat/time32/clock_adjtime32.c
create mode 100644 lib/libc/musl/compat/time32/clock_getres_time32.c
create mode 100644 lib/libc/musl/compat/time32/clock_gettime32.c
create mode 100644 lib/libc/musl/compat/time32/clock_nanosleep_time32.c
create mode 100644 lib/libc/musl/compat/time32/clock_settime32.c
create mode 100644 lib/libc/musl/compat/time32/cnd_timedwait_time32.c
create mode 100644 lib/libc/musl/compat/time32/ctime32.c
create mode 100644 lib/libc/musl/compat/time32/ctime32_r.c
create mode 100644 lib/libc/musl/compat/time32/difftime32.c
create mode 100644 lib/libc/musl/compat/time32/fstat_time32.c
create mode 100644 lib/libc/musl/compat/time32/fstatat_time32.c
create mode 100644 lib/libc/musl/compat/time32/ftime32.c
create mode 100644 lib/libc/musl/compat/time32/futimens_time32.c
create mode 100644 lib/libc/musl/compat/time32/futimes_time32.c
create mode 100644 lib/libc/musl/compat/time32/futimesat_time32.c
create mode 100644 lib/libc/musl/compat/time32/getitimer_time32.c
create mode 100644 lib/libc/musl/compat/time32/getrusage_time32.c
create mode 100644 lib/libc/musl/compat/time32/gettimeofday_time32.c
create mode 100644 lib/libc/musl/compat/time32/gmtime32.c
create mode 100644 lib/libc/musl/compat/time32/gmtime32_r.c
create mode 100644 lib/libc/musl/compat/time32/localtime32.c
create mode 100644 lib/libc/musl/compat/time32/localtime32_r.c
create mode 100644 lib/libc/musl/compat/time32/lstat_time32.c
create mode 100644 lib/libc/musl/compat/time32/lutimes_time32.c
create mode 100644 lib/libc/musl/compat/time32/mktime32.c
create mode 100644 lib/libc/musl/compat/time32/mq_timedreceive_time32.c
create mode 100644 lib/libc/musl/compat/time32/mq_timedsend_time32.c
create mode 100644 lib/libc/musl/compat/time32/mtx_timedlock_time32.c
create mode 100644 lib/libc/musl/compat/time32/nanosleep_time32.c
create mode 100644 lib/libc/musl/compat/time32/ppoll_time32.c
create mode 100644 lib/libc/musl/compat/time32/pselect_time32.c
create mode 100644 lib/libc/musl/compat/time32/pthread_cond_timedwait_time32.c
create mode 100644 lib/libc/musl/compat/time32/pthread_mutex_timedlock_time32.c
create mode 100644 lib/libc/musl/compat/time32/pthread_rwlock_timedrdlock_time32.c
create mode 100644 lib/libc/musl/compat/time32/pthread_rwlock_timedwrlock_time32.c
create mode 100644 lib/libc/musl/compat/time32/pthread_timedjoin_np_time32.c
create mode 100644 lib/libc/musl/compat/time32/recvmmsg_time32.c
create mode 100644 lib/libc/musl/compat/time32/sched_rr_get_interval_time32.c
create mode 100644 lib/libc/musl/compat/time32/select_time32.c
create mode 100644 lib/libc/musl/compat/time32/sem_timedwait_time32.c
create mode 100644 lib/libc/musl/compat/time32/semtimedop_time32.c
create mode 100644 lib/libc/musl/compat/time32/setitimer_time32.c
create mode 100644 lib/libc/musl/compat/time32/settimeofday_time32.c
create mode 100644 lib/libc/musl/compat/time32/sigtimedwait_time32.c
create mode 100644 lib/libc/musl/compat/time32/stat_time32.c
create mode 100644 lib/libc/musl/compat/time32/stime32.c
create mode 100644 lib/libc/musl/compat/time32/thrd_sleep_time32.c
create mode 100644 lib/libc/musl/compat/time32/time32.c
create mode 100644 lib/libc/musl/compat/time32/time32.h
create mode 100644 lib/libc/musl/compat/time32/time32gm.c
create mode 100644 lib/libc/musl/compat/time32/timer_gettime32.c
create mode 100644 lib/libc/musl/compat/time32/timer_settime32.c
create mode 100644 lib/libc/musl/compat/time32/timerfd_gettime32.c
create mode 100644 lib/libc/musl/compat/time32/timerfd_settime32.c
create mode 100644 lib/libc/musl/compat/time32/timespec_get_time32.c
create mode 100644 lib/libc/musl/compat/time32/utime_time32.c
create mode 100644 lib/libc/musl/compat/time32/utimensat_time32.c
create mode 100644 lib/libc/musl/compat/time32/utimes_time32.c
create mode 100644 lib/libc/musl/compat/time32/wait3_time32.c
create mode 100644 lib/libc/musl/compat/time32/wait4_time32.c
create mode 100644 lib/libc/musl/src/ctype/casemap.h
create mode 100644 lib/libc/musl/src/ldso/arm/dlsym_time64.S
create mode 100644 lib/libc/musl/src/ldso/i386/dlsym_time64.S
create mode 100644 lib/libc/musl/src/ldso/m68k/dlsym_time64.S
create mode 100644 lib/libc/musl/src/ldso/microblaze/dlsym_time64.S
create mode 100644 lib/libc/musl/src/ldso/mips/dlsym_time64.S
create mode 100644 lib/libc/musl/src/ldso/mipsn32/dlsym_time64.S
create mode 100644 lib/libc/musl/src/ldso/or1k/dlsym_time64.S
create mode 100644 lib/libc/musl/src/ldso/powerpc/dlsym_time64.S
create mode 100644 lib/libc/musl/src/ldso/sh/dlsym_time64.S
delete mode 100644 lib/libc/musl/src/math/i386/exp2.s
delete mode 100644 lib/libc/musl/src/math/i386/exp2f.s
rename lib/libc/musl/src/math/i386/{exp.s => exp_ld.s} (67%)
delete mode 100644 lib/libc/musl/src/math/i386/expf.s
delete mode 100644 lib/libc/musl/src/math/i386/expm1.s
delete mode 100644 lib/libc/musl/src/math/i386/expm1f.s
create mode 100644 lib/libc/musl/src/math/mips/fabs.c
create mode 100644 lib/libc/musl/src/math/mips/fabsf.c
create mode 100644 lib/libc/musl/src/math/mips/sqrt.c
create mode 100644 lib/libc/musl/src/math/mips/sqrtf.c
diff --git a/lib/libc/musl/COPYRIGHT b/lib/libc/musl/COPYRIGHT
index 67802d119..e64723714 100644
--- a/lib/libc/musl/COPYRIGHT
+++ b/lib/libc/musl/COPYRIGHT
@@ -1,7 +1,7 @@
musl as a whole is licensed under the following standard MIT license:
----------------------------------------------------------------------
-Copyright © 2005-2019 Rich Felker, et al.
+Copyright © 2005-2020 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -26,6 +26,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Authors/contributors include:
A. Wilcox
+Ada Worcester
Alex Dowad
Alex Suykov
Alexander Monakov
@@ -65,7 +66,6 @@ Jeremy Huntwork
Jo-Philipp Wich
Joakim Sindholt
John Spencer
-Josiah Worcester
Julien Ramseier
Justin Cormack
Kaarle Ritvanen
diff --git a/lib/libc/musl/arch/aarch64/bits/alltypes.h.in b/lib/libc/musl/arch/aarch64/bits/alltypes.h.in
index d56abdac9..c547ca0b7 100644
--- a/lib/libc/musl/arch/aarch64/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/aarch64/bits/alltypes.h.in
@@ -2,8 +2,13 @@
#define _Int64 long
#define _Reg long
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#if __AARCH64EB__
+#define __BYTE_ORDER 4321
+#else
+#define __BYTE_ORDER 1234
+#endif
+
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
TYPEDEF unsigned wchar_t;
@@ -17,14 +22,3 @@ TYPEDEF float float_t;
TYPEDEF double double_t;
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/aarch64/bits/endian.h b/lib/libc/musl/arch/aarch64/bits/endian.h
deleted file mode 100644
index 7a74d2feb..000000000
--- a/lib/libc/musl/arch/aarch64/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if __AARCH64EB__
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
diff --git a/lib/libc/musl/arch/aarch64/bits/limits.h b/lib/libc/musl/arch/aarch64/bits/limits.h
deleted file mode 100644
index 0226588c3..000000000
--- a/lib/libc/musl/arch/aarch64/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/aarch64/bits/socket.h b/lib/libc/musl/arch/aarch64/bits/socket.h
deleted file mode 100644
index c11677e9d..000000000
--- a/lib/libc/musl/arch/aarch64/bits/socket.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#include
-
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1, msg_iovlen;
-#else
- int msg_iovlen, __pad1;
-#endif
- void *msg_control;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad2;
- socklen_t msg_controllen;
-#else
- socklen_t msg_controllen;
- int __pad2;
-#endif
- int msg_flags;
-};
-
-struct cmsghdr {
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1;
- socklen_t cmsg_len;
-#else
- socklen_t cmsg_len;
- int __pad1;
-#endif
- int cmsg_level;
- int cmsg_type;
-};
diff --git a/lib/libc/musl/arch/aarch64/bits/syscall.h.in b/lib/libc/musl/arch/aarch64/bits/syscall.h.in
index 955e2caba..93648afdf 100644
--- a/lib/libc/musl/arch/aarch64/bits/syscall.h.in
+++ b/lib/libc/musl/arch/aarch64/bits/syscall.h.in
@@ -287,4 +287,6 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
diff --git a/lib/libc/musl/arch/aarch64/reloc.h b/lib/libc/musl/arch/aarch64/reloc.h
index 40cf0b289..b1b68c725 100644
--- a/lib/libc/musl/arch/aarch64/reloc.h
+++ b/lib/libc/musl/arch/aarch64/reloc.h
@@ -1,5 +1,3 @@
-#include
-
#if __BYTE_ORDER == __BIG_ENDIAN
#define ENDIAN_SUFFIX "_be"
#else
diff --git a/lib/libc/musl/arch/arm/bits/alltypes.h.in b/lib/libc/musl/arch/arm/bits/alltypes.h.in
index 667963c7e..d62bd7bde 100644
--- a/lib/libc/musl/arch/arm/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/arm/bits/alltypes.h.in
@@ -1,9 +1,15 @@
+#define _REDIR_TIME64 1
#define _Addr int
#define _Int64 long long
#define _Reg int
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#if __ARMEB__
+#define __BYTE_ORDER 4321
+#else
+#define __BYTE_ORDER 1234
+#endif
+
+#define __LONG_MAX 0x7fffffffL
#ifndef __cplusplus
TYPEDEF unsigned wchar_t;
@@ -13,14 +19,3 @@ TYPEDEF float float_t;
TYPEDEF double double_t;
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/arm/bits/endian.h b/lib/libc/musl/arch/arm/bits/endian.h
deleted file mode 100644
index 5953724a0..000000000
--- a/lib/libc/musl/arch/arm/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if __ARMEB__
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
diff --git a/lib/libc/musl/arch/arm/bits/ipcstat.h b/lib/libc/musl/arch/arm/bits/ipcstat.h
index 0018ad1e2..4f4fcb0c5 100644
--- a/lib/libc/musl/arch/arm/bits/ipcstat.h
+++ b/lib/libc/musl/arch/arm/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/lib/libc/musl/arch/arm/bits/limits.h b/lib/libc/musl/arch/arm/bits/limits.h
deleted file mode 100644
index fbc6d238d..000000000
--- a/lib/libc/musl/arch/arm/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 32
-#endif
-
-#define LONG_MAX 0x7fffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/arm/bits/msg.h b/lib/libc/musl/arch/arm/bits/msg.h
index bc8436c4a..7bbbb2bf4 100644
--- a/lib/libc/musl/arch/arm/bits/msg.h
+++ b/lib/libc/musl/arch/arm/bits/msg.h
@@ -1,15 +1,18 @@
struct msqid_ds {
struct ipc_perm msg_perm;
- time_t msg_stime;
- int __unused1;
- time_t msg_rtime;
- int __unused2;
- time_t msg_ctime;
- int __unused3;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_ctime_lo;
+ unsigned long __msg_ctime_hi;
unsigned long msg_cbytes;
msgqnum_t msg_qnum;
msglen_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
unsigned long __unused[2];
+ time_t msg_stime;
+ time_t msg_rtime;
+ time_t msg_ctime;
};
diff --git a/lib/libc/musl/arch/arm/bits/sem.h b/lib/libc/musl/arch/arm/bits/sem.h
index d383d4ea5..544e3d2a5 100644
--- a/lib/libc/musl/arch/arm/bits/sem.h
+++ b/lib/libc/musl/arch/arm/bits/sem.h
@@ -1,9 +1,9 @@
struct semid_ds {
struct ipc_perm sem_perm;
- time_t sem_otime;
- long __unused1;
- time_t sem_ctime;
- long __unused2;
+ unsigned long __sem_otime_lo;
+ unsigned long __sem_otime_hi;
+ unsigned long __sem_ctime_lo;
+ unsigned long __sem_ctime_hi;
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned short sem_nsems;
char __sem_nsems_pad[sizeof(long)-sizeof(short)];
@@ -13,4 +13,6 @@ struct semid_ds {
#endif
long __unused3;
long __unused4;
+ time_t sem_otime;
+ time_t sem_ctime;
};
diff --git a/lib/libc/musl/arch/arm/bits/shm.h b/lib/libc/musl/arch/arm/bits/shm.h
index 81b2a29ab..725fb4696 100644
--- a/lib/libc/musl/arch/arm/bits/shm.h
+++ b/lib/libc/musl/arch/arm/bits/shm.h
@@ -3,17 +3,21 @@
struct shmid_ds {
struct ipc_perm shm_perm;
size_t shm_segsz;
- time_t shm_atime;
- int __unused1;
- time_t shm_dtime;
- int __unused2;
- time_t shm_ctime;
- int __unused3;
+ unsigned long __shm_atime_lo;
+ unsigned long __shm_atime_hi;
+ unsigned long __shm_dtime_lo;
+ unsigned long __shm_dtime_hi;
+ unsigned long __shm_ctime_lo;
+ unsigned long __shm_ctime_hi;
pid_t shm_cpid;
pid_t shm_lpid;
unsigned long shm_nattch;
unsigned long __pad1;
unsigned long __pad2;
+ unsigned long __pad3;
+ time_t shm_atime;
+ time_t shm_dtime;
+ time_t shm_ctime;
};
struct shminfo {
diff --git a/lib/libc/musl/arch/arm/bits/stat.h b/lib/libc/musl/arch/arm/bits/stat.h
index 22b19bbfe..5d7828cf7 100644
--- a/lib/libc/musl/arch/arm/bits/stat.h
+++ b/lib/libc/musl/arch/arm/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
+ struct {
+ long tv_sec;
+ long tv_nsec;
+ } __st_atim32, __st_mtim32, __st_ctim32;
+ ino_t st_ino;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
- ino_t st_ino;
};
diff --git a/lib/libc/musl/arch/arm/bits/syscall.h.in b/lib/libc/musl/arch/arm/bits/syscall.h.in
index a565a4ee1..11d677635 100644
--- a/lib/libc/musl/arch/arm/bits/syscall.h.in
+++ b/lib/libc/musl/arch/arm/bits/syscall.h.in
@@ -55,8 +55,8 @@
#define __NR_sethostname 74
#define __NR_setrlimit 75
#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
+#define __NR_gettimeofday_time32 78
+#define __NR_settimeofday_time32 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_symlink 83
@@ -211,14 +211,14 @@
#define __NR_remap_file_pages 253
#define __NR_set_tid_address 256
#define __NR_timer_create 257
-#define __NR_timer_settime 258
-#define __NR_timer_gettime 259
+#define __NR_timer_settime32 258
+#define __NR_timer_gettime32 259
#define __NR_timer_getoverrun 260
#define __NR_timer_delete 261
-#define __NR_clock_settime 262
-#define __NR_clock_gettime 263
-#define __NR_clock_getres 264
-#define __NR_clock_nanosleep 265
+#define __NR_clock_settime32 262
+#define __NR_clock_gettime32 263
+#define __NR_clock_getres_time32 264
+#define __NR_clock_nanosleep_time32 265
#define __NR_statfs64 266
#define __NR_fstatfs64 267
#define __NR_tgkill 268
@@ -308,8 +308,8 @@
#define __NR_timerfd_create 350
#define __NR_eventfd 351
#define __NR_fallocate 352
-#define __NR_timerfd_settime 353
-#define __NR_timerfd_gettime 354
+#define __NR_timerfd_settime32 353
+#define __NR_timerfd_gettime32 354
#define __NR_signalfd4 355
#define __NR_eventfd2 356
#define __NR_epoll_create1 357
@@ -387,6 +387,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define __ARM_NR_breakpoint 0x0f0001
#define __ARM_NR_cacheflush 0x0f0002
diff --git a/lib/libc/musl/arch/arm/reloc.h b/lib/libc/musl/arch/arm/reloc.h
index 2c2e7f58f..d091d2ad9 100644
--- a/lib/libc/musl/arch/arm/reloc.h
+++ b/lib/libc/musl/arch/arm/reloc.h
@@ -1,5 +1,3 @@
-#include
-
#if __BYTE_ORDER == __BIG_ENDIAN
#define ENDIAN_SUFFIX "eb"
#else
diff --git a/lib/libc/musl/arch/arm/syscall_arch.h b/lib/libc/musl/arch/arm/syscall_arch.h
index 53fb155c0..4b08762d7 100644
--- a/lib/libc/musl/arch/arm/syscall_arch.h
+++ b/lib/libc/musl/arch/arm/syscall_arch.h
@@ -99,7 +99,9 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo
}
#define VDSO_USEFUL
-#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
#define VDSO_CGT_VER "LINUX_2.6"
#define SYSCALL_FADVISE_6_ARG
diff --git a/lib/libc/musl/arch/generic/bits/dirent.h b/lib/libc/musl/arch/generic/bits/dirent.h
new file mode 100644
index 000000000..c845fe82d
--- /dev/null
+++ b/lib/libc/musl/arch/generic/bits/dirent.h
@@ -0,0 +1,11 @@
+#define _DIRENT_HAVE_D_RECLEN
+#define _DIRENT_HAVE_D_OFF
+#define _DIRENT_HAVE_D_TYPE
+
+struct dirent {
+ ino_t d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[256];
+};
diff --git a/lib/libc/musl/arch/generic/bits/ioctl.h b/lib/libc/musl/arch/generic/bits/ioctl.h
index d1a6c035f..60ae8b850 100644
--- a/lib/libc/musl/arch/generic/bits/ioctl.h
+++ b/lib/libc/musl/arch/generic/bits/ioctl.h
@@ -104,7 +104,12 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
+#if __LONG_MAX == 0x7fffffff
+#define SIOCGSTAMP _IOR(0x89, 6, char[16])
+#define SIOCGSTAMPNS _IOR(0x89, 7, char[16])
+#else
#define SIOCGSTAMP 0x8906
#define SIOCGSTAMPNS 0x8907
+#endif
#include
diff --git a/lib/libc/musl/arch/generic/bits/limits.h b/lib/libc/musl/arch/generic/bits/limits.h
new file mode 100644
index 000000000..e69de29bb
diff --git a/lib/libc/musl/arch/generic/bits/socket.h b/lib/libc/musl/arch/generic/bits/socket.h
index 1f73b995c..e69de29bb 100644
--- a/lib/libc/musl/arch/generic/bits/socket.h
+++ b/lib/libc/musl/arch/generic/bits/socket.h
@@ -1,15 +0,0 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen;
- void *msg_control;
- socklen_t msg_controllen;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
diff --git a/lib/libc/musl/arch/i386/bits/alltypes.h.in b/lib/libc/musl/arch/i386/bits/alltypes.h.in
index 1a8432d3e..6feb03a6c 100644
--- a/lib/libc/musl/arch/i386/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/i386/bits/alltypes.h.in
@@ -1,14 +1,10 @@
+#define _REDIR_TIME64 1
#define _Addr int
#define _Int64 long long
#define _Reg int
-#if __GNUC__ >= 3
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
-#else
-TYPEDEF struct __va_list * va_list;
-TYPEDEF struct __va_list * __isoc_va_list;
-#endif
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffL
#ifndef __cplusplus
#ifdef __WCHAR_TYPE__
@@ -33,14 +29,3 @@ TYPEDEF struct { __attribute__((__aligned__(8))) long long __ll; long double __l
#else
TYPEDEF struct { alignas(8) long long __ll; long double __ld; } max_align_t;
#endif
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/i386/bits/endian.h b/lib/libc/musl/arch/i386/bits/endian.h
deleted file mode 100644
index 172c338f5..000000000
--- a/lib/libc/musl/arch/i386/bits/endian.h
+++ /dev/null
@@ -1 +0,0 @@
-#define __BYTE_ORDER __LITTLE_ENDIAN
diff --git a/lib/libc/musl/arch/i386/bits/ipcstat.h b/lib/libc/musl/arch/i386/bits/ipcstat.h
index 0018ad1e2..4f4fcb0c5 100644
--- a/lib/libc/musl/arch/i386/bits/ipcstat.h
+++ b/lib/libc/musl/arch/i386/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/lib/libc/musl/arch/i386/bits/limits.h b/lib/libc/musl/arch/i386/bits/limits.h
index c340ceb22..07743b6fd 100644
--- a/lib/libc/musl/arch/i386/bits/limits.h
+++ b/lib/libc/musl/arch/i386/bits/limits.h
@@ -1,8 +1 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define PAGESIZE 4096
-#define LONG_BIT 32
-#endif
-
-#define LONG_MAX 0x7fffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/i386/bits/msg.h b/lib/libc/musl/arch/i386/bits/msg.h
index bc8436c4a..7bbbb2bf4 100644
--- a/lib/libc/musl/arch/i386/bits/msg.h
+++ b/lib/libc/musl/arch/i386/bits/msg.h
@@ -1,15 +1,18 @@
struct msqid_ds {
struct ipc_perm msg_perm;
- time_t msg_stime;
- int __unused1;
- time_t msg_rtime;
- int __unused2;
- time_t msg_ctime;
- int __unused3;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_ctime_lo;
+ unsigned long __msg_ctime_hi;
unsigned long msg_cbytes;
msgqnum_t msg_qnum;
msglen_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
unsigned long __unused[2];
+ time_t msg_stime;
+ time_t msg_rtime;
+ time_t msg_ctime;
};
diff --git a/lib/libc/musl/arch/i386/bits/sem.h b/lib/libc/musl/arch/i386/bits/sem.h
index e61571c12..65661542a 100644
--- a/lib/libc/musl/arch/i386/bits/sem.h
+++ b/lib/libc/musl/arch/i386/bits/sem.h
@@ -1,11 +1,13 @@
struct semid_ds {
struct ipc_perm sem_perm;
- time_t sem_otime;
- long __unused1;
- time_t sem_ctime;
- long __unused2;
+ unsigned long __sem_otime_lo;
+ unsigned long __sem_otime_hi;
+ unsigned long __sem_ctime_lo;
+ unsigned long __sem_ctime_hi;
unsigned short sem_nsems;
char __sem_nsems_pad[sizeof(long)-sizeof(short)];
long __unused3;
long __unused4;
+ time_t sem_otime;
+ time_t sem_ctime;
};
diff --git a/lib/libc/musl/arch/i386/bits/shm.h b/lib/libc/musl/arch/i386/bits/shm.h
index 81b2a29ab..725fb4696 100644
--- a/lib/libc/musl/arch/i386/bits/shm.h
+++ b/lib/libc/musl/arch/i386/bits/shm.h
@@ -3,17 +3,21 @@
struct shmid_ds {
struct ipc_perm shm_perm;
size_t shm_segsz;
- time_t shm_atime;
- int __unused1;
- time_t shm_dtime;
- int __unused2;
- time_t shm_ctime;
- int __unused3;
+ unsigned long __shm_atime_lo;
+ unsigned long __shm_atime_hi;
+ unsigned long __shm_dtime_lo;
+ unsigned long __shm_dtime_hi;
+ unsigned long __shm_ctime_lo;
+ unsigned long __shm_ctime_hi;
pid_t shm_cpid;
pid_t shm_lpid;
unsigned long shm_nattch;
unsigned long __pad1;
unsigned long __pad2;
+ unsigned long __pad3;
+ time_t shm_atime;
+ time_t shm_dtime;
+ time_t shm_ctime;
};
struct shminfo {
diff --git a/lib/libc/musl/arch/i386/bits/stat.h b/lib/libc/musl/arch/i386/bits/stat.h
index 22b19bbfe..5d7828cf7 100644
--- a/lib/libc/musl/arch/i386/bits/stat.h
+++ b/lib/libc/musl/arch/i386/bits/stat.h
@@ -14,8 +14,12 @@ struct stat {
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
+ struct {
+ long tv_sec;
+ long tv_nsec;
+ } __st_atim32, __st_mtim32, __st_ctim32;
+ ino_t st_ino;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
- ino_t st_ino;
};
diff --git a/lib/libc/musl/arch/i386/bits/syscall.h.in b/lib/libc/musl/arch/i386/bits/syscall.h.in
index c95e108e5..1ae4e48a8 100644
--- a/lib/libc/musl/arch/i386/bits/syscall.h.in
+++ b/lib/libc/musl/arch/i386/bits/syscall.h.in
@@ -76,8 +76,8 @@
#define __NR_setrlimit 75
#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
+#define __NR_gettimeofday_time32 78
+#define __NR_settimeofday_time32 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_select 82
@@ -257,14 +257,14 @@
#define __NR_remap_file_pages 257
#define __NR_set_tid_address 258
#define __NR_timer_create 259
-#define __NR_timer_settime (__NR_timer_create+1)
-#define __NR_timer_gettime (__NR_timer_create+2)
+#define __NR_timer_settime32 (__NR_timer_create+1)
+#define __NR_timer_gettime32 (__NR_timer_create+2)
#define __NR_timer_getoverrun (__NR_timer_create+3)
#define __NR_timer_delete (__NR_timer_create+4)
-#define __NR_clock_settime (__NR_timer_create+5)
-#define __NR_clock_gettime (__NR_timer_create+6)
-#define __NR_clock_getres (__NR_timer_create+7)
-#define __NR_clock_nanosleep (__NR_timer_create+8)
+#define __NR_clock_settime32 (__NR_timer_create+5)
+#define __NR_clock_gettime32 (__NR_timer_create+6)
+#define __NR_clock_getres_time32 (__NR_timer_create+7)
+#define __NR_clock_nanosleep_time32 (__NR_timer_create+8)
#define __NR_statfs64 268
#define __NR_fstatfs64 269
#define __NR_tgkill 270
@@ -322,8 +322,8 @@
#define __NR_timerfd_create 322
#define __NR_eventfd 323
#define __NR_fallocate 324
-#define __NR_timerfd_settime 325
-#define __NR_timerfd_gettime 326
+#define __NR_timerfd_settime32 325
+#define __NR_timerfd_gettime32 326
#define __NR_signalfd4 327
#define __NR_eventfd2 328
#define __NR_epoll_create1 329
@@ -424,4 +424,6 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
diff --git a/lib/libc/musl/arch/i386/syscall_arch.h b/lib/libc/musl/arch/i386/syscall_arch.h
index 22b0b28b8..69642e578 100644
--- a/lib/libc/musl/arch/i386/syscall_arch.h
+++ b/lib/libc/musl/arch/i386/syscall_arch.h
@@ -83,7 +83,9 @@ static inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a
}
#define VDSO_USEFUL
-#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
#define VDSO_CGT_VER "LINUX_2.6"
#define SYSCALL_USE_SOCKETCALL
diff --git a/lib/libc/musl/arch/mips/bits/alltypes.h.in b/lib/libc/musl/arch/mips/bits/alltypes.h.in
index 66ca18ad6..ff934a4c4 100644
--- a/lib/libc/musl/arch/mips/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/mips/bits/alltypes.h.in
@@ -1,9 +1,15 @@
+#define _REDIR_TIME64 1
#define _Addr int
#define _Int64 long long
#define _Reg int
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#if _MIPSEL || __MIPSEL || __MIPSEL__
+#define __BYTE_ORDER 1234
+#else
+#define __BYTE_ORDER 4321
+#endif
+
+#define __LONG_MAX 0x7fffffffL
#ifndef __cplusplus
TYPEDEF int wchar_t;
@@ -13,14 +19,3 @@ TYPEDEF float float_t;
TYPEDEF double double_t;
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/mips/bits/endian.h b/lib/libc/musl/arch/mips/bits/endian.h
deleted file mode 100644
index 5399dcb54..000000000
--- a/lib/libc/musl/arch/mips/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if _MIPSEL || __MIPSEL || __MIPSEL__
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#else
-#define __BYTE_ORDER __BIG_ENDIAN
-#endif
diff --git a/lib/libc/musl/arch/mips/bits/hwcap.h b/lib/libc/musl/arch/mips/bits/hwcap.h
index 13e86fe70..7986deb7f 100644
--- a/lib/libc/musl/arch/mips/bits/hwcap.h
+++ b/lib/libc/musl/arch/mips/bits/hwcap.h
@@ -1,3 +1,14 @@
#define HWCAP_MIPS_R6 (1 << 0)
#define HWCAP_MIPS_MSA (1 << 1)
#define HWCAP_MIPS_CRC32 (1 << 2)
+#define HWCAP_MIPS_MIPS16 (1 << 3)
+#define HWCAP_MIPS_MDMX (1 << 4)
+#define HWCAP_MIPS_MIPS3D (1 << 5)
+#define HWCAP_MIPS_SMARTMIPS (1 << 6)
+#define HWCAP_MIPS_DSP (1 << 7)
+#define HWCAP_MIPS_DSP2 (1 << 8)
+#define HWCAP_MIPS_DSP3 (1 << 9)
+#define HWCAP_MIPS_MIPS16E2 (1 << 10)
+#define HWCAP_LOONGSON_MMI (1 << 11)
+#define HWCAP_LOONGSON_EXT (1 << 12)
+#define HWCAP_LOONGSON_EXT2 (1 << 13)
diff --git a/lib/libc/musl/arch/mips/bits/ioctl.h b/lib/libc/musl/arch/mips/bits/ioctl.h
index e277c3f05..e20bf19ea 100644
--- a/lib/libc/musl/arch/mips/bits/ioctl.h
+++ b/lib/libc/musl/arch/mips/bits/ioctl.h
@@ -110,5 +110,5 @@
#define SIOCATMARK _IOR('s', 7, int)
#define SIOCSPGRP _IOW('s', 8, pid_t)
#define SIOCGPGRP _IOR('s', 9, pid_t)
-#define SIOCGSTAMP 0x8906
-#define SIOCGSTAMPNS 0x8907
+#define SIOCGSTAMP _IOR(0x89, 6, char[16])
+#define SIOCGSTAMPNS _IOR(0x89, 7, char[16])
diff --git a/lib/libc/musl/arch/mips/bits/ipcstat.h b/lib/libc/musl/arch/mips/bits/ipcstat.h
index 0018ad1e2..4f4fcb0c5 100644
--- a/lib/libc/musl/arch/mips/bits/ipcstat.h
+++ b/lib/libc/musl/arch/mips/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/lib/libc/musl/arch/mips/bits/limits.h b/lib/libc/musl/arch/mips/bits/limits.h
deleted file mode 100644
index fbc6d238d..000000000
--- a/lib/libc/musl/arch/mips/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 32
-#endif
-
-#define LONG_MAX 0x7fffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/mips/bits/msg.h b/lib/libc/musl/arch/mips/bits/msg.h
index f28aece8f..c734dbb57 100644
--- a/lib/libc/musl/arch/mips/bits/msg.h
+++ b/lib/libc/musl/arch/mips/bits/msg.h
@@ -1,19 +1,19 @@
struct msqid_ds {
struct ipc_perm msg_perm;
#if _MIPSEL || __MIPSEL || __MIPSEL__
- time_t msg_stime;
- int __unused1;
- time_t msg_rtime;
- int __unused2;
- time_t msg_ctime;
- int __unused3;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_ctime_lo;
+ unsigned long __msg_ctime_hi;
#else
- int __unused1;
- time_t msg_stime;
- int __unused2;
- time_t msg_rtime;
- int __unused3;
- time_t msg_ctime;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_ctime_hi;
+ unsigned long __msg_ctime_lo;
#endif
unsigned long msg_cbytes;
msgqnum_t msg_qnum;
@@ -21,4 +21,7 @@ struct msqid_ds {
pid_t msg_lspid;
pid_t msg_lrpid;
unsigned long __unused[2];
+ time_t msg_stime;
+ time_t msg_rtime;
+ time_t msg_ctime;
};
diff --git a/lib/libc/musl/arch/mips/bits/sem.h b/lib/libc/musl/arch/mips/bits/sem.h
index 5184eb597..fe6f09485 100644
--- a/lib/libc/musl/arch/mips/bits/sem.h
+++ b/lib/libc/musl/arch/mips/bits/sem.h
@@ -1,7 +1,7 @@
struct semid_ds {
struct ipc_perm sem_perm;
- time_t sem_otime;
- time_t sem_ctime;
+ unsigned long __sem_otime_lo;
+ unsigned long __sem_ctime_lo;
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned short sem_nsems;
char __sem_nsems_pad[sizeof(long)-sizeof(short)];
@@ -9,6 +9,8 @@ struct semid_ds {
char __sem_nsems_pad[sizeof(long)-sizeof(short)];
unsigned short sem_nsems;
#endif
- long __unused3;
- long __unused4;
+ unsigned long __sem_otime_hi;
+ unsigned long __sem_ctime_hi;
+ time_t sem_otime;
+ time_t sem_ctime;
};
diff --git a/lib/libc/musl/arch/mips/bits/shm.h b/lib/libc/musl/arch/mips/bits/shm.h
index 8d1937819..ab8c642d8 100644
--- a/lib/libc/musl/arch/mips/bits/shm.h
+++ b/lib/libc/musl/arch/mips/bits/shm.h
@@ -3,14 +3,19 @@
struct shmid_ds {
struct ipc_perm shm_perm;
size_t shm_segsz;
- time_t shm_atime;
- time_t shm_dtime;
- time_t shm_ctime;
+ unsigned long __shm_atime_lo;
+ unsigned long __shm_dtime_lo;
+ unsigned long __shm_ctime_lo;
pid_t shm_cpid;
pid_t shm_lpid;
unsigned long shm_nattch;
- unsigned long __pad1;
- unsigned long __pad2;
+ unsigned short __shm_atime_hi;
+ unsigned short __shm_dtime_hi;
+ unsigned short __shm_ctime_hi;
+ unsigned short __pad1;
+ time_t shm_atime;
+ time_t shm_dtime;
+ time_t shm_ctime;
};
struct shminfo {
diff --git a/lib/libc/musl/arch/mips/bits/signal.h b/lib/libc/musl/arch/mips/bits/signal.h
index 1a84de590..e1d97ac78 100644
--- a/lib/libc/musl/arch/mips/bits/signal.h
+++ b/lib/libc/musl/arch/mips/bits/signal.h
@@ -19,14 +19,18 @@ typedef struct {
} fpregset_t;
struct sigcontext {
unsigned sc_regmask, sc_status;
- unsigned long long sc_pc, sc_regs[32], sc_fpregs[32];
+ unsigned long long sc_pc;
+ gregset_t sc_regs;
+ fpregset_t sc_fpregs;
unsigned sc_ownedfp, sc_fpc_csr, sc_fpc_eir, sc_used_math, sc_dsp;
unsigned long long sc_mdhi, sc_mdlo;
unsigned long sc_hi1, sc_lo1, sc_hi2, sc_lo2, sc_hi3, sc_lo3;
};
typedef struct {
unsigned regmask, status;
- unsigned long long pc, gregs[32], fpregs[32];
+ unsigned long long pc;
+ gregset_t gregs;
+ fpregset_t fpregs;
unsigned ownedfp, fpc_csr, fpc_eir, used_math, dsp;
unsigned long long mdhi, mdlo;
unsigned long hi1, lo1, hi2, lo2, hi3, lo3;
diff --git a/lib/libc/musl/arch/mips/bits/socket.h b/lib/libc/musl/arch/mips/bits/socket.h
index b82c7d341..02fbb88b4 100644
--- a/lib/libc/musl/arch/mips/bits/socket.h
+++ b/lib/libc/musl/arch/mips/bits/socket.h
@@ -1,19 +1,3 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen;
- void *msg_control;
- socklen_t msg_controllen;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
-
#define SOCK_STREAM 2
#define SOCK_DGRAM 1
@@ -32,8 +16,6 @@ struct cmsghdr {
#define SO_RCVBUF 0x1002
#define SO_SNDLOWAT 0x1003
#define SO_RCVLOWAT 0x1004
-#define SO_RCVTIMEO 0x1006
-#define SO_SNDTIMEO 0x1005
#define SO_ERROR 0x1007
#define SO_TYPE 0x1008
#define SO_ACCEPTCONN 0x1009
diff --git a/lib/libc/musl/arch/mips/bits/stat.h b/lib/libc/musl/arch/mips/bits/stat.h
index 3291a6362..48d4ac804 100644
--- a/lib/libc/musl/arch/mips/bits/stat.h
+++ b/lib/libc/musl/arch/mips/bits/stat.h
@@ -12,11 +12,15 @@ struct stat {
dev_t st_rdev;
long __st_padding2[2];
off_t st_size;
- struct timespec st_atim;
- struct timespec st_mtim;
- struct timespec st_ctim;
+ struct {
+ long tv_sec;
+ long tv_nsec;
+ } __st_atim32, __st_mtim32, __st_ctim32;
blksize_t st_blksize;
long __st_padding3;
blkcnt_t st_blocks;
- long __st_padding4[14];
+ struct timespec st_atim;
+ struct timespec st_mtim;
+ struct timespec st_ctim;
+ long __st_padding4[2];
};
diff --git a/lib/libc/musl/arch/mips/bits/syscall.h.in b/lib/libc/musl/arch/mips/bits/syscall.h.in
index 582fa3b51..86251bf31 100644
--- a/lib/libc/musl/arch/mips/bits/syscall.h.in
+++ b/lib/libc/musl/arch/mips/bits/syscall.h.in
@@ -76,8 +76,8 @@
#define __NR_setrlimit 4075
#define __NR_getrlimit 4076
#define __NR_getrusage 4077
-#define __NR_gettimeofday 4078
-#define __NR_settimeofday 4079
+#define __NR_gettimeofday_time32 4078
+#define __NR_settimeofday_time32 4079
#define __NR_getgroups 4080
#define __NR_setgroups 4081
#define __NR_reserved82 4082
@@ -256,14 +256,14 @@
#define __NR_statfs64 4255
#define __NR_fstatfs64 4256
#define __NR_timer_create 4257
-#define __NR_timer_settime 4258
-#define __NR_timer_gettime 4259
+#define __NR_timer_settime32 4258
+#define __NR_timer_gettime32 4259
#define __NR_timer_getoverrun 4260
#define __NR_timer_delete 4261
-#define __NR_clock_settime 4262
-#define __NR_clock_gettime 4263
-#define __NR_clock_getres 4264
-#define __NR_clock_nanosleep 4265
+#define __NR_clock_settime32 4262
+#define __NR_clock_gettime32 4263
+#define __NR_clock_getres_time32 4264
+#define __NR_clock_nanosleep_time32 4265
#define __NR_tgkill 4266
#define __NR_utimes 4267
#define __NR_mbind 4268
@@ -319,8 +319,8 @@
#define __NR_eventfd 4319
#define __NR_fallocate 4320
#define __NR_timerfd_create 4321
-#define __NR_timerfd_gettime 4322
-#define __NR_timerfd_settime 4323
+#define __NR_timerfd_gettime32 4322
+#define __NR_timerfd_settime32 4323
#define __NR_signalfd4 4324
#define __NR_eventfd2 4325
#define __NR_epoll_create1 4326
@@ -406,4 +406,6 @@
#define __NR_fsconfig 4431
#define __NR_fsmount 4432
#define __NR_fspick 4433
+#define __NR_pidfd_open 4434
+#define __NR_clone3 4435
diff --git a/lib/libc/musl/arch/mips/reloc.h b/lib/libc/musl/arch/mips/reloc.h
index b3d59a45c..88d236390 100644
--- a/lib/libc/musl/arch/mips/reloc.h
+++ b/lib/libc/musl/arch/mips/reloc.h
@@ -1,5 +1,3 @@
-#include
-
#if __mips_isa_rev >= 6
#define ISA_SUFFIX "r6"
#else
diff --git a/lib/libc/musl/arch/mips/syscall_arch.h b/lib/libc/musl/arch/mips/syscall_arch.h
index 6ea73437b..f821e73fc 100644
--- a/lib/libc/musl/arch/mips/syscall_arch.h
+++ b/lib/libc/musl/arch/mips/syscall_arch.h
@@ -142,7 +142,9 @@ static inline long __syscall7(long n, long a, long b, long c, long d, long e, lo
}
#define VDSO_USEFUL
-#define VDSO_CGT_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_SYM "__vdso_clock_gettime"
+#define VDSO_CGT32_VER "LINUX_2.6"
+#define VDSO_CGT_SYM "__vdso_clock_gettime64"
#define VDSO_CGT_VER "LINUX_2.6"
#define SO_SNDTIMEO_OLD 0x1005
diff --git a/lib/libc/musl/arch/mips64/bits/alltypes.h.in b/lib/libc/musl/arch/mips64/bits/alltypes.h.in
index 2b2e34a83..fcd61ee85 100644
--- a/lib/libc/musl/arch/mips64/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/mips64/bits/alltypes.h.in
@@ -2,8 +2,13 @@
#define _Int64 long
#define _Reg long
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#if _MIPSEL || __MIPSEL || __MIPSEL__
+#define __BYTE_ORDER 1234
+#else
+#define __BYTE_ORDER 4321
+#endif
+
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
TYPEDEF int wchar_t;
@@ -14,15 +19,4 @@ TYPEDEF double double_t;
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
TYPEDEF unsigned nlink_t;
-
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/mips64/bits/endian.h b/lib/libc/musl/arch/mips64/bits/endian.h
deleted file mode 100644
index 5399dcb54..000000000
--- a/lib/libc/musl/arch/mips64/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if _MIPSEL || __MIPSEL || __MIPSEL__
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#else
-#define __BYTE_ORDER __BIG_ENDIAN
-#endif
diff --git a/lib/libc/musl/arch/mips64/bits/limits.h b/lib/libc/musl/arch/mips64/bits/limits.h
deleted file mode 100644
index 58698c62d..000000000
--- a/lib/libc/musl/arch/mips64/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/mips64/bits/socket.h b/lib/libc/musl/arch/mips64/bits/socket.h
index 5aff0d91c..519b9c8ea 100644
--- a/lib/libc/musl/arch/mips64/bits/socket.h
+++ b/lib/libc/musl/arch/mips64/bits/socket.h
@@ -1,37 +1,3 @@
-#include
-
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1, msg_iovlen;
-#else
- int msg_iovlen, __pad1;
-#endif
- void *msg_control;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad2;
- socklen_t msg_controllen;
-#else
- socklen_t msg_controllen;
- int __pad2;
-#endif
- int msg_flags;
-};
-
-struct cmsghdr {
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1;
- socklen_t cmsg_len;
-#else
- socklen_t cmsg_len;
- int __pad1;
-#endif
- int cmsg_level;
- int cmsg_type;
-};
-
#define SOCK_STREAM 2
#define SOCK_DGRAM 1
#define SOL_SOCKET 65535
diff --git a/lib/libc/musl/arch/mips64/bits/syscall.h.in b/lib/libc/musl/arch/mips64/bits/syscall.h.in
index 34b9752e6..9b406e9a4 100644
--- a/lib/libc/musl/arch/mips64/bits/syscall.h.in
+++ b/lib/libc/musl/arch/mips64/bits/syscall.h.in
@@ -336,4 +336,6 @@
#define __NR_fsconfig 5431
#define __NR_fsmount 5432
#define __NR_fspick 5433
+#define __NR_pidfd_open 5434
+#define __NR_clone3 5435
diff --git a/lib/libc/musl/arch/mips64/reloc.h b/lib/libc/musl/arch/mips64/reloc.h
index bbd9bd9d2..fdb5edc9c 100644
--- a/lib/libc/musl/arch/mips64/reloc.h
+++ b/lib/libc/musl/arch/mips64/reloc.h
@@ -1,9 +1,3 @@
-#ifndef __RELOC_H__
-#define __RELOC_H__
-
-#define _GNU_SOURCE
-#include
-
#if __mips_isa_rev >= 6
#define ISA_SUFFIX "r6"
#else
@@ -33,6 +27,8 @@
#define REL_DTPOFF R_MIPS_TLS_DTPREL64
#define REL_TPOFF R_MIPS_TLS_TPREL64
+#include
+
#undef R_TYPE
#undef R_SYM
#undef R_INFO
@@ -62,5 +58,3 @@
" daddu %0, %0, $ra \n" \
".set pop \n" \
: "=r"(*(fp)) : : "memory", "ra" )
-
-#endif
diff --git a/lib/libc/musl/arch/powerpc/bits/alltypes.h.in b/lib/libc/musl/arch/powerpc/bits/alltypes.h.in
index 8e687ef16..b48df6a62 100644
--- a/lib/libc/musl/arch/powerpc/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/powerpc/bits/alltypes.h.in
@@ -1,9 +1,10 @@
+#define _REDIR_TIME64 1
#define _Addr int
#define _Int64 long long
#define _Reg int
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#define __BYTE_ORDER 4321
+#define __LONG_MAX 0x7fffffffL
#ifndef __cplusplus
#ifdef __WCHAR_TYPE__
@@ -17,14 +18,3 @@ TYPEDEF float float_t;
TYPEDEF double double_t;
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[9]; volatile int __vi[9]; unsigned __s[9]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[6]; volatile int __vi[6]; volatile void *volatile __p[6]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[12]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[8]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[5]; volatile int __vi[5]; void *__p[5]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/powerpc/bits/endian.h b/lib/libc/musl/arch/powerpc/bits/endian.h
deleted file mode 100644
index 4442abf4e..000000000
--- a/lib/libc/musl/arch/powerpc/bits/endian.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifdef __BIG_ENDIAN__
- #if __BIG_ENDIAN__
- #define __BYTE_ORDER __BIG_ENDIAN
- #endif
-#endif /* __BIG_ENDIAN__ */
-
-#ifdef __LITTLE_ENDIAN__
- #if __LITTLE_ENDIAN__
- #define __BYTE_ORDER __LITTLE_ENDIAN
- #endif
-#endif /* __LITTLE_ENDIAN__ */
-
-#ifndef __BYTE_ORDER
- #define __BYTE_ORDER __BIG_ENDIAN
-#endif
diff --git a/lib/libc/musl/arch/powerpc/bits/ioctl.h b/lib/libc/musl/arch/powerpc/bits/ioctl.h
index b6cbb18f4..ac9bfd204 100644
--- a/lib/libc/musl/arch/powerpc/bits/ioctl.h
+++ b/lib/libc/musl/arch/powerpc/bits/ioctl.h
@@ -116,5 +116,5 @@
#define FIOGETOWN 0x8903
#define SIOCGPGRP 0x8904
#define SIOCATMARK 0x8905
-#define SIOCGSTAMP 0x8906
-#define SIOCGSTAMPNS 0x8907
+#define SIOCGSTAMP _IOR(0x89, 6, char[16])
+#define SIOCGSTAMPNS _IOR(0x89, 7, char[16])
diff --git a/lib/libc/musl/arch/powerpc/bits/ipcstat.h b/lib/libc/musl/arch/powerpc/bits/ipcstat.h
index 0018ad1e2..4f4fcb0c5 100644
--- a/lib/libc/musl/arch/powerpc/bits/ipcstat.h
+++ b/lib/libc/musl/arch/powerpc/bits/ipcstat.h
@@ -1 +1 @@
-#define IPC_STAT 2
+#define IPC_STAT 0x102
diff --git a/lib/libc/musl/arch/powerpc/bits/limits.h b/lib/libc/musl/arch/powerpc/bits/limits.h
deleted file mode 100644
index fbc6d238d..000000000
--- a/lib/libc/musl/arch/powerpc/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 32
-#endif
-
-#define LONG_MAX 0x7fffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/powerpc/bits/msg.h b/lib/libc/musl/arch/powerpc/bits/msg.h
index 171c11a34..9fb15dccb 100644
--- a/lib/libc/musl/arch/powerpc/bits/msg.h
+++ b/lib/libc/musl/arch/powerpc/bits/msg.h
@@ -1,15 +1,18 @@
struct msqid_ds {
struct ipc_perm msg_perm;
- int __unused1;
- time_t msg_stime;
- int __unused2;
- time_t msg_rtime;
- int __unused3;
- time_t msg_ctime;
+ unsigned long __msg_stime_hi;
+ unsigned long __msg_stime_lo;
+ unsigned long __msg_rtime_hi;
+ unsigned long __msg_rtime_lo;
+ unsigned long __msg_ctime_hi;
+ unsigned long __msg_ctime_lo;
unsigned long msg_cbytes;
msgqnum_t msg_qnum;
msglen_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
unsigned long __unused[2];
+ time_t msg_stime;
+ time_t msg_rtime;
+ time_t msg_ctime;
};
diff --git a/lib/libc/musl/arch/powerpc/bits/sem.h b/lib/libc/musl/arch/powerpc/bits/sem.h
index bc2d6d1f5..28be48452 100644
--- a/lib/libc/musl/arch/powerpc/bits/sem.h
+++ b/lib/libc/musl/arch/powerpc/bits/sem.h
@@ -1,10 +1,12 @@
struct semid_ds {
struct ipc_perm sem_perm;
- int __unused1;
- time_t sem_otime;
- int __unused2;
- time_t sem_ctime;
+ unsigned long __sem_otime_hi;
+ unsigned long __sem_otime_lo;
+ unsigned long __sem_ctime_hi;
+ unsigned long __sem_ctime_lo;
unsigned short __sem_nsems_pad, sem_nsems;
long __unused3;
long __unused4;
+ time_t sem_otime;
+ time_t sem_ctime;
};
diff --git a/lib/libc/musl/arch/powerpc/bits/shm.h b/lib/libc/musl/arch/powerpc/bits/shm.h
index b19801d51..fb1d4020f 100644
--- a/lib/libc/musl/arch/powerpc/bits/shm.h
+++ b/lib/libc/musl/arch/powerpc/bits/shm.h
@@ -2,19 +2,21 @@
struct shmid_ds {
struct ipc_perm shm_perm;
- int __unused1;
- time_t shm_atime;
- int __unused2;
- time_t shm_dtime;
- int __unused3;
- time_t shm_ctime;
- int __unused4;
+ unsigned long __shm_atime_hi;
+ unsigned long __shm_atime_lo;
+ unsigned long __shm_dtime_hi;
+ unsigned long __shm_dtime_lo;
+ unsigned long __shm_ctime_hi;
+ unsigned long __shm_ctime_lo;
size_t shm_segsz;
pid_t shm_cpid;
pid_t shm_lpid;
unsigned long shm_nattch;
unsigned long __pad1;
unsigned long __pad2;
+ time_t shm_atime;
+ time_t shm_dtime;
+ time_t shm_ctime;
};
struct shminfo {
diff --git a/lib/libc/musl/arch/powerpc/bits/signal.h b/lib/libc/musl/arch/powerpc/bits/signal.h
index 06efb11cf..c1bf3caf3 100644
--- a/lib/libc/musl/arch/powerpc/bits/signal.h
+++ b/lib/libc/musl/arch/powerpc/bits/signal.h
@@ -28,7 +28,7 @@ struct sigcontext {
int signal;
unsigned long handler;
unsigned long oldmask;
- void *regs;
+ struct pt_regs *regs;
};
typedef struct {
diff --git a/lib/libc/musl/arch/powerpc/bits/socket.h b/lib/libc/musl/arch/powerpc/bits/socket.h
index a94b8bdb8..b19ed42bf 100644
--- a/lib/libc/musl/arch/powerpc/bits/socket.h
+++ b/lib/libc/musl/arch/powerpc/bits/socket.h
@@ -1,19 +1,3 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen;
- void *msg_control;
- socklen_t msg_controllen;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
-
#define SO_DEBUG 1
#define SO_REUSEADDR 2
#define SO_TYPE 3
@@ -31,8 +15,6 @@ struct cmsghdr {
#define SO_REUSEPORT 15
#define SO_RCVLOWAT 16
#define SO_SNDLOWAT 17
-#define SO_RCVTIMEO 18
-#define SO_SNDTIMEO 19
#define SO_PASSCRED 20
#define SO_PEERCRED 21
#define SO_ACCEPTCONN 30
diff --git a/lib/libc/musl/arch/powerpc/bits/stat.h b/lib/libc/musl/arch/powerpc/bits/stat.h
index dcb896fd5..585d98e90 100644
--- a/lib/libc/musl/arch/powerpc/bits/stat.h
+++ b/lib/libc/musl/arch/powerpc/bits/stat.h
@@ -13,8 +13,12 @@ struct stat {
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
+ struct {
+ long tv_sec;
+ long tv_nsec;
+ } __st_atim32, __st_mtim32, __st_ctim32;
+ unsigned __unused[2];
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
- unsigned __unused[2];
};
diff --git a/lib/libc/musl/arch/powerpc/bits/syscall.h.in b/lib/libc/musl/arch/powerpc/bits/syscall.h.in
index adcf63dbb..8d4f79b52 100644
--- a/lib/libc/musl/arch/powerpc/bits/syscall.h.in
+++ b/lib/libc/musl/arch/powerpc/bits/syscall.h.in
@@ -76,8 +76,8 @@
#define __NR_setrlimit 75
#define __NR_getrlimit 76
#define __NR_getrusage 77
-#define __NR_gettimeofday 78
-#define __NR_settimeofday 79
+#define __NR_gettimeofday_time32 78
+#define __NR_settimeofday_time32 79
#define __NR_getgroups 80
#define __NR_setgroups 81
#define __NR_select 82
@@ -238,14 +238,14 @@
#define __NR_epoll_wait 238
#define __NR_remap_file_pages 239
#define __NR_timer_create 240
-#define __NR_timer_settime 241
-#define __NR_timer_gettime 242
+#define __NR_timer_settime32 241
+#define __NR_timer_gettime32 242
#define __NR_timer_getoverrun 243
#define __NR_timer_delete 244
-#define __NR_clock_settime 245
-#define __NR_clock_gettime 246
-#define __NR_clock_getres 247
-#define __NR_clock_nanosleep 248
+#define __NR_clock_settime32 245
+#define __NR_clock_gettime32 246
+#define __NR_clock_getres_time32 247
+#define __NR_clock_nanosleep_time32 248
#define __NR_swapcontext 249
#define __NR_tgkill 250
#define __NR_utimes 251
@@ -307,8 +307,8 @@
#define __NR_sync_file_range2 308
#define __NR_fallocate 309
#define __NR_subpage_prot 310
-#define __NR_timerfd_settime 311
-#define __NR_timerfd_gettime 312
+#define __NR_timerfd_settime32 311
+#define __NR_timerfd_gettime32 312
#define __NR_signalfd4 313
#define __NR_eventfd2 314
#define __NR_epoll_create1 315
@@ -413,4 +413,6 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
diff --git a/lib/libc/musl/arch/powerpc64/bits/alltypes.h.in b/lib/libc/musl/arch/powerpc64/bits/alltypes.h.in
index 5b205851f..143ffa8d2 100644
--- a/lib/libc/musl/arch/powerpc64/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/powerpc64/bits/alltypes.h.in
@@ -2,8 +2,13 @@
#define _Int64 long
#define _Reg long
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#if __BIG_ENDIAN__
+#define __BYTE_ORDER 4321
+#else
+#define __BYTE_ORDER 1234
+#endif
+
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
TYPEDEF int wchar_t;
@@ -13,14 +18,3 @@ TYPEDEF float float_t;
TYPEDEF double double_t;
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/powerpc64/bits/endian.h b/lib/libc/musl/arch/powerpc64/bits/endian.h
deleted file mode 100644
index 2016cb207..000000000
--- a/lib/libc/musl/arch/powerpc64/bits/endian.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if __BIG_ENDIAN__
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
diff --git a/lib/libc/musl/arch/powerpc64/bits/limits.h b/lib/libc/musl/arch/powerpc64/bits/limits.h
deleted file mode 100644
index 0226588c3..000000000
--- a/lib/libc/musl/arch/powerpc64/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/powerpc64/bits/signal.h b/lib/libc/musl/arch/powerpc64/bits/signal.h
index 2cc0604c5..d5493b185 100644
--- a/lib/libc/musl/arch/powerpc64/bits/signal.h
+++ b/lib/libc/musl/arch/powerpc64/bits/signal.h
@@ -9,11 +9,7 @@
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
typedef unsigned long greg_t, gregset_t[48];
-
-typedef struct {
- double fpregs[32];
- double fpscr;
-} fpregset_t;
+typedef double fpregset_t[33];
typedef struct {
#ifdef __GNUC__
@@ -36,7 +32,7 @@ typedef struct sigcontext {
int _pad0;
unsigned long handler;
unsigned long oldmask;
- void *regs;
+ struct pt_regs *regs;
gregset_t gp_regs;
fpregset_t fp_regs;
vrregset_t *v_regs;
diff --git a/lib/libc/musl/arch/powerpc64/bits/socket.h b/lib/libc/musl/arch/powerpc64/bits/socket.h
index 0f3c9aac9..557e324fd 100644
--- a/lib/libc/musl/arch/powerpc64/bits/socket.h
+++ b/lib/libc/musl/arch/powerpc64/bits/socket.h
@@ -1,37 +1,3 @@
-#include
-
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1, msg_iovlen;
-#else
- int msg_iovlen, __pad1;
-#endif
- void *msg_control;
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad2;
- socklen_t msg_controllen;
-#else
- socklen_t msg_controllen;
- int __pad2;
-#endif
- int msg_flags;
-};
-
-struct cmsghdr {
-#if __BYTE_ORDER == __BIG_ENDIAN
- int __pad1;
- socklen_t cmsg_len;
-#else
- socklen_t cmsg_len;
- int __pad1;
-#endif
- int cmsg_level;
- int cmsg_type;
-};
-
#define SO_DEBUG 1
#define SO_REUSEADDR 2
#define SO_TYPE 3
diff --git a/lib/libc/musl/arch/powerpc64/bits/syscall.h.in b/lib/libc/musl/arch/powerpc64/bits/syscall.h.in
index 32545b394..b935864c4 100644
--- a/lib/libc/musl/arch/powerpc64/bits/syscall.h.in
+++ b/lib/libc/musl/arch/powerpc64/bits/syscall.h.in
@@ -385,4 +385,6 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
diff --git a/lib/libc/musl/arch/powerpc64/reloc.h b/lib/libc/musl/arch/powerpc64/reloc.h
index 5bdaeede5..2f1bba059 100644
--- a/lib/libc/musl/arch/powerpc64/reloc.h
+++ b/lib/libc/musl/arch/powerpc64/reloc.h
@@ -1,5 +1,3 @@
-#include
-
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define ENDIAN_SUFFIX "le"
#else
diff --git a/lib/libc/musl/arch/riscv64/atomic_arch.h b/lib/libc/musl/arch/riscv64/atomic_arch.h
index 41ad4d049..0c3825886 100644
--- a/lib/libc/musl/arch/riscv64/atomic_arch.h
+++ b/lib/libc/musl/arch/riscv64/atomic_arch.h
@@ -15,7 +15,7 @@ static inline int a_cas(volatile int *p, int t, int s)
" bnez %1, 1b\n"
"1:"
: "=&r"(old), "=&r"(tmp)
- : "r"(p), "r"(t), "r"(s)
+ : "r"(p), "r"((long)t), "r"((long)s)
: "memory");
return old;
}
diff --git a/lib/libc/musl/arch/riscv64/bits/alltypes.h.in b/lib/libc/musl/arch/riscv64/bits/alltypes.h.in
index ae9ba41da..4579d1740 100644
--- a/lib/libc/musl/arch/riscv64/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/riscv64/bits/alltypes.h.in
@@ -2,8 +2,8 @@
#define _Int64 long
#define _Reg long
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
TYPEDEF int wchar_t;
@@ -16,14 +16,3 @@ TYPEDEF float float_t;
TYPEDEF double double_t;
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/riscv64/bits/endian.h b/lib/libc/musl/arch/riscv64/bits/endian.h
deleted file mode 100644
index 172c338f5..000000000
--- a/lib/libc/musl/arch/riscv64/bits/endian.h
+++ /dev/null
@@ -1 +0,0 @@
-#define __BYTE_ORDER __LITTLE_ENDIAN
diff --git a/lib/libc/musl/arch/riscv64/bits/limits.h b/lib/libc/musl/arch/riscv64/bits/limits.h
deleted file mode 100644
index 0226588c3..000000000
--- a/lib/libc/musl/arch/riscv64/bits/limits.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/riscv64/bits/reg.h b/lib/libc/musl/arch/riscv64/bits/reg.h
index c800788c3..2633f39d7 100644
--- a/lib/libc/musl/arch/riscv64/bits/reg.h
+++ b/lib/libc/musl/arch/riscv64/bits/reg.h
@@ -1,8 +1,2 @@
#undef __WORDSIZE
#define __WORDSIZE 64
-#define REG_PC 0
-#define REG_RA 1
-#define REG_SP 2
-#define REG_TP 4
-#define REG_S0 8
-#define REG_A0 10
diff --git a/lib/libc/musl/arch/riscv64/bits/signal.h b/lib/libc/musl/arch/riscv64/bits/signal.h
index 2ff4be302..b006334f7 100644
--- a/lib/libc/musl/arch/riscv64/bits/signal.h
+++ b/lib/libc/musl/arch/riscv64/bits/signal.h
@@ -35,6 +35,15 @@ typedef struct mcontext_t {
union __riscv_mc_fp_state __fpregs;
} mcontext_t;
+#if defined(_GNU_SOURCE)
+#define REG_PC 0
+#define REG_RA 1
+#define REG_SP 2
+#define REG_TP 4
+#define REG_S0 8
+#define REG_A0 10
+#endif
+
#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
typedef unsigned long greg_t;
typedef unsigned long gregset_t[32];
diff --git a/lib/libc/musl/arch/riscv64/bits/socket.h b/lib/libc/musl/arch/riscv64/bits/socket.h
deleted file mode 100644
index aae537d34..000000000
--- a/lib/libc/musl/arch/riscv64/bits/socket.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#include
-
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen, __pad1;
- void *msg_control;
- socklen_t msg_controllen;
- int __pad2;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int __pad1;
- int cmsg_level;
- int cmsg_type;
-};
diff --git a/lib/libc/musl/arch/riscv64/bits/syscall.h.in b/lib/libc/musl/arch/riscv64/bits/syscall.h.in
index 1db70cfbf..0043eeba3 100644
--- a/lib/libc/musl/arch/riscv64/bits/syscall.h.in
+++ b/lib/libc/musl/arch/riscv64/bits/syscall.h.in
@@ -287,6 +287,8 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
#define __NR_sysriscv __NR_arch_specific_syscall
#define __NR_riscv_flush_icache (__NR_sysriscv + 15)
diff --git a/lib/libc/musl/arch/s390x/bits/alltypes.h.in b/lib/libc/musl/arch/s390x/bits/alltypes.h.in
index 1a8384620..15d18c8f4 100644
--- a/lib/libc/musl/arch/s390x/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/s390x/bits/alltypes.h.in
@@ -2,8 +2,8 @@
#define _Int64 long
#define _Reg long
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#define __BYTE_ORDER 4321
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
TYPEDEF int wchar_t;
@@ -13,14 +13,3 @@ TYPEDEF double float_t;
TYPEDEF double double_t;
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/s390x/bits/endian.h b/lib/libc/musl/arch/s390x/bits/endian.h
deleted file mode 100644
index ef074b776..000000000
--- a/lib/libc/musl/arch/s390x/bits/endian.h
+++ /dev/null
@@ -1 +0,0 @@
-#define __BYTE_ORDER __BIG_ENDIAN
diff --git a/lib/libc/musl/arch/s390x/bits/limits.h b/lib/libc/musl/arch/s390x/bits/limits.h
index 86ef7663f..07743b6fd 100644
--- a/lib/libc/musl/arch/s390x/bits/limits.h
+++ b/lib/libc/musl/arch/s390x/bits/limits.h
@@ -1,8 +1 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define PAGESIZE 4096
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/s390x/bits/socket.h b/lib/libc/musl/arch/s390x/bits/socket.h
deleted file mode 100644
index bd4b20c42..000000000
--- a/lib/libc/musl/arch/s390x/bits/socket.h
+++ /dev/null
@@ -1,17 +0,0 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int __pad1, msg_iovlen;
- void *msg_control;
- int __pad2;
- socklen_t msg_controllen;
- int msg_flags;
-};
-
-struct cmsghdr {
- int __pad1;
- socklen_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
diff --git a/lib/libc/musl/arch/s390x/bits/syscall.h.in b/lib/libc/musl/arch/s390x/bits/syscall.h.in
index c4c70474e..e89f37829 100644
--- a/lib/libc/musl/arch/s390x/bits/syscall.h.in
+++ b/lib/libc/musl/arch/s390x/bits/syscall.h.in
@@ -350,4 +350,6 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
diff --git a/lib/libc/musl/arch/s390x/reloc.h b/lib/libc/musl/arch/s390x/reloc.h
index a238dc654..6e5c1fb87 100644
--- a/lib/libc/musl/arch/s390x/reloc.h
+++ b/lib/libc/musl/arch/s390x/reloc.h
@@ -1,5 +1,3 @@
-#include
-
#define LDSO_ARCH "s390x"
#define REL_SYMBOLIC R_390_64
diff --git a/lib/libc/musl/arch/x86_64/bits/alltypes.h.in b/lib/libc/musl/arch/x86_64/bits/alltypes.h.in
index dc551d472..5cd8a2997 100644
--- a/lib/libc/musl/arch/x86_64/bits/alltypes.h.in
+++ b/lib/libc/musl/arch/x86_64/bits/alltypes.h.in
@@ -2,8 +2,8 @@
#define _Int64 long
#define _Reg long
-TYPEDEF __builtin_va_list va_list;
-TYPEDEF __builtin_va_list __isoc_va_list;
+#define __BYTE_ORDER 1234
+#define __LONG_MAX 0x7fffffffffffffffL
#ifndef __cplusplus
TYPEDEF int wchar_t;
@@ -18,14 +18,3 @@ TYPEDEF double double_t;
#endif
TYPEDEF struct { long long __ll; long double __ld; } max_align_t;
-
-TYPEDEF long time_t;
-TYPEDEF long suseconds_t;
-
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; unsigned long __s[7]; } __u; } pthread_attr_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } pthread_mutex_t;
-TYPEDEF struct { union { int __i[10]; volatile int __vi[10]; volatile void *volatile __p[5]; } __u; } mtx_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } pthread_cond_t;
-TYPEDEF struct { union { int __i[12]; volatile int __vi[12]; void *__p[6]; } __u; } cnd_t;
-TYPEDEF struct { union { int __i[14]; volatile int __vi[14]; void *__p[7]; } __u; } pthread_rwlock_t;
-TYPEDEF struct { union { int __i[8]; volatile int __vi[8]; void *__p[4]; } __u; } pthread_barrier_t;
diff --git a/lib/libc/musl/arch/x86_64/bits/endian.h b/lib/libc/musl/arch/x86_64/bits/endian.h
deleted file mode 100644
index 172c338f5..000000000
--- a/lib/libc/musl/arch/x86_64/bits/endian.h
+++ /dev/null
@@ -1 +0,0 @@
-#define __BYTE_ORDER __LITTLE_ENDIAN
diff --git a/lib/libc/musl/arch/x86_64/bits/limits.h b/lib/libc/musl/arch/x86_64/bits/limits.h
index 86ef7663f..07743b6fd 100644
--- a/lib/libc/musl/arch/x86_64/bits/limits.h
+++ b/lib/libc/musl/arch/x86_64/bits/limits.h
@@ -1,8 +1 @@
-#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
- || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define PAGESIZE 4096
-#define LONG_BIT 64
-#endif
-
-#define LONG_MAX 0x7fffffffffffffffL
-#define LLONG_MAX 0x7fffffffffffffffLL
diff --git a/lib/libc/musl/arch/x86_64/bits/socket.h b/lib/libc/musl/arch/x86_64/bits/socket.h
deleted file mode 100644
index a4c89f3d7..000000000
--- a/lib/libc/musl/arch/x86_64/bits/socket.h
+++ /dev/null
@@ -1,16 +0,0 @@
-struct msghdr {
- void *msg_name;
- socklen_t msg_namelen;
- struct iovec *msg_iov;
- int msg_iovlen, __pad1;
- void *msg_control;
- socklen_t msg_controllen, __pad2;
- int msg_flags;
-};
-
-struct cmsghdr {
- socklen_t cmsg_len;
- int __pad1;
- int cmsg_level;
- int cmsg_type;
-};
diff --git a/lib/libc/musl/arch/x86_64/bits/syscall.h.in b/lib/libc/musl/arch/x86_64/bits/syscall.h.in
index 2d4634f68..6a646ad34 100644
--- a/lib/libc/musl/arch/x86_64/bits/syscall.h.in
+++ b/lib/libc/musl/arch/x86_64/bits/syscall.h.in
@@ -343,4 +343,6 @@
#define __NR_fsconfig 431
#define __NR_fsmount 432
#define __NR_fspick 433
+#define __NR_pidfd_open 434
+#define __NR_clone3 435
diff --git a/lib/libc/musl/compat/time32/__xstat.c b/lib/libc/musl/compat/time32/__xstat.c
new file mode 100644
index 000000000..acfbd3cc5
--- /dev/null
+++ b/lib/libc/musl/compat/time32/__xstat.c
@@ -0,0 +1,24 @@
+#include "time32.h"
+#include
+
+struct stat32;
+
+int __fxstat64(int ver, int fd, struct stat32 *buf)
+{
+ return __fstat_time32(fd, buf);
+}
+
+int __fxstatat64(int ver, int fd, const char *path, struct stat32 *buf, int flag)
+{
+ return __fstatat_time32(fd, path, buf, flag);
+}
+
+int __lxstat64(int ver, const char *path, struct stat32 *buf)
+{
+ return __lstat_time32(path, buf);
+}
+
+int __xstat64(int ver, const char *path, struct stat32 *buf)
+{
+ return __stat_time32(path, buf);
+}
diff --git a/lib/libc/musl/compat/time32/adjtime32.c b/lib/libc/musl/compat/time32/adjtime32.c
new file mode 100644
index 000000000..b0042c631
--- /dev/null
+++ b/lib/libc/musl/compat/time32/adjtime32.c
@@ -0,0 +1,21 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include
+#include
+#include
+
+int __adjtime32(const struct timeval32 *in32, struct timeval32 *out32)
+{
+ struct timeval out;
+ int r = adjtime((&(struct timeval){
+ .tv_sec = in32->tv_sec,
+ .tv_usec = in32->tv_usec}), &out);
+ if (r) return r;
+ /* We can't range-check the result because success was already
+ * committed by the above call. */
+ if (out32) {
+ out32->tv_sec = out.tv_sec;
+ out32->tv_usec = out.tv_usec;
+ }
+ return r;
+}
diff --git a/lib/libc/musl/compat/time32/adjtimex_time32.c b/lib/libc/musl/compat/time32/adjtimex_time32.c
new file mode 100644
index 000000000..9c6f190ab
--- /dev/null
+++ b/lib/libc/musl/compat/time32/adjtimex_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include
+#include
+
+struct timex32;
+
+int __adjtimex_time32(struct timex32 *tx32)
+{
+ return __clock_adjtime32(CLOCK_REALTIME, tx32);
+}
diff --git a/lib/libc/musl/compat/time32/aio_suspend_time32.c b/lib/libc/musl/compat/time32/aio_suspend_time32.c
new file mode 100644
index 000000000..ed5119bd7
--- /dev/null
+++ b/lib/libc/musl/compat/time32/aio_suspend_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include
+#include
+
+int __aio_suspend_time32(const struct aiocb *const cbs[], int cnt, const struct timespec32 *ts32)
+{
+ return aio_suspend(cbs, cnt, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
+
+weak_alias(aio_suspend, aio_suspend64);
diff --git a/lib/libc/musl/compat/time32/clock_adjtime32.c b/lib/libc/musl/compat/time32/clock_adjtime32.c
new file mode 100644
index 000000000..5a25b8ac0
--- /dev/null
+++ b/lib/libc/musl/compat/time32/clock_adjtime32.c
@@ -0,0 +1,70 @@
+#include "time32.h"
+#include
+#include
+#include
+#include
+#include
+
+struct timex32 {
+ unsigned modes;
+ long offset, freq, maxerror, esterror;
+ int status;
+ long constant, precision, tolerance;
+ struct timeval32 time;
+ long tick, ppsfreq, jitter;
+ int shift;
+ long stabil, jitcnt, calcnt, errcnt, stbcnt;
+ int tai;
+ int __padding[11];
+};
+
+int __clock_adjtime32(clockid_t clock_id, struct timex32 *tx32)
+{
+ struct timex utx = {
+ .modes = tx32->modes,
+ .offset = tx32->offset,
+ .freq = tx32->freq,
+ .maxerror = tx32->maxerror,
+ .esterror = tx32->esterror,
+ .status = tx32->status,
+ .constant = tx32->constant,
+ .precision = tx32->precision,
+ .tolerance = tx32->tolerance,
+ .time.tv_sec = tx32->time.tv_sec,
+ .time.tv_usec = tx32->time.tv_usec,
+ .tick = tx32->tick,
+ .ppsfreq = tx32->ppsfreq,
+ .jitter = tx32->jitter,
+ .shift = tx32->shift,
+ .stabil = tx32->stabil,
+ .jitcnt = tx32->jitcnt,
+ .calcnt = tx32->calcnt,
+ .errcnt = tx32->errcnt,
+ .stbcnt = tx32->stbcnt,
+ .tai = tx32->tai,
+ };
+ int r = clock_adjtime(clock_id, &utx);
+ if (r<0) return r;
+ tx32->modes = utx.modes;
+ tx32->offset = utx.offset;
+ tx32->freq = utx.freq;
+ tx32->maxerror = utx.maxerror;
+ tx32->esterror = utx.esterror;
+ tx32->status = utx.status;
+ tx32->constant = utx.constant;
+ tx32->precision = utx.precision;
+ tx32->tolerance = utx.tolerance;
+ tx32->time.tv_sec = utx.time.tv_sec;
+ tx32->time.tv_usec = utx.time.tv_usec;
+ tx32->tick = utx.tick;
+ tx32->ppsfreq = utx.ppsfreq;
+ tx32->jitter = utx.jitter;
+ tx32->shift = utx.shift;
+ tx32->stabil = utx.stabil;
+ tx32->jitcnt = utx.jitcnt;
+ tx32->calcnt = utx.calcnt;
+ tx32->errcnt = utx.errcnt;
+ tx32->stbcnt = utx.stbcnt;
+ tx32->tai = utx.tai;
+ return r;
+}
diff --git a/lib/libc/musl/compat/time32/clock_getres_time32.c b/lib/libc/musl/compat/time32/clock_getres_time32.c
new file mode 100644
index 000000000..47a24c135
--- /dev/null
+++ b/lib/libc/musl/compat/time32/clock_getres_time32.c
@@ -0,0 +1,13 @@
+#include "time32.h"
+#include
+
+int __clock_getres_time32(clockid_t clk, struct timespec32 *ts32)
+{
+ struct timespec ts;
+ int r = clock_getres(clk, &ts);
+ if (!r && ts32) {
+ ts32->tv_sec = ts.tv_sec;
+ ts32->tv_nsec = ts.tv_nsec;
+ }
+ return r;
+}
diff --git a/lib/libc/musl/compat/time32/clock_gettime32.c b/lib/libc/musl/compat/time32/clock_gettime32.c
new file mode 100644
index 000000000..0cac7bbdf
--- /dev/null
+++ b/lib/libc/musl/compat/time32/clock_gettime32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include
+#include
+#include
+
+int __clock_gettime32(clockid_t clk, struct timespec32 *ts32)
+{
+ struct timespec ts;
+ int r = clock_gettime(clk, &ts);
+ if (r) return r;
+ if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ ts32->tv_sec = ts.tv_sec;
+ ts32->tv_nsec = ts.tv_nsec;
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/clock_nanosleep_time32.c b/lib/libc/musl/compat/time32/clock_nanosleep_time32.c
new file mode 100644
index 000000000..91ef067d0
--- /dev/null
+++ b/lib/libc/musl/compat/time32/clock_nanosleep_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include
+#include
+
+int __clock_nanosleep_time32(clockid_t clk, int flags, const struct timespec32 *req32, struct timespec32 *rem32)
+{
+ struct timespec rem;
+ int ret = clock_nanosleep(clk, flags, (&(struct timespec){
+ .tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+ if (ret==EINTR && rem32 && !(flags & TIMER_ABSTIME)) {
+ rem32->tv_sec = rem.tv_sec;
+ rem32->tv_nsec = rem.tv_nsec;
+ }
+ return ret;
+}
diff --git a/lib/libc/musl/compat/time32/clock_settime32.c b/lib/libc/musl/compat/time32/clock_settime32.c
new file mode 100644
index 000000000..7ca4f0e9c
--- /dev/null
+++ b/lib/libc/musl/compat/time32/clock_settime32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+
+int __clock_settime32(clockid_t clk, const struct timespec32 *ts32)
+{
+ return clock_settime(clk, (&(struct timespec){
+ .tv_sec = ts32->tv_sec,
+ .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/cnd_timedwait_time32.c b/lib/libc/musl/compat/time32/cnd_timedwait_time32.c
new file mode 100644
index 000000000..314251d1c
--- /dev/null
+++ b/lib/libc/musl/compat/time32/cnd_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __cnd_timedwait_time32(cnd_t *restrict c, mtx_t *restrict m, const struct timespec32 *restrict ts32)
+{
+ return cnd_timedwait(c, m, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/lib/libc/musl/compat/time32/ctime32.c b/lib/libc/musl/compat/time32/ctime32.c
new file mode 100644
index 000000000..a057274e1
--- /dev/null
+++ b/lib/libc/musl/compat/time32/ctime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include
+
+char *__ctime32(time32_t *t)
+{
+ return ctime(&(time_t){*t});
+}
diff --git a/lib/libc/musl/compat/time32/ctime32_r.c b/lib/libc/musl/compat/time32/ctime32_r.c
new file mode 100644
index 000000000..e1ad2e283
--- /dev/null
+++ b/lib/libc/musl/compat/time32/ctime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include
+
+char *__ctime32_r(time32_t *t, char *buf)
+{
+ return ctime_r(&(time_t){*t}, buf);
+}
diff --git a/lib/libc/musl/compat/time32/difftime32.c b/lib/libc/musl/compat/time32/difftime32.c
new file mode 100644
index 000000000..5950943a0
--- /dev/null
+++ b/lib/libc/musl/compat/time32/difftime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include
+
+double __difftime32(time32_t t1, time32_t t2)
+{
+ return difftime(t1, t2);
+}
diff --git a/lib/libc/musl/compat/time32/fstat_time32.c b/lib/libc/musl/compat/time32/fstat_time32.c
new file mode 100644
index 000000000..3e0843988
--- /dev/null
+++ b/lib/libc/musl/compat/time32/fstat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include
+#include
+#include
+#include
+
+struct stat32;
+
+int __fstat_time32(int fd, struct stat32 *restrict st32)
+{
+ struct stat st;
+ int r = fstat(fd, &st);
+ if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+ return r;
+}
+
+weak_alias(fstat, fstat64);
diff --git a/lib/libc/musl/compat/time32/fstatat_time32.c b/lib/libc/musl/compat/time32/fstatat_time32.c
new file mode 100644
index 000000000..85dcb008e
--- /dev/null
+++ b/lib/libc/musl/compat/time32/fstatat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include
+#include
+#include
+#include
+
+struct stat32;
+
+int __fstatat_time32(int fd, const char *restrict path, struct stat32 *restrict st32, int flag)
+{
+ struct stat st;
+ int r = fstatat(fd, path, &st, flag);
+ if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+ return r;
+}
+
+weak_alias(fstatat, fstatat64);
diff --git a/lib/libc/musl/compat/time32/ftime32.c b/lib/libc/musl/compat/time32/ftime32.c
new file mode 100644
index 000000000..166a6daeb
--- /dev/null
+++ b/lib/libc/musl/compat/time32/ftime32.c
@@ -0,0 +1,25 @@
+#include "time32.h"
+#include
+#include
+#include
+
+struct timeb32 {
+ int32_t time;
+ unsigned short millitm;
+ short timezone, dstflag;
+};
+
+int __ftime32(struct timeb32 *tp)
+{
+ struct timeb tb;
+ if (ftime(&tb) < 0) return -1;
+ if (tb.time < INT32_MIN || tb.time > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ tp->time = tb.time;
+ tp->millitm = tb.millitm;
+ tp->timezone = tb.timezone;
+ tp->dstflag = tb.dstflag;
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/futimens_time32.c b/lib/libc/musl/compat/time32/futimens_time32.c
new file mode 100644
index 000000000..7856f176e
--- /dev/null
+++ b/lib/libc/musl/compat/time32/futimens_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include
+#include
+
+int __futimens_time32(int fd, const struct timespec32 *times32)
+{
+ return futimens(fd, !times32 ? 0 : ((struct timespec[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
+ {.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}));
+}
diff --git a/lib/libc/musl/compat/time32/futimes_time32.c b/lib/libc/musl/compat/time32/futimes_time32.c
new file mode 100644
index 000000000..f29533f12
--- /dev/null
+++ b/lib/libc/musl/compat/time32/futimes_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include
+#include
+#include
+
+int __futimes_time32(int fd, const struct timeval32 times32[2])
+{
+ return futimes(fd, !times32 ? 0 : ((struct timeval[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+ {.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/lib/libc/musl/compat/time32/futimesat_time32.c b/lib/libc/musl/compat/time32/futimesat_time32.c
new file mode 100644
index 000000000..5a1295bde
--- /dev/null
+++ b/lib/libc/musl/compat/time32/futimesat_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include
+#include
+#include
+
+int __futimesat_time32(int dirfd, const char *pathname, const struct timeval32 times32[2])
+{
+ return futimesat(dirfd, pathname, !times32 ? 0 : ((struct timeval[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+ {.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/lib/libc/musl/compat/time32/getitimer_time32.c b/lib/libc/musl/compat/time32/getitimer_time32.c
new file mode 100644
index 000000000..4bac4bf52
--- /dev/null
+++ b/lib/libc/musl/compat/time32/getitimer_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include
+#include
+
+int __getitimer_time32(int which, struct itimerval32 *old32)
+{
+ struct itimerval old;
+ int r = getitimer(which, &old);
+ if (r) return r;
+ old32->it_interval.tv_sec = old.it_interval.tv_sec;
+ old32->it_interval.tv_usec = old.it_interval.tv_usec;
+ old32->it_value.tv_sec = old.it_value.tv_sec;
+ old32->it_value.tv_usec = old.it_value.tv_usec;
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/getrusage_time32.c b/lib/libc/musl/compat/time32/getrusage_time32.c
new file mode 100644
index 000000000..d7487dee6
--- /dev/null
+++ b/lib/libc/musl/compat/time32/getrusage_time32.c
@@ -0,0 +1,39 @@
+#include "time32.h"
+#include
+#include
+#include
+
+struct compat_rusage {
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
+ long ru_maxrss;
+ long ru_ixrss;
+ long ru_idrss;
+ long ru_isrss;
+ long ru_minflt;
+ long ru_majflt;
+ long ru_nswap;
+ long ru_inblock;
+ long ru_oublock;
+ long ru_msgsnd;
+ long ru_msgrcv;
+ long ru_nsignals;
+ long ru_nvcsw;
+ long ru_nivcsw;
+};
+
+int __getrusage_time32(int who, struct compat_rusage *usage)
+{
+ struct rusage ru;
+ int r = getrusage(who, &ru);
+ if (!r) {
+ usage->ru_utime.tv_sec = ru.ru_utime.tv_sec;
+ usage->ru_utime.tv_usec = ru.ru_utime.tv_usec;
+ usage->ru_stime.tv_sec = ru.ru_stime.tv_sec;
+ usage->ru_stime.tv_usec = ru.ru_stime.tv_usec;
+ memcpy(&usage->ru_maxrss, &ru.ru_maxrss,
+ sizeof(struct compat_rusage) -
+ offsetof(struct compat_rusage, ru_maxrss));
+ }
+ return r;
+}
diff --git a/lib/libc/musl/compat/time32/gettimeofday_time32.c b/lib/libc/musl/compat/time32/gettimeofday_time32.c
new file mode 100644
index 000000000..1f3ce68e3
--- /dev/null
+++ b/lib/libc/musl/compat/time32/gettimeofday_time32.c
@@ -0,0 +1,19 @@
+#include "time32.h"
+#include
+#include
+#include
+
+int __gettimeofday_time32(struct timeval32 *tv32, void *tz)
+{
+ struct timeval tv;
+ if (!tv32) return 0;
+ int r = gettimeofday(&tv, 0);
+ if (r) return r;
+ if (tv.tv_sec < INT32_MIN || tv.tv_sec > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ tv32->tv_sec = tv.tv_sec;
+ tv32->tv_usec = tv.tv_usec;
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/gmtime32.c b/lib/libc/musl/compat/time32/gmtime32.c
new file mode 100644
index 000000000..963f0e052
--- /dev/null
+++ b/lib/libc/musl/compat/time32/gmtime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include
+
+struct tm *__gmtime32(time32_t *t)
+{
+ return gmtime(&(time_t){*t});
+}
diff --git a/lib/libc/musl/compat/time32/gmtime32_r.c b/lib/libc/musl/compat/time32/gmtime32_r.c
new file mode 100644
index 000000000..7d72bfb32
--- /dev/null
+++ b/lib/libc/musl/compat/time32/gmtime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include
+
+struct tm *__gmtime32_r(time32_t *t, struct tm *tm)
+{
+ return gmtime_r(&(time_t){*t}, tm);
+}
diff --git a/lib/libc/musl/compat/time32/localtime32.c b/lib/libc/musl/compat/time32/localtime32.c
new file mode 100644
index 000000000..96bc30349
--- /dev/null
+++ b/lib/libc/musl/compat/time32/localtime32.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include
+
+struct tm *__localtime32(time32_t *t)
+{
+ return localtime(&(time_t){*t});
+}
diff --git a/lib/libc/musl/compat/time32/localtime32_r.c b/lib/libc/musl/compat/time32/localtime32_r.c
new file mode 100644
index 000000000..633ec8293
--- /dev/null
+++ b/lib/libc/musl/compat/time32/localtime32_r.c
@@ -0,0 +1,7 @@
+#include "time32.h"
+#include
+
+struct tm *__localtime32_r(time32_t *t, struct tm *tm)
+{
+ return localtime_r(&(time_t){*t}, tm);
+}
diff --git a/lib/libc/musl/compat/time32/lstat_time32.c b/lib/libc/musl/compat/time32/lstat_time32.c
new file mode 100644
index 000000000..c1257a144
--- /dev/null
+++ b/lib/libc/musl/compat/time32/lstat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include
+#include
+#include
+#include
+
+struct stat32;
+
+int __lstat_time32(const char *restrict path, struct stat32 *restrict st32)
+{
+ struct stat st;
+ int r = lstat(path, &st);
+ if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+ return r;
+}
+
+weak_alias(lstat, lstat64);
diff --git a/lib/libc/musl/compat/time32/lutimes_time32.c b/lib/libc/musl/compat/time32/lutimes_time32.c
new file mode 100644
index 000000000..7f75cd4a1
--- /dev/null
+++ b/lib/libc/musl/compat/time32/lutimes_time32.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include
+#include
+#include
+
+int __lutimes_time32(const char *path, const struct timeval32 times32[2])
+{
+ return lutimes(path, !times32 ? 0 : ((struct timeval[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+ {.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/lib/libc/musl/compat/time32/mktime32.c b/lib/libc/musl/compat/time32/mktime32.c
new file mode 100644
index 000000000..e6f15d513
--- /dev/null
+++ b/lib/libc/musl/compat/time32/mktime32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include
+#include
+#include
+
+time32_t __mktime32(struct tm *tm)
+{
+ struct tm tmp = *tm;
+ time_t t = mktime(&tmp);
+ if (t < INT32_MIN || t > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ *tm = tmp;
+ return t;
+}
diff --git a/lib/libc/musl/compat/time32/mq_timedreceive_time32.c b/lib/libc/musl/compat/time32/mq_timedreceive_time32.c
new file mode 100644
index 000000000..211cea4ba
--- /dev/null
+++ b/lib/libc/musl/compat/time32/mq_timedreceive_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+ssize_t __mq_timedreceive_time32(mqd_t mqd, char *restrict msg, size_t len, unsigned *restrict prio, const struct timespec32 *restrict ts32)
+{
+ return mq_timedreceive(mqd, msg, len, prio, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/lib/libc/musl/compat/time32/mq_timedsend_time32.c b/lib/libc/musl/compat/time32/mq_timedsend_time32.c
new file mode 100644
index 000000000..93b697a7e
--- /dev/null
+++ b/lib/libc/musl/compat/time32/mq_timedsend_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __mq_timedsend_time32(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec32 *ts32)
+{
+ return mq_timedsend(mqd, msg, len, prio, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/lib/libc/musl/compat/time32/mtx_timedlock_time32.c b/lib/libc/musl/compat/time32/mtx_timedlock_time32.c
new file mode 100644
index 000000000..a01f09b89
--- /dev/null
+++ b/lib/libc/musl/compat/time32/mtx_timedlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __mtx_timedlock_time32(mtx_t *restrict m, const struct timespec32 *restrict ts32)
+{
+ return mtx_timedlock(m, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/nanosleep_time32.c b/lib/libc/musl/compat/time32/nanosleep_time32.c
new file mode 100644
index 000000000..ea6bdd81b
--- /dev/null
+++ b/lib/libc/musl/compat/time32/nanosleep_time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include
+#include
+
+int __nanosleep_time32(const struct timespec32 *req32, struct timespec32 *rem32)
+{
+ struct timespec rem;
+ int ret = nanosleep((&(struct timespec){
+ .tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+ if (ret<0 && errno==EINTR && rem32) {
+ rem32->tv_sec = rem.tv_sec;
+ rem32->tv_nsec = rem.tv_nsec;
+ }
+ return ret;
+}
diff --git a/lib/libc/musl/compat/time32/ppoll_time32.c b/lib/libc/musl/compat/time32/ppoll_time32.c
new file mode 100644
index 000000000..43b4b0df6
--- /dev/null
+++ b/lib/libc/musl/compat/time32/ppoll_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include
+#include
+
+int __ppoll_time32(struct pollfd *fds, nfds_t n, const struct timespec32 *ts32, const sigset_t *mask)
+{
+ return ppoll(fds, n, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
+}
diff --git a/lib/libc/musl/compat/time32/pselect_time32.c b/lib/libc/musl/compat/time32/pselect_time32.c
new file mode 100644
index 000000000..ecaa8f868
--- /dev/null
+++ b/lib/libc/musl/compat/time32/pselect_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __pselect_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, const struct timespec32 *restrict ts32, const sigset_t *restrict mask)
+{
+ return pselect(n, rfds, wfds, efds, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}), mask);
+}
diff --git a/lib/libc/musl/compat/time32/pthread_cond_timedwait_time32.c b/lib/libc/musl/compat/time32/pthread_cond_timedwait_time32.c
new file mode 100644
index 000000000..fba1f2a91
--- /dev/null
+++ b/lib/libc/musl/compat/time32/pthread_cond_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __pthread_cond_timedwait_time32(pthread_cond_t *restrict c, pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
+{
+ return pthread_cond_timedwait(c, m, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/pthread_mutex_timedlock_time32.c b/lib/libc/musl/compat/time32/pthread_mutex_timedlock_time32.c
new file mode 100644
index 000000000..2d29602cb
--- /dev/null
+++ b/lib/libc/musl/compat/time32/pthread_mutex_timedlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __pthread_mutex_timedlock_time32(pthread_mutex_t *restrict m, const struct timespec32 *restrict ts32)
+{
+ return pthread_mutex_timedlock(m, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/pthread_rwlock_timedrdlock_time32.c b/lib/libc/musl/compat/time32/pthread_rwlock_timedrdlock_time32.c
new file mode 100644
index 000000000..33df27a4a
--- /dev/null
+++ b/lib/libc/musl/compat/time32/pthread_rwlock_timedrdlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __pthread_rwlock_timedrdlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
+{
+ return pthread_rwlock_timedrdlock(rw, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/pthread_rwlock_timedwrlock_time32.c b/lib/libc/musl/compat/time32/pthread_rwlock_timedwrlock_time32.c
new file mode 100644
index 000000000..99f24f734
--- /dev/null
+++ b/lib/libc/musl/compat/time32/pthread_rwlock_timedwrlock_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __pthread_rwlock_timedwrlock_time32(pthread_rwlock_t *restrict rw, const struct timespec32 *restrict ts32)
+{
+ return pthread_rwlock_timedwrlock(rw, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/pthread_timedjoin_np_time32.c b/lib/libc/musl/compat/time32/pthread_timedjoin_np_time32.c
new file mode 100644
index 000000000..3ec299511
--- /dev/null
+++ b/lib/libc/musl/compat/time32/pthread_timedjoin_np_time32.c
@@ -0,0 +1,10 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include
+#include
+
+int __pthread_timedjoin_np_time32(pthread_t t, void **res, const struct timespec32 *at32)
+{
+ return pthread_timedjoin_np(t, res, !at32 ? 0 : (&(struct timespec){
+ .tv_sec = at32->tv_sec, .tv_nsec = at32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/recvmmsg_time32.c b/lib/libc/musl/compat/time32/recvmmsg_time32.c
new file mode 100644
index 000000000..acf1cfb8c
--- /dev/null
+++ b/lib/libc/musl/compat/time32/recvmmsg_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include
+#include
+
+int __recvmmsg_time32(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec32 *ts32)
+{
+ return recvmmsg(fd, msgvec, vlen, flags, ts32 ? (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}) : 0);
+}
diff --git a/lib/libc/musl/compat/time32/sched_rr_get_interval_time32.c b/lib/libc/musl/compat/time32/sched_rr_get_interval_time32.c
new file mode 100644
index 000000000..36cbbaca0
--- /dev/null
+++ b/lib/libc/musl/compat/time32/sched_rr_get_interval_time32.c
@@ -0,0 +1,13 @@
+#include "time32.h"
+#include
+#include
+
+int __sched_rr_get_interval_time32(pid_t pid, struct timespec32 *ts32)
+{
+ struct timespec ts;
+ int r = sched_rr_get_interval(pid, &ts);
+ if (r) return r;
+ ts32->tv_sec = ts.tv_sec;
+ ts32->tv_nsec = ts.tv_nsec;
+ return r;
+}
diff --git a/lib/libc/musl/compat/time32/select_time32.c b/lib/libc/musl/compat/time32/select_time32.c
new file mode 100644
index 000000000..2d8df9aca
--- /dev/null
+++ b/lib/libc/musl/compat/time32/select_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#include
+#include
+#include
+
+int __select_time32(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval32 *restrict tv32)
+{
+ return select(n, rfds, wfds, efds, !tv32 ? 0 : (&(struct timeval){
+ .tv_sec = tv32->tv_sec, .tv_usec = tv32->tv_usec}));
+}
diff --git a/lib/libc/musl/compat/time32/sem_timedwait_time32.c b/lib/libc/musl/compat/time32/sem_timedwait_time32.c
new file mode 100644
index 000000000..c3469f9bc
--- /dev/null
+++ b/lib/libc/musl/compat/time32/sem_timedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __sem_timedwait_time32(sem_t *sem, const struct timespec32 *restrict ts32)
+{
+ return sem_timedwait(sem, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/semtimedop_time32.c b/lib/libc/musl/compat/time32/semtimedop_time32.c
new file mode 100644
index 000000000..34ec52819
--- /dev/null
+++ b/lib/libc/musl/compat/time32/semtimedop_time32.c
@@ -0,0 +1,10 @@
+#include "time32.h"
+#define _GNU_SOURCE
+#include
+#include
+
+int __semtimedop_time32(int id, struct sembuf *buf, size_t n, const struct timespec32 *ts32)
+{
+ return semtimedop(id, buf, n, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/setitimer_time32.c b/lib/libc/musl/compat/time32/setitimer_time32.c
new file mode 100644
index 000000000..2475fd8c1
--- /dev/null
+++ b/lib/libc/musl/compat/time32/setitimer_time32.c
@@ -0,0 +1,25 @@
+#include "time32.h"
+#include
+#include
+
+int __setitimer_time32(int which, const struct itimerval32 *restrict new32, struct itimerval32 *restrict old32)
+{
+ struct itimerval old;
+ int r = setitimer(which, (&(struct itimerval){
+ .it_interval.tv_sec = new32->it_interval.tv_sec,
+ .it_interval.tv_usec = new32->it_interval.tv_usec,
+ .it_value.tv_sec = new32->it_value.tv_sec,
+ .it_value.tv_usec = new32->it_value.tv_usec}), &old);
+ if (r) return r;
+ /* The above call has already committed to success by changing the
+ * timer setting, so we can't fail on out-of-range old value.
+ * Since these are relative times, values large enough to overflow
+ * don't make sense anyway. */
+ if (old32) {
+ old32->it_interval.tv_sec = old.it_interval.tv_sec;
+ old32->it_interval.tv_usec = old.it_interval.tv_usec;
+ old32->it_value.tv_sec = old.it_value.tv_sec;
+ old32->it_value.tv_usec = old.it_value.tv_usec;
+ }
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/settimeofday_time32.c b/lib/libc/musl/compat/time32/settimeofday_time32.c
new file mode 100644
index 000000000..09e625cba
--- /dev/null
+++ b/lib/libc/musl/compat/time32/settimeofday_time32.c
@@ -0,0 +1,10 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include
+
+int __settimeofday_time32(const struct timeval32 *tv32, const void *tz)
+{
+ return settimeofday(!tv32 ? 0 : (&(struct timeval){
+ .tv_sec = tv32->tv_sec,
+ .tv_usec = tv32->tv_usec}), 0);
+}
diff --git a/lib/libc/musl/compat/time32/sigtimedwait_time32.c b/lib/libc/musl/compat/time32/sigtimedwait_time32.c
new file mode 100644
index 000000000..6b3aa39c7
--- /dev/null
+++ b/lib/libc/musl/compat/time32/sigtimedwait_time32.c
@@ -0,0 +1,9 @@
+#include "time32.h"
+#include
+#include
+
+int __sigtimedwait_time32(const sigset_t *restrict set, siginfo_t *restrict si, const struct timespec32 *restrict ts32)
+{
+ return sigtimedwait(set, si, !ts32 ? 0 : (&(struct timespec){
+ .tv_sec = ts32->tv_sec, .tv_nsec = ts32->tv_nsec}));
+}
diff --git a/lib/libc/musl/compat/time32/stat_time32.c b/lib/libc/musl/compat/time32/stat_time32.c
new file mode 100644
index 000000000..8c6121dad
--- /dev/null
+++ b/lib/libc/musl/compat/time32/stat_time32.c
@@ -0,0 +1,17 @@
+#include "time32.h"
+#include
+#include
+#include
+#include
+
+struct stat32;
+
+int __stat_time32(const char *restrict path, struct stat32 *restrict st32)
+{
+ struct stat st;
+ int r = stat(path, &st);
+ if (!r) memcpy(st32, &st, offsetof(struct stat, st_atim));
+ return r;
+}
+
+weak_alias(stat, stat64);
diff --git a/lib/libc/musl/compat/time32/stime32.c b/lib/libc/musl/compat/time32/stime32.c
new file mode 100644
index 000000000..cc76364d3
--- /dev/null
+++ b/lib/libc/musl/compat/time32/stime32.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include
+
+int __stime32(const time32_t *t)
+{
+ return stime(&(time_t){*t});
+}
diff --git a/lib/libc/musl/compat/time32/thrd_sleep_time32.c b/lib/libc/musl/compat/time32/thrd_sleep_time32.c
new file mode 100644
index 000000000..59088001b
--- /dev/null
+++ b/lib/libc/musl/compat/time32/thrd_sleep_time32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include
+#include
+#include
+
+int __thrd_sleep_time32(const struct timespec32 *req32, struct timespec32 *rem32)
+{
+ struct timespec rem;
+ int ret = thrd_sleep((&(struct timespec){
+ .tv_sec = req32->tv_sec, .tv_nsec = req32->tv_nsec}), &rem);
+ if (ret<0 && errno==EINTR && rem32) {
+ rem32->tv_sec = rem.tv_sec;
+ rem32->tv_nsec = rem.tv_nsec;
+ }
+ return ret;
+}
diff --git a/lib/libc/musl/compat/time32/time32.c b/lib/libc/musl/compat/time32/time32.c
new file mode 100644
index 000000000..4b8fac1c2
--- /dev/null
+++ b/lib/libc/musl/compat/time32/time32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include
+#include
+#include
+
+time32_t __time32(time32_t *p)
+{
+ time_t t = time(0);
+ if (t < INT32_MIN || t > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ if (p) *p = t;
+ return t;
+}
diff --git a/lib/libc/musl/compat/time32/time32.h b/lib/libc/musl/compat/time32/time32.h
new file mode 100644
index 000000000..fdec17c34
--- /dev/null
+++ b/lib/libc/musl/compat/time32/time32.h
@@ -0,0 +1,91 @@
+#ifndef TIME32_H
+#define TIME32_H
+
+#include
+
+typedef long time32_t;
+
+struct timeval32 {
+ long tv_sec;
+ long tv_usec;
+};
+
+struct itimerval32 {
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+struct timespec32 {
+ long tv_sec;
+ long tv_nsec;
+};
+
+struct itimerspec32 {
+ struct timespec32 it_interval;
+ struct timespec32 it_value;
+};
+
+int __adjtime32() __asm__("adjtime");
+int __adjtimex_time32() __asm__("adjtimex");
+int __aio_suspend_time32() __asm__("aio_suspend");
+int __clock_adjtime32() __asm__("clock_adjtime");
+int __clock_getres_time32() __asm__("clock_getres");
+int __clock_gettime32() __asm__("clock_gettime");
+int __clock_nanosleep_time32() __asm__("clock_nanosleep");
+int __clock_settime32() __asm__("clock_settime");
+int __cnd_timedwait_time32() __asm__("cnd_timedwait");
+char *__ctime32() __asm__("ctime");
+char *__ctime32_r() __asm__("ctime_r");
+double __difftime32() __asm__("difftime");
+int __fstat_time32() __asm__("fstat");
+int __fstatat_time32() __asm__("fstatat");
+int __ftime32() __asm__("ftime");
+int __futimens_time32() __asm__("futimens");
+int __futimes_time32() __asm__("futimes");
+int __futimesat_time32() __asm__("futimesat");
+int __getitimer_time32() __asm__("getitimer");
+int __getrusage_time32() __asm__("getrusage");
+int __gettimeofday_time32() __asm__("gettimeofday");
+struct tm *__gmtime32() __asm__("gmtime");
+struct tm *__gmtime32_r() __asm__("gmtime_r");
+struct tm *__localtime32() __asm__("localtime");
+struct tm *__localtime32_r() __asm__("localtime_r");
+int __lstat_time32() __asm__("lstat");
+int __lutimes_time32() __asm__("lutimes");
+time32_t __mktime32() __asm__("mktime");
+ssize_t __mq_timedreceive_time32() __asm__("mq_timedreceive");
+int __mq_timedsend_time32() __asm__("mq_timedsend");
+int __mtx_timedlock_time32() __asm__("mtx_timedlock");
+int __nanosleep_time32() __asm__("nanosleep");
+int __ppoll_time32() __asm__("ppoll");
+int __pselect_time32() __asm__("pselect");
+int __pthread_cond_timedwait_time32() __asm__("pthread_cond_timedwait");
+int __pthread_mutex_timedlock_time32() __asm__("pthread_mutex_timedlock");
+int __pthread_rwlock_timedrdlock_time32() __asm__("pthread_rwlock_timedrdlock");
+int __pthread_rwlock_timedwrlock_time32() __asm__("pthread_rwlock_timedwrlock");
+int __pthread_timedjoin_np_time32() __asm__("pthread_timedjoin_np");
+int __recvmmsg_time32() __asm__("recvmmsg");
+int __sched_rr_get_interval_time32() __asm__("sched_rr_get_interval");
+int __select_time32() __asm__("select");
+int __sem_timedwait_time32() __asm__("sem_timedwait");
+int __semtimedop_time32() __asm__("semtimedop");
+int __setitimer_time32() __asm__("setitimer");
+int __settimeofday_time32() __asm__("settimeofday");
+int __sigtimedwait_time32() __asm__("sigtimedwait");
+int __stat_time32() __asm__("stat");
+int __stime32() __asm__("stime");
+int __thrd_sleep_time32() __asm__("thrd_sleep");
+time32_t __time32() __asm__("time");
+time32_t __time32gm() __asm__("timegm");
+int __timer_gettime32() __asm__("timer_gettime");
+int __timer_settime32() __asm__("timer_settime");
+int __timerfd_gettime32() __asm__("timerfd_gettime");
+int __timerfd_settime32() __asm__("timerfd_settime");
+int __timespec_get_time32() __asm__("timespec_get");
+int __utime_time32() __asm__("utime");
+int __utimensat_time32() __asm__("utimensat");
+int __utimes_time32() __asm__("utimes");
+pid_t __wait3_time32() __asm__("wait3");
+pid_t __wait4_time32() __asm__("wait4");
+
+#endif
diff --git a/lib/libc/musl/compat/time32/time32gm.c b/lib/libc/musl/compat/time32/time32gm.c
new file mode 100644
index 000000000..60d68fbf8
--- /dev/null
+++ b/lib/libc/musl/compat/time32/time32gm.c
@@ -0,0 +1,15 @@
+#define _GNU_SOURCE
+#include "time32.h"
+#include
+#include
+#include
+
+time32_t __time32gm(struct tm *tm)
+{
+ time_t t = timegm(tm);
+ if (t < INT32_MIN || t > INT32_MAX) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+ return t;
+}
diff --git a/lib/libc/musl/compat/time32/timer_gettime32.c b/lib/libc/musl/compat/time32/timer_gettime32.c
new file mode 100644
index 000000000..b4184cc28
--- /dev/null
+++ b/lib/libc/musl/compat/time32/timer_gettime32.c
@@ -0,0 +1,15 @@
+#include "time32.h"
+#include
+
+int __timer_gettime32(timer_t t, struct itimerspec32 *val32)
+{
+ struct itimerspec old;
+ int r = timer_gettime(t, &old);
+ if (r) return r;
+ /* No range checking for consistency with settime */
+ val32->it_interval.tv_sec = old.it_interval.tv_sec;
+ val32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+ val32->it_value.tv_sec = old.it_value.tv_sec;
+ val32->it_value.tv_nsec = old.it_value.tv_nsec;
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/timer_settime32.c b/lib/libc/musl/compat/time32/timer_settime32.c
new file mode 100644
index 000000000..a447e7d41
--- /dev/null
+++ b/lib/libc/musl/compat/time32/timer_settime32.c
@@ -0,0 +1,25 @@
+#include "time32.h"
+#include
+
+int __timer_settime32(timer_t t, int flags, const struct itimerspec32 *restrict val32, struct itimerspec32 *restrict old32)
+{
+ struct itimerspec old;
+ int r = timer_settime(t, flags, (&(struct itimerspec){
+ .it_interval.tv_sec = val32->it_interval.tv_sec,
+ .it_interval.tv_nsec = val32->it_interval.tv_nsec,
+ .it_value.tv_sec = val32->it_value.tv_sec,
+ .it_value.tv_nsec = val32->it_value.tv_nsec}),
+ old32 ? &old : 0);
+ if (r) return r;
+ /* The above call has already committed to success by changing the
+ * timer setting, so we can't fail on out-of-range old value.
+ * Since these are relative times, values large enough to overflow
+ * don't make sense anyway. */
+ if (old32) {
+ old32->it_interval.tv_sec = old.it_interval.tv_sec;
+ old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+ old32->it_value.tv_sec = old.it_value.tv_sec;
+ old32->it_value.tv_nsec = old.it_value.tv_nsec;
+ }
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/timerfd_gettime32.c b/lib/libc/musl/compat/time32/timerfd_gettime32.c
new file mode 100644
index 000000000..75e5435f1
--- /dev/null
+++ b/lib/libc/musl/compat/time32/timerfd_gettime32.c
@@ -0,0 +1,16 @@
+#include "time32.h"
+#include
+#include
+
+int __timerfd_gettime32(int t, struct itimerspec32 *val32)
+{
+ struct itimerspec old;
+ int r = timerfd_gettime(t, &old);
+ if (r) return r;
+ /* No range checking for consistency with settime */
+ val32->it_interval.tv_sec = old.it_interval.tv_sec;
+ val32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+ val32->it_value.tv_sec = old.it_value.tv_sec;
+ val32->it_value.tv_nsec = old.it_value.tv_nsec;
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/timerfd_settime32.c b/lib/libc/musl/compat/time32/timerfd_settime32.c
new file mode 100644
index 000000000..67830d341
--- /dev/null
+++ b/lib/libc/musl/compat/time32/timerfd_settime32.c
@@ -0,0 +1,26 @@
+#include "time32.h"
+#include
+#include
+
+int __timerfd_settime32(int t, int flags, const struct itimerspec32 *restrict val32, struct itimerspec32 *restrict old32)
+{
+ struct itimerspec old;
+ int r = timerfd_settime(t, flags, (&(struct itimerspec){
+ .it_interval.tv_sec = val32->it_interval.tv_sec,
+ .it_interval.tv_nsec = val32->it_interval.tv_nsec,
+ .it_value.tv_sec = val32->it_value.tv_sec,
+ .it_value.tv_nsec = val32->it_value.tv_nsec}),
+ old32 ? &old : 0);
+ if (r) return r;
+ /* The above call has already committed to success by changing the
+ * timer setting, so we can't fail on out-of-range old value.
+ * Since these are relative times, values large enough to overflow
+ * don't make sense anyway. */
+ if (old32) {
+ old32->it_interval.tv_sec = old.it_interval.tv_sec;
+ old32->it_interval.tv_nsec = old.it_interval.tv_nsec;
+ old32->it_value.tv_sec = old.it_value.tv_sec;
+ old32->it_value.tv_nsec = old.it_value.tv_nsec;
+ }
+ return 0;
+}
diff --git a/lib/libc/musl/compat/time32/timespec_get_time32.c b/lib/libc/musl/compat/time32/timespec_get_time32.c
new file mode 100644
index 000000000..e9ca94cb4
--- /dev/null
+++ b/lib/libc/musl/compat/time32/timespec_get_time32.c
@@ -0,0 +1,18 @@
+#include "time32.h"
+#include
+#include
+#include
+
+int __timespec_get_time32(struct timespec32 *ts32, int base)
+{
+ struct timespec ts;
+ int r = timespec_get(&ts, base);
+ if (!r) return r;
+ if (ts.tv_sec < INT32_MIN || ts.tv_sec > INT32_MAX) {
+ errno = EOVERFLOW;
+ return 0;
+ }
+ ts32->tv_sec = ts.tv_sec;
+ ts32->tv_nsec = ts.tv_nsec;
+ return r;
+}
diff --git a/lib/libc/musl/compat/time32/utime_time32.c b/lib/libc/musl/compat/time32/utime_time32.c
new file mode 100644
index 000000000..65f11d463
--- /dev/null
+++ b/lib/libc/musl/compat/time32/utime_time32.c
@@ -0,0 +1,14 @@
+#include "time32.h"
+#include
+#include
+
+struct utimbuf32 {
+ time32_t actime;
+ time32_t modtime;
+};
+
+int __utime_time32(const char *path, const struct utimbuf32 *times32)
+{
+ return utime(path, !times32 ? 0 : (&(struct utimbuf){
+ .actime = times32->actime, .modtime = times32->modtime}));
+}
diff --git a/lib/libc/musl/compat/time32/utimensat_time32.c b/lib/libc/musl/compat/time32/utimensat_time32.c
new file mode 100644
index 000000000..c687b8d1b
--- /dev/null
+++ b/lib/libc/musl/compat/time32/utimensat_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include
+#include
+
+int __utimensat_time32(int fd, const char *path, const struct timespec32 times32[2], int flags)
+{
+ return utimensat(fd, path, !times32 ? 0 : ((struct timespec[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_nsec = times32[0].tv_nsec},
+ {.tv_sec = times32[1].tv_sec,.tv_nsec = times32[1].tv_nsec}}),
+ flags);
+}
diff --git a/lib/libc/musl/compat/time32/utimes_time32.c b/lib/libc/musl/compat/time32/utimes_time32.c
new file mode 100644
index 000000000..59248f623
--- /dev/null
+++ b/lib/libc/musl/compat/time32/utimes_time32.c
@@ -0,0 +1,11 @@
+#include "time32.h"
+#include
+#include
+#include
+
+int __utimes_time32(const char *path, const struct timeval32 times32[2])
+{
+ return utimes(path, !times32 ? 0 : ((struct timeval[2]){
+ {.tv_sec = times32[0].tv_sec,.tv_usec = times32[0].tv_usec},
+ {.tv_sec = times32[1].tv_sec,.tv_usec = times32[1].tv_usec}}));
+}
diff --git a/lib/libc/musl/compat/time32/wait3_time32.c b/lib/libc/musl/compat/time32/wait3_time32.c
new file mode 100644
index 000000000..8fe128edb
--- /dev/null
+++ b/lib/libc/musl/compat/time32/wait3_time32.c
@@ -0,0 +1,40 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include
+#include
+#include
+
+struct compat_rusage {
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
+ long ru_maxrss;
+ long ru_ixrss;
+ long ru_idrss;
+ long ru_isrss;
+ long ru_minflt;
+ long ru_majflt;
+ long ru_nswap;
+ long ru_inblock;
+ long ru_oublock;
+ long ru_msgsnd;
+ long ru_msgrcv;
+ long ru_nsignals;
+ long ru_nvcsw;
+ long ru_nivcsw;
+};
+
+pid_t __wait3_time32(int *status, int options, struct compat_rusage *usage)
+{
+ struct rusage ru;
+ int r = wait3(status, options, usage ? &ru : 0);
+ if (!r && usage) {
+ usage->ru_utime.tv_sec = ru.ru_utime.tv_sec;
+ usage->ru_utime.tv_usec = ru.ru_utime.tv_usec;
+ usage->ru_stime.tv_sec = ru.ru_stime.tv_sec;
+ usage->ru_stime.tv_usec = ru.ru_stime.tv_usec;
+ memcpy(&usage->ru_maxrss, &ru.ru_maxrss,
+ sizeof(struct compat_rusage) -
+ offsetof(struct compat_rusage, ru_maxrss));
+ }
+ return r;
+}
diff --git a/lib/libc/musl/compat/time32/wait4_time32.c b/lib/libc/musl/compat/time32/wait4_time32.c
new file mode 100644
index 000000000..918548e74
--- /dev/null
+++ b/lib/libc/musl/compat/time32/wait4_time32.c
@@ -0,0 +1,40 @@
+#define _BSD_SOURCE
+#include "time32.h"
+#include
+#include
+#include