Merge remote-tracking branch 'origin/more' into wrangle-writer-buffering

This commit is contained in:
Andrew Kelley 2025-07-18 18:22:14 -07:00
commit 5d2faeb8f3
47 changed files with 1261 additions and 867 deletions

View File

@ -49,10 +49,13 @@ unset CXX
ninja install
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-debug/bin/zig build test-cases test-modules test-unit test-standalone test-c-abi test-link test-stack-traces test-asm-link test-llvm-ir docs \
--maxrss 34359738368 \
stage3-debug/bin/zig build test-cases test-modules test-unit test-standalone test-c-abi test-link test-stack-traces test-asm-link test-llvm-ir \
--maxrss 68719476736 \
-Dstatic-llvm \
-Dskip-non-native \
-Dskip-single-threaded \
-Dskip-translate-c \
-Dskip-run-translated-c \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib"

View File

@ -49,10 +49,13 @@ unset CXX
ninja install
# No -fqemu and -fwasmtime here as they're covered by the x86_64-linux scripts.
stage3-release/bin/zig build test-cases test-modules test-unit test-standalone test-c-abi test-link test-stack-traces test-asm-link test-llvm-ir docs \
--maxrss 34359738368 \
stage3-release/bin/zig build test-cases test-modules test-unit test-standalone test-c-abi test-link test-stack-traces test-asm-link test-llvm-ir \
--maxrss 68719476736 \
-Dstatic-llvm \
-Dskip-non-native \
-Dskip-single-threaded \
-Dskip-translate-c \
-Dskip-run-translated-c \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib"

View File

@ -1824,7 +1824,7 @@ pub fn main() !void {
};
defer tree.deinit(gpa);
const formatted = try tree.render(arena);
const formatted = try tree.renderAlloc(arena);
try std.fs.File.stdout().writeAll(formatted);
return std.process.cleanExit();
}

View File

@ -10,6 +10,9 @@ const assert = std.debug.assert;
const fatal = std.process.fatal;
const Server = std.zig.Server;
var stdin_buffer: [1024]u8 = undefined;
var stdout_buffer: [1024]u8 = undefined;
pub fn main() !void {
var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena_instance.deinit();
@ -22,11 +25,8 @@ pub fn main() !void {
return cmdObjCopy(gpa, arena, args[1..]);
}
fn cmdObjCopy(
gpa: Allocator,
arena: Allocator,
args: []const []const u8,
) !void {
fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
_ = gpa;
var i: usize = 0;
var opt_out_fmt: ?std.Target.ObjectFormat = null;
var opt_input: ?[]const u8 = null;
@ -225,13 +225,13 @@ fn cmdObjCopy(
}
if (listen) {
var stdin_reader = fs.File.stdin().reader(&stdin_buffer);
var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
var server = try Server.init(.{
.gpa = gpa,
.in = .stdin(),
.out = .stdout(),
.in = &stdin_reader.interface,
.out = &stdout_writer.interface,
.zig_version = builtin.zig_version_string,
});
defer server.deinit();
var seen_update = false;
while (true) {

View File

@ -13,6 +13,8 @@ const hasDisjointCodePage = @import("disjoint_code_page.zig").hasDisjointCodePag
const fmtResourceType = @import("res.zig").NameOrOrdinal.fmtResourceType;
const aro = @import("aro");
var stdout_buffer: [1024]u8 = undefined;
pub fn main() !void {
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
defer std.debug.assert(gpa.deinit() == .ok);
@ -41,12 +43,12 @@ pub fn main() !void {
cli_args = args[3..];
}
var stdout_writer2 = std.fs.File.stdout().writer(&stdout_buffer);
var error_handler: ErrorHandler = switch (zig_integration) {
true => .{
.server = .{
.out = std.fs.File.stdout(),
.out = &stdout_writer2.interface,
.in = undefined, // won't be receiving messages
.receive_fifo = undefined, // won't be receiving messages
},
},
false => .{

View File

@ -10,6 +10,7 @@ const arch = builtin.cpu.arch;
const math = std.math;
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const common = @import("common.zig");
pub const panic = common.panic;
@ -211,32 +212,100 @@ pub fn expl(x: c_longdouble) callconv(.c) c_longdouble {
}
}
test "exp32" {
const epsilon = 0.000001;
try expect(expf(0.0) == 1.0);
try expect(math.approxEqAbs(f32, expf(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f32, expf(0.2), 1.221403, epsilon));
try expect(math.approxEqAbs(f32, expf(0.8923), 2.440737, epsilon));
try expect(math.approxEqAbs(f32, expf(1.5), 4.481689, epsilon));
}
test "exp64" {
const epsilon = 0.000001;
try expect(exp(0.0) == 1.0);
try expect(math.approxEqAbs(f64, exp(0.0), 1.0, epsilon));
try expect(math.approxEqAbs(f64, exp(0.2), 1.221403, epsilon));
try expect(math.approxEqAbs(f64, exp(0.8923), 2.440737, epsilon));
try expect(math.approxEqAbs(f64, exp(1.5), 4.481689, epsilon));
}
test "exp32.special" {
try expect(math.isPositiveInf(expf(math.inf(f32))));
test "expf() special" {
try expectEqual(expf(0.0), 1.0);
try expectEqual(expf(-0.0), 1.0);
try expectEqual(expf(1.0), math.e);
try expectEqual(expf(math.ln2), 2.0);
try expectEqual(expf(math.inf(f32)), math.inf(f32));
try expect(math.isPositiveZero(expf(-math.inf(f32))));
try expect(math.isNan(expf(math.nan(f32))));
try expect(math.isNan(expf(math.snan(f32))));
}
test "exp64.special" {
try expect(math.isPositiveInf(exp(math.inf(f64))));
try expect(math.isNan(exp(math.nan(f64))));
test "expf() sanity" {
try expectEqual(expf(-0x1.0223a0p+3), 0x1.490320p-12);
try expectEqual(expf(0x1.161868p+2), 0x1.34712ap+6);
try expectEqual(expf(-0x1.0c34b4p+3), 0x1.e06b1ap-13);
try expectEqual(expf(-0x1.a206f0p+2), 0x1.7dd484p-10);
try expectEqual(expf(0x1.288bbcp+3), 0x1.4abc80p+13);
try expectEqual(expf(0x1.52efd0p-1), 0x1.f04a9cp+0);
try expectEqual(expf(-0x1.a05cc8p-2), 0x1.54f1e0p-1);
try expectEqual(expf(0x1.1f9efap-1), 0x1.c0f628p+0);
try expectEqual(expf(0x1.8c5db0p-1), 0x1.1599b2p+1);
try expectEqual(expf(-0x1.5b86eap-1), 0x1.03b572p-1);
try expectEqual(expf(-0x1.57f25cp+2), 0x1.2fbea2p-8);
try expectEqual(expf(0x1.c7d310p+3), 0x1.76eefp+20);
try expectEqual(expf(0x1.19be70p+4), 0x1.52d3dep+25);
try expectEqual(expf(-0x1.ab6d70p+3), 0x1.a88adep-20);
try expectEqual(expf(-0x1.5ac18ep+2), 0x1.22b328p-8);
try expectEqual(expf(-0x1.925982p-1), 0x1.d2acc0p-2);
try expectEqual(expf(0x1.7221cep+3), 0x1.9c2ceap+16);
try expectEqual(expf(0x1.11a0d4p+4), 0x1.980ee6p+24);
try expectEqual(expf(-0x1.ae41a2p+1), 0x1.1c28d0p-5);
try expectEqual(expf(-0x1.329154p+4), 0x1.47ef94p-28);
}
test "expf() boundary" {
try expectEqual(expf(0x1.62e42ep+6), 0x1.ffff08p+127); // The last value before the result gets infinite
try expectEqual(expf(0x1.62e430p+6), math.inf(f32)); // The first value that gives inf
try expectEqual(expf(0x1.fffffep+127), math.inf(f32)); // Max input value
try expectEqual(expf(0x1p-149), 1.0); // Min positive input value
try expectEqual(expf(-0x1p-149), 1.0); // Min negative input value
try expectEqual(expf(0x1p-126), 1.0); // First positive subnormal input
try expectEqual(expf(-0x1p-126), 1.0); // First negative subnormal input
try expectEqual(expf(-0x1.9fe368p+6), 0x1p-149); // The last value before the result flushes to zero
try expectEqual(expf(-0x1.9fe36ap+6), 0.0); // The first value at which the result flushes to zero
try expectEqual(expf(-0x1.5d589ep+6), 0x1.00004cp-126); // The last value before the result flushes to subnormal
try expectEqual(expf(-0x1.5d58a0p+6), 0x1.ffff98p-127); // The first value for which the result flushes to subnormal
}
test "exp() special" {
try expectEqual(exp(0.0), 1.0);
try expectEqual(exp(-0.0), 1.0);
// TODO: Accuracy error - off in the last bit in 64-bit, disagreeing with GCC
// try expectEqual(exp(1.0), math.e);
try expectEqual(exp(math.ln2), 2.0);
try expectEqual(exp(math.inf(f64)), math.inf(f64));
try expect(math.isPositiveZero(exp(-math.inf(f64))));
try expect(math.isNan(exp(math.nan(f64))));
try expect(math.isNan(exp(math.snan(f64))));
}
test "exp() sanity" {
try expectEqual(exp(-0x1.02239f3c6a8f1p+3), 0x1.490327ea61235p-12);
try expectEqual(exp(0x1.161868e18bc67p+2), 0x1.34712ed238c04p+6);
try expectEqual(exp(-0x1.0c34b3e01e6e7p+3), 0x1.e06b1b6c18e64p-13);
try expectEqual(exp(-0x1.a206f0a19dcc4p+2), 0x1.7dd47f810e68cp-10);
try expectEqual(exp(0x1.288bbb0d6a1e6p+3), 0x1.4abc77496e07ep+13);
try expectEqual(exp(0x1.52efd0cd80497p-1), 0x1.f04a9c1080500p+0);
try expectEqual(exp(-0x1.a05cc754481d1p-2), 0x1.54f1e0fd3ea0dp-1);
try expectEqual(exp(0x1.1f9ef934745cbp-1), 0x1.c0f6266a6a547p+0);
try expectEqual(exp(0x1.8c5db097f7442p-1), 0x1.1599b1d4a25fbp+1);
try expectEqual(exp(-0x1.5b86ea8118a0ep-1), 0x1.03b5728a00229p-1);
try expectEqual(exp(-0x1.57f25b2b5006dp+2), 0x1.2fbea6a01cab9p-8);
try expectEqual(exp(0x1.c7d30fb825911p+3), 0x1.76eeed45a0634p+20);
try expectEqual(exp(0x1.19be709de7505p+4), 0x1.52d3eb7be6844p+25);
try expectEqual(exp(-0x1.ab6d6fba96889p+3), 0x1.a88ae12f985d6p-20);
try expectEqual(exp(-0x1.5ac18e27084ddp+2), 0x1.22b327da9cca6p-8);
try expectEqual(exp(-0x1.925981b093c41p-1), 0x1.d2acc046b55f7p-2);
try expectEqual(exp(0x1.7221cd18455f5p+3), 0x1.9c2cde8699cfbp+16);
try expectEqual(exp(0x1.11a0d4a51b239p+4), 0x1.980ef612ff182p+24);
try expectEqual(exp(-0x1.ae41a1079de4dp+1), 0x1.1c28d16bb3222p-5);
try expectEqual(exp(-0x1.329153103b871p+4), 0x1.47efa6ddd0d22p-28);
}
test "exp() boundary" {
try expectEqual(exp(0x1.62e42fefa39efp+9), 0x1.fffffffffff2ap+1023); // The last value before the result gets infinite
try expectEqual(exp(0x1.62e42fefa39f0p+9), math.inf(f64)); // The first value that gives inf
try expectEqual(exp(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value
try expectEqual(exp(0x1p-1074), 1.0); // Min positive input value
try expectEqual(exp(-0x1p-1074), 1.0); // Min negative input value
try expectEqual(exp(0x1p-1022), 1.0); // First positive subnormal input
try expectEqual(exp(-0x1p-1022), 1.0); // First negative subnormal input
try expectEqual(exp(-0x1.74910d52d3051p+9), 0x1p-1074); // The last value before the result flushes to zero
try expectEqual(exp(-0x1.74910d52d3052p+9), 0.0); // The first value at which the result flushes to zero
try expectEqual(exp(-0x1.6232bdd7abcd2p+9), 0x1.000000000007cp-1022); // The last value before the result flushes to subnormal
try expectEqual(exp(-0x1.6232bdd7abcd3p+9), 0x1.ffffffffffcf8p-1023); // The first value for which the result flushes to subnormal
}

View File

@ -10,6 +10,7 @@ const arch = builtin.cpu.arch;
const math = std.math;
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const common = @import("common.zig");
pub const panic = common.panic;
@ -58,7 +59,7 @@ pub fn exp2f(x: f32) callconv(.c) f32 {
if (common.want_float_exceptions) mem.doNotOptimizeAway(-0x1.0p-149 / x);
}
// x <= -150
if (u >= 0x3160000) {
if (u >= 0xC3160000) {
return 0;
}
}
@ -457,34 +458,78 @@ const exp2dt = [_]f64{
0x1.690f4b19e9471p+0, -0x1.9780p-45,
};
test "exp2_32" {
const epsilon = 0.000001;
try expect(exp2f(0.0) == 1.0);
try expect(math.approxEqAbs(f32, exp2f(0.2), 1.148698, epsilon));
try expect(math.approxEqAbs(f32, exp2f(0.8923), 1.856133, epsilon));
try expect(math.approxEqAbs(f32, exp2f(1.5), 2.828427, epsilon));
try expect(math.approxEqAbs(f32, exp2f(37.45), 187747237888, epsilon));
try expect(math.approxEqAbs(f32, exp2f(-1), 0.5, epsilon));
}
test "exp2_64" {
const epsilon = 0.000001;
try expect(exp2(0.0) == 1.0);
try expect(math.approxEqAbs(f64, exp2(0.2), 1.148698, epsilon));
try expect(math.approxEqAbs(f64, exp2(0.8923), 1.856133, epsilon));
try expect(math.approxEqAbs(f64, exp2(1.5), 2.828427, epsilon));
try expect(math.approxEqAbs(f64, exp2(-1), 0.5, epsilon));
try expect(math.approxEqAbs(f64, exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1, epsilon));
}
test "exp2_32.special" {
try expect(math.isPositiveInf(exp2f(math.inf(f32))));
test "exp2f() special" {
try expectEqual(exp2f(0.0), 1.0);
try expectEqual(exp2f(-0.0), 1.0);
try expectEqual(exp2f(1.0), 2.0);
try expectEqual(exp2f(-1.0), 0.5);
try expectEqual(exp2f(math.inf(f32)), math.inf(f32));
try expect(math.isPositiveZero(exp2f(-math.inf(f32))));
try expect(math.isNan(exp2f(math.nan(f32))));
try expect(math.isNan(exp2f(math.snan(f32))));
}
test "exp2_64.special" {
try expect(math.isPositiveInf(exp2(math.inf(f64))));
try expect(math.isNan(exp2(math.nan(f64))));
test "exp2f() sanity" {
try expectEqual(exp2f(-0x1.0223a0p+3), 0x1.e8d134p-9);
try expectEqual(exp2f(0x1.161868p+2), 0x1.453672p+4);
try expectEqual(exp2f(-0x1.0c34b4p+3), 0x1.890ca0p-9);
try expectEqual(exp2f(-0x1.a206f0p+2), 0x1.622d4ep-7);
try expectEqual(exp2f(0x1.288bbcp+3), 0x1.340ecep+9);
try expectEqual(exp2f(0x1.52efd0p-1), 0x1.950eeep+0);
try expectEqual(exp2f(-0x1.a05cc8p-2), 0x1.824056p-1);
try expectEqual(exp2f(0x1.1f9efap-1), 0x1.79dfa2p+0);
try expectEqual(exp2f(0x1.8c5db0p-1), 0x1.b5ceacp+0);
try expectEqual(exp2f(-0x1.5b86eap-1), 0x1.3fd8bap-1);
}
test "exp2f() boundary" {
try expectEqual(exp2f(0x1.fffffep+6), 0x1.ffff4ep+127); // The last value before the result gets infinite
try expectEqual(exp2f(0x1p+7), math.inf(f32)); // The first value that gives infinite result
try expectEqual(exp2f(-0x1.2bccccp+7), 0x1p-149); // The last value before the result flushes to zero
try expectEqual(exp2f(-0x1.2cp+7), 0); // The first value at which the result flushes to zero
try expectEqual(exp2f(-0x1.f8p+6), 0x1p-126); // The last value before the result flushes to subnormal
try expectEqual(exp2f(-0x1.f80002p+6), 0x1.ffff50p-127); // The first value for which the result flushes to subnormal
try expectEqual(exp2f(0x1.fffffep+127), math.inf(f32)); // Max input value
try expectEqual(exp2f(0x1p-149), 1); // Min positive input value
try expectEqual(exp2f(-0x1p-149), 1); // Min negative input value
try expectEqual(exp2f(0x1p-126), 1); // First positive subnormal input
try expectEqual(exp2f(-0x1p-126), 1); // First negative subnormal input
}
test "exp2() special" {
try expectEqual(exp2(0.0), 1.0);
try expectEqual(exp2(-0.0), 1.0);
try expectEqual(exp2(1.0), 2.0);
try expectEqual(exp2(-1.0), 0.5);
try expectEqual(exp2(math.inf(f64)), math.inf(f64));
try expect(math.isPositiveZero(exp2(-math.inf(f64))));
try expect(math.isNan(exp2(math.nan(f64))));
try expect(math.isNan(exp2(math.snan(f64))));
}
test "exp2() sanity" {
try expectEqual(exp2(-0x1.02239f3c6a8f1p+3), 0x1.e8d13c396f452p-9);
try expectEqual(exp2(0x1.161868e18bc67p+2), 0x1.4536746bb6f12p+4);
try expectEqual(exp2(-0x1.0c34b3e01e6e7p+3), 0x1.890ca0c00b9a2p-9);
try expectEqual(exp2(-0x1.a206f0a19dcc4p+2), 0x1.622d4b0ebc6c1p-7);
try expectEqual(exp2(0x1.288bbb0d6a1e6p+3), 0x1.340ec7f3e607ep+9);
try expectEqual(exp2(0x1.52efd0cd80497p-1), 0x1.950eef4bc5451p+0);
try expectEqual(exp2(-0x1.a05cc754481d1p-2), 0x1.824056efc687cp-1);
try expectEqual(exp2(0x1.1f9ef934745cbp-1), 0x1.79dfa14ab121ep+0);
try expectEqual(exp2(0x1.8c5db097f7442p-1), 0x1.b5cead2247372p+0);
try expectEqual(exp2(-0x1.5b86ea8118a0ep-1), 0x1.3fd8ba33216b9p-1);
}
test "exp2() boundary" {
try expectEqual(exp2(0x1.fffffffffffffp+9), 0x1.ffffffffffd3ap+1023); // The last value before the result gets infinite
try expectEqual(exp2(0x1p+10), math.inf(f64)); // The first value that gives infinite result
try expectEqual(exp2(-0x1.0cbffffffffffp+10), 0x1p-1074); // The last value before the result flushes to zero
try expectEqual(exp2(-0x1.0ccp+10), 0); // The first value at which the result flushes to zero
try expectEqual(exp2(-0x1.ffp+9), 0x1p-1022); // The last value before the result flushes to subnormal
try expectEqual(exp2(-0x1.ff00000000001p+9), 0x1.ffffffffffd3ap-1023); // The first value for which the result flushes to subnormal
try expectEqual(exp2(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value
try expectEqual(exp2(0x1p-1074), 1); // Min positive input value
try expectEqual(exp2(-0x1p-1074), 1); // Min negative input value
try expectEqual(exp2(0x1p-1022), 1); // First positive subnormal input
try expectEqual(exp2(-0x1p-1022), 1); // First negative subnormal input
}

View File

@ -7,7 +7,8 @@
const std = @import("std");
const builtin = @import("builtin");
const math = std.math;
const testing = std.testing;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const arch = builtin.cpu.arch;
const common = @import("common.zig");
@ -110,8 +111,8 @@ pub fn log(x_: f64) callconv(.c) f64 {
// subnormal, scale x
k -= 54;
x *= 0x1.0p54;
hx = @intCast(@as(u64, @bitCast(ix)) >> 32);
x *= 0x1p54;
hx = @intCast(@as(u64, @bitCast(x)) >> 32);
} else if (hx >= 0x7FF00000) {
return x;
} else if (hx == 0x3FF00000 and ix << 32 == 0) {
@ -159,38 +160,72 @@ pub fn logl(x: c_longdouble) callconv(.c) c_longdouble {
}
}
test "ln32" {
const epsilon = 0.000001;
try testing.expect(math.approxEqAbs(f32, logf(0.2), -1.609438, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(0.8923), -0.113953, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(1.5), 0.405465, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(37.45), 3.623007, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(89.123), 4.490017, epsilon));
try testing.expect(math.approxEqAbs(f32, logf(123123.234375), 11.720941, epsilon));
test "logf() special" {
try expectEqual(logf(0.0), -math.inf(f32));
try expectEqual(logf(-0.0), -math.inf(f32));
try expect(math.isPositiveZero(logf(1.0)));
try expectEqual(logf(math.e), 1.0);
try expectEqual(logf(math.inf(f32)), math.inf(f32));
try expect(math.isNan(logf(-1.0)));
try expect(math.isNan(logf(-math.inf(f32))));
try expect(math.isNan(logf(math.nan(f32))));
try expect(math.isNan(logf(math.snan(f32))));
}
test "ln64" {
const epsilon = 0.000001;
try testing.expect(math.approxEqAbs(f64, log(0.2), -1.609438, epsilon));
try testing.expect(math.approxEqAbs(f64, log(0.8923), -0.113953, epsilon));
try testing.expect(math.approxEqAbs(f64, log(1.5), 0.405465, epsilon));
try testing.expect(math.approxEqAbs(f64, log(37.45), 3.623007, epsilon));
try testing.expect(math.approxEqAbs(f64, log(89.123), 4.490017, epsilon));
try testing.expect(math.approxEqAbs(f64, log(123123.234375), 11.720941, epsilon));
test "logf() sanity" {
try expect(math.isNan(logf(-0x1.0223a0p+3)));
try expectEqual(logf(0x1.161868p+2), 0x1.7815b0p+0);
try expect(math.isNan(logf(-0x1.0c34b4p+3)));
try expect(math.isNan(logf(-0x1.a206f0p+2)));
try expectEqual(logf(0x1.288bbcp+3), 0x1.1cfcd6p+1);
try expectEqual(logf(0x1.52efd0p-1), -0x1.a6694cp-2);
try expect(math.isNan(logf(-0x1.a05cc8p-2)));
try expectEqual(logf(0x1.1f9efap-1), -0x1.2742bap-1);
try expectEqual(logf(0x1.8c5db0p-1), -0x1.062160p-2);
try expect(math.isNan(logf(-0x1.5b86eap-1)));
}
test "ln32.special" {
try testing.expect(math.isPositiveInf(logf(math.inf(f32))));
try testing.expect(math.isNegativeInf(logf(0.0)));
try testing.expect(math.isNan(logf(-1.0)));
try testing.expect(math.isNan(logf(math.nan(f32))));
test "logf() boundary" {
try expectEqual(logf(0x1.fffffep+127), 0x1.62e430p+6); // Max input value
try expectEqual(logf(0x1p-149), -0x1.9d1da0p+6); // Min positive input value
try expect(math.isNan(logf(-0x1p-149))); // Min negative input value
try expectEqual(logf(0x1.000002p+0), 0x1.fffffep-24); // Last value before result reaches +0
try expectEqual(logf(0x1.fffffep-1), -0x1p-24); // Last value before result reaches -0
try expectEqual(logf(0x1p-126), -0x1.5d58a0p+6); // First subnormal
try expect(math.isNan(logf(-0x1p-126))); // First negative subnormal
}
test "ln64.special" {
try testing.expect(math.isPositiveInf(log(math.inf(f64))));
try testing.expect(math.isNegativeInf(log(0.0)));
try testing.expect(math.isNan(log(-1.0)));
try testing.expect(math.isNan(log(math.nan(f64))));
test "log() special" {
try expectEqual(log(0.0), -math.inf(f64));
try expectEqual(log(-0.0), -math.inf(f64));
try expect(math.isPositiveZero(log(1.0)));
try expectEqual(log(math.e), 1.0);
try expectEqual(log(math.inf(f64)), math.inf(f64));
try expect(math.isNan(log(-1.0)));
try expect(math.isNan(log(-math.inf(f64))));
try expect(math.isNan(log(math.nan(f64))));
try expect(math.isNan(log(math.snan(f64))));
}
test "log() sanity" {
try expect(math.isNan(log(-0x1.02239f3c6a8f1p+3)));
try expectEqual(log(0x1.161868e18bc67p+2), 0x1.7815b08f99c65p+0);
try expect(math.isNan(log(-0x1.0c34b3e01e6e7p+3)));
try expect(math.isNan(log(-0x1.a206f0a19dcc4p+2)));
try expectEqual(log(0x1.288bbb0d6a1e6p+3), 0x1.1cfcd53d72604p+1);
try expectEqual(log(0x1.52efd0cd80497p-1), -0x1.a6694a4a85621p-2);
try expect(math.isNan(log(-0x1.a05cc754481d1p-2)));
try expectEqual(log(0x1.1f9ef934745cbp-1), -0x1.2742bc03d02ddp-1);
try expectEqual(log(0x1.8c5db097f7442p-1), -0x1.06215de4a3f92p-2);
try expect(math.isNan(log(-0x1.5b86ea8118a0ep-1)));
}
test "log() boundary" {
try expectEqual(log(0x1.fffffffffffffp+1023), 0x1.62e42fefa39efp+9); // Max input value
try expectEqual(log(0x1p-1074), -0x1.74385446d71c3p+9); // Min positive input value
try expect(math.isNan(log(-0x1p-1074))); // Min negative input value
try expectEqual(log(0x1.0000000000001p+0), 0x1.fffffffffffffp-53); // Last value before result reaches +0
try expectEqual(log(0x1.fffffffffffffp-1), -0x1p-53); // Last value before result reaches -0
try expectEqual(log(0x1p-1022), -0x1.6232bdd7abcd2p+9); // First subnormal
try expect(math.isNan(log(-0x1p-1022))); // First negative subnormal
}

View File

@ -7,7 +7,8 @@
const std = @import("std");
const builtin = @import("builtin");
const math = std.math;
const testing = std.testing;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const maxInt = std.math.maxInt;
const arch = builtin.cpu.arch;
const common = @import("common.zig");
@ -187,38 +188,74 @@ pub fn log10l(x: c_longdouble) callconv(.c) c_longdouble {
}
}
test "log10_32" {
const epsilon = 0.000001;
try testing.expect(math.approxEqAbs(f32, log10f(0.2), -0.698970, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(0.8923), -0.049489, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(1.5), 0.176091, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(37.45), 1.573452, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(89.123), 1.94999, epsilon));
try testing.expect(math.approxEqAbs(f32, log10f(123123.234375), 5.09034, epsilon));
test "log10f() special" {
try expectEqual(log10f(0.0), -math.inf(f32));
try expectEqual(log10f(-0.0), -math.inf(f32));
try expect(math.isPositiveZero(log10f(1.0)));
try expectEqual(log10f(10.0), 1.0);
try expectEqual(log10f(0.1), -1.0);
try expectEqual(log10f(math.inf(f32)), math.inf(f32));
try expect(math.isNan(log10f(-1.0)));
try expect(math.isNan(log10f(-math.inf(f32))));
try expect(math.isNan(log10f(math.nan(f32))));
try expect(math.isNan(log10f(math.snan(f32))));
}
test "log10_64" {
const epsilon = 0.000001;
try testing.expect(math.approxEqAbs(f64, log10(0.2), -0.698970, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(0.8923), -0.049489, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(1.5), 0.176091, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(37.45), 1.573452, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(89.123), 1.94999, epsilon));
try testing.expect(math.approxEqAbs(f64, log10(123123.234375), 5.09034, epsilon));
test "log10f() sanity" {
try expect(math.isNan(log10f(-0x1.0223a0p+3)));
try expectEqual(log10f(0x1.161868p+2), 0x1.46a9bcp-1);
try expect(math.isNan(log10f(-0x1.0c34b4p+3)));
try expect(math.isNan(log10f(-0x1.a206f0p+2)));
try expectEqual(log10f(0x1.288bbcp+3), 0x1.ef1300p-1);
try expectEqual(log10f(0x1.52efd0p-1), -0x1.6ee6dcp-3); // Disagrees with GCC in last bit
try expect(math.isNan(log10f(-0x1.a05cc8p-2)));
try expectEqual(log10f(0x1.1f9efap-1), -0x1.0075ccp-2);
try expectEqual(log10f(0x1.8c5db0p-1), -0x1.c75df8p-4);
try expect(math.isNan(log10f(-0x1.5b86eap-1)));
}
test "log10_32.special" {
try testing.expect(math.isPositiveInf(log10f(math.inf(f32))));
try testing.expect(math.isNegativeInf(log10f(0.0)));
try testing.expect(math.isNan(log10f(-1.0)));
try testing.expect(math.isNan(log10f(math.nan(f32))));
test "log10f() boundary" {
try expectEqual(log10f(0x1.fffffep+127), 0x1.344136p+5); // Max input value
try expectEqual(log10f(0x1p-149), -0x1.66d3e8p+5); // Min positive input value
try expect(math.isNan(log10f(-0x1p-149))); // Min negative input value
try expectEqual(log10f(0x1.000002p+0), 0x1.bcb7b0p-25); // Last value before result reaches +0
try expectEqual(log10f(0x1.fffffep-1), -0x1.bcb7b2p-26); // Last value before result reaches -0
try expectEqual(log10f(0x1p-126), -0x1.2f7030p+5); // First subnormal
try expect(math.isNan(log10f(-0x1p-126))); // First negative subnormal
}
test "log10_64.special" {
try testing.expect(math.isPositiveInf(log10(math.inf(f64))));
try testing.expect(math.isNegativeInf(log10(0.0)));
try testing.expect(math.isNan(log10(-1.0)));
try testing.expect(math.isNan(log10(math.nan(f64))));
test "log10() special" {
try expectEqual(log10(0.0), -math.inf(f64));
try expectEqual(log10(-0.0), -math.inf(f64));
try expect(math.isPositiveZero(log10(1.0)));
try expectEqual(log10(10.0), 1.0);
try expectEqual(log10(0.1), -1.0);
try expectEqual(log10(math.inf(f64)), math.inf(f64));
try expect(math.isNan(log10(-1.0)));
try expect(math.isNan(log10(-math.inf(f64))));
try expect(math.isNan(log10(math.nan(f64))));
try expect(math.isNan(log10(math.snan(f64))));
}
test "log10() sanity" {
try expect(math.isNan(log10(-0x1.02239f3c6a8f1p+3)));
try expectEqual(log10(0x1.161868e18bc67p+2), 0x1.46a9bd1d2eb87p-1);
try expect(math.isNan(log10(-0x1.0c34b3e01e6e7p+3)));
try expect(math.isNan(log10(-0x1.a206f0a19dcc4p+2)));
try expectEqual(log10(0x1.288bbb0d6a1e6p+3), 0x1.ef12fff994862p-1);
try expectEqual(log10(0x1.52efd0cd80497p-1), -0x1.6ee6db5a155cbp-3);
try expect(math.isNan(log10(-0x1.a05cc754481d1p-2)));
try expectEqual(log10(0x1.1f9ef934745cbp-1), -0x1.0075cda79d321p-2);
try expectEqual(log10(0x1.8c5db097f7442p-1), -0x1.c75df6442465ap-4);
try expect(math.isNan(log10(-0x1.5b86ea8118a0ep-1)));
}
test "log10() boundary" {
try expectEqual(log10(0x1.fffffffffffffp+1023), 0x1.34413509f79ffp+8); // Max input value
try expectEqual(log10(0x1p-1074), -0x1.434e6420f4374p+8); // Min positive input value
try expect(math.isNan(log10(-0x1p-1074))); // Min negative input value
try expectEqual(log10(0x1.0000000000001p+0), 0x1.bcb7b1526e50dp-54); // Last value before result reaches +0
try expectEqual(log10(0x1.fffffffffffffp-1), -0x1.bcb7b1526e50fp-55); // Last value before result reaches -0
try expectEqual(log10(0x1p-1022), -0x1.33a7146f72a42p+8); // First subnormal
try expect(math.isNan(log10(-0x1p-1022))); // First negative subnormal
}

View File

@ -8,6 +8,7 @@ const std = @import("std");
const builtin = @import("builtin");
const math = std.math;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
const maxInt = std.math.maxInt;
const arch = builtin.cpu.arch;
const common = @import("common.zig");
@ -179,36 +180,73 @@ pub fn log2l(x: c_longdouble) callconv(.c) c_longdouble {
}
}
test "log2_32" {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f32, log2f(0.2), -2.321928, epsilon));
try expect(math.approxEqAbs(f32, log2f(0.8923), -0.164399, epsilon));
try expect(math.approxEqAbs(f32, log2f(1.5), 0.584962, epsilon));
try expect(math.approxEqAbs(f32, log2f(37.45), 5.226894, epsilon));
try expect(math.approxEqAbs(f32, log2f(123123.234375), 16.909744, epsilon));
}
test "log2_64" {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f64, log2(0.2), -2.321928, epsilon));
try expect(math.approxEqAbs(f64, log2(0.8923), -0.164399, epsilon));
try expect(math.approxEqAbs(f64, log2(1.5), 0.584962, epsilon));
try expect(math.approxEqAbs(f64, log2(37.45), 5.226894, epsilon));
try expect(math.approxEqAbs(f64, log2(123123.234375), 16.909744, epsilon));
}
test "log2_32.special" {
try expect(math.isPositiveInf(log2f(math.inf(f32))));
try expect(math.isNegativeInf(log2f(0.0)));
test "log2f() special" {
try expectEqual(log2f(0.0), -math.inf(f32));
try expectEqual(log2f(-0.0), -math.inf(f32));
try expect(math.isPositiveZero(log2f(1.0)));
try expectEqual(log2f(2.0), 1.0);
try expectEqual(log2f(math.inf(f32)), math.inf(f32));
try expect(math.isNan(log2f(-1.0)));
try expect(math.isNan(log2f(-math.inf(f32))));
try expect(math.isNan(log2f(math.nan(f32))));
try expect(math.isNan(log2f(math.snan(f32))));
}
test "log2_64.special" {
try expect(math.isPositiveInf(log2(math.inf(f64))));
try expect(math.isNegativeInf(log2(0.0)));
try expect(math.isNan(log2(-1.0)));
try expect(math.isNan(log2(math.nan(f64))));
test "log2f() sanity" {
try expect(math.isNan(log2f(-0x1.0223a0p+3)));
try expectEqual(log2f(0x1.161868p+2), 0x1.0f49acp+1);
try expect(math.isNan(log2f(-0x1.0c34b4p+3)));
try expect(math.isNan(log2f(-0x1.a206f0p+2)));
try expectEqual(log2f(0x1.288bbcp+3), 0x1.9b2676p+1);
try expectEqual(log2f(0x1.52efd0p-1), -0x1.30b494p-1); // Disagrees with GCC in last bit
try expect(math.isNan(log2f(-0x1.a05cc8p-2)));
try expectEqual(log2f(0x1.1f9efap-1), -0x1.a9f89ap-1);
try expectEqual(log2f(0x1.8c5db0p-1), -0x1.7a2c96p-2);
try expect(math.isNan(log2f(-0x1.5b86eap-1)));
}
test "log2f() boundary" {
try expectEqual(log2f(0x1.fffffep+127), 0x1p+7); // Max input value
try expectEqual(log2f(0x1p-149), -0x1.2ap+7); // Min positive input value
try expect(math.isNan(log2f(-0x1p-149))); // Min negative input value
try expectEqual(log2f(0x1.000002p+0), 0x1.715474p-23); // Last value before result reaches +0
try expectEqual(log2f(0x1.fffffep-1), -0x1.715478p-24); // Last value before result reaches -0
try expectEqual(log2f(0x1p-126), -0x1.f8p+6); // First subnormal
try expect(math.isNan(log2f(-0x1p-126))); // First negative subnormal
}
test "log2() special" {
try expectEqual(log2(0.0), -math.inf(f64));
try expectEqual(log2(-0.0), -math.inf(f64));
try expect(math.isPositiveZero(log2(1.0)));
try expectEqual(log2(2.0), 1.0);
try expectEqual(log2(math.inf(f64)), math.inf(f64));
try expect(math.isNan(log2(-1.0)));
try expect(math.isNan(log2(-math.inf(f64))));
try expect(math.isNan(log2(math.nan(f64))));
try expect(math.isNan(log2(math.snan(f64))));
}
test "log2() sanity" {
try expect(math.isNan(log2(-0x1.02239f3c6a8f1p+3)));
try expectEqual(log2(0x1.161868e18bc67p+2), 0x1.0f49ac3838580p+1);
try expect(math.isNan(log2(-0x1.0c34b3e01e6e7p+3)));
try expect(math.isNan(log2(-0x1.a206f0a19dcc4p+2)));
try expectEqual(log2(0x1.288bbb0d6a1e6p+3), 0x1.9b26760c2a57ep+1);
try expectEqual(log2(0x1.52efd0cd80497p-1), -0x1.30b490ef684c7p-1);
try expect(math.isNan(log2(-0x1.a05cc754481d1p-2)));
try expectEqual(log2(0x1.1f9ef934745cbp-1), -0x1.a9f89b5f5acb8p-1);
try expectEqual(log2(0x1.8c5db097f7442p-1), -0x1.7a2c947173f06p-2);
try expect(math.isNan(log2(-0x1.5b86ea8118a0ep-1)));
}
test "log2() boundary" {
try expectEqual(log2(0x1.fffffffffffffp+1023), 0x1p+10); // Max input value
try expectEqual(log2(0x1p-1074), -0x1.0c8p+10); // Min positive input value
try expect(math.isNan(log2(-0x1p-1074))); // Min negative input value
try expectEqual(log2(0x1.0000000000001p+0), 0x1.71547652b82fdp-52); // Last value before result reaches +0
try expectEqual(log2(0x1.fffffffffffffp-1), -0x1.71547652b82fep-53); // Last value before result reaches -0
try expectEqual(log2(0x1p-1022), -0x1.ffp+9); // First subnormal
try expect(math.isNan(log2(-0x1p-1022))); // First negative subnormal
}

View File

@ -13,11 +13,11 @@ comptime {
// Default stack-probe functions emitted by LLVM
if (builtin.target.isMinGW()) {
@export(&_chkstk, .{ .name = "_alloca", .linkage = common.linkage, .visibility = common.visibility });
@export(&__chkstk, .{ .name = "__chkstk", .linkage = common.linkage, .visibility = common.visibility });
@export(&___chkstk, .{ .name = "__alloca", .linkage = common.linkage, .visibility = common.visibility });
@export(&___chkstk, .{ .name = "___chkstk", .linkage = common.linkage, .visibility = common.visibility });
@export(&__chkstk_ms, .{ .name = "__chkstk_ms", .linkage = common.linkage, .visibility = common.visibility });
@export(&___chkstk_ms, .{ .name = "___chkstk_ms", .linkage = common.linkage, .visibility = common.visibility });
if (arch == .thumb or arch == .aarch64) {
@export(&__chkstk, .{ .name = "__chkstk", .linkage = common.linkage, .visibility = common.visibility });
}
} else if (!builtin.link_libc) {
// This symbols are otherwise exported by MSVCRT.lib
@export(&_chkstk, .{ .name = "_chkstk", .linkage = common.linkage, .visibility = common.visibility });

View File

@ -433,20 +433,18 @@ fn parse(file_name: []const u8, source: []u8) Oom!Ast {
defer ast.deinit(gpa);
const token_offsets = ast.tokens.items(.start);
var rendered_err: std.ArrayListUnmanaged(u8) = .{};
defer rendered_err.deinit(gpa);
var rendered_err: std.Io.Writer.Allocating = .init(gpa);
defer rendered_err.deinit();
for (ast.errors) |err| {
const err_offset = token_offsets[err.token] + ast.errorOffset(err);
const err_loc = std.zig.findLineColumn(ast.source, err_offset);
rendered_err.clearRetainingCapacity();
{
var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &rendered_err);
defer rendered_err = aw.toArrayList();
ast.renderError(err, &aw.interface) catch |e| switch (e) {
error.WriteFailed => return error.OutOfMemory,
};
}
log.err("{s}:{d}:{d}: {s}", .{ file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.items });
ast.renderError(err, &rendered_err.writer) catch |e| switch (e) {
error.WriteFailed => return error.OutOfMemory,
};
log.err("{s}:{d}:{d}: {s}", .{
file_name, err_loc.line + 1, err_loc.column + 1, rendered_err.getWritten(),
});
}
return Ast.parse(gpa, "", .zig);
}

View File

@ -101,6 +101,9 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader {
.generated_dir = .{ .step = &config_header.step },
};
if (options.style.getPath()) |s| {
s.addStepDependencies(&config_header.step);
}
return config_header;
}

View File

@ -372,6 +372,34 @@ pub fn discard(self: Self) anyerror!u64 {
}
}
/// Helper for bridging to the new `Reader` API while upgrading.
pub fn adaptToNewApi(self: *const Self) Adapter {
return .{
.derp_reader = self.*,
.new_interface = .{
.buffer = &.{},
.vtable = &.{ .stream = Adapter.stream },
.seek = 0,
.end = 0,
},
};
}
pub const Adapter = struct {
derp_reader: Self,
new_interface: std.io.Reader,
err: ?Error = null,
fn stream(r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {
const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r));
const buf = limit.slice(try w.writableSliceGreedy(1));
return a.derp_reader.read(buf) catch |err| {
a.err = err;
return error.ReadFailed;
};
}
};
const std = @import("../std.zig");
const Self = @This();
const math = std.math;

View File

@ -246,33 +246,40 @@ pub fn appendRemaining(
limit: Limit,
) LimitedAllocError!void {
assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.
const buffer = r.buffer;
const buffer_contents = buffer[r.seek..r.end];
const buffer_contents = r.buffer[r.seek..r.end];
const copy_len = limit.minInt(buffer_contents.len);
try list.ensureUnusedCapacity(gpa, copy_len);
@memcpy(list.unusedCapacitySlice()[0..copy_len], buffer[0..copy_len]);
list.items.len += copy_len;
try list.appendSlice(gpa, r.buffer[0..copy_len]);
r.seek += copy_len;
if (copy_len == buffer_contents.len) {
r.seek = 0;
r.end = 0;
}
var remaining = limit.subtract(copy_len).?;
if (buffer_contents.len - copy_len != 0) return error.StreamTooLong;
r.seek = 0;
r.end = 0;
var remaining = @intFromEnum(limit) - copy_len;
while (true) {
try list.ensureUnusedCapacity(gpa, 1);
const dest = remaining.slice(list.unusedCapacitySlice());
const additional_buffer: []u8 = if (@intFromEnum(remaining) == dest.len) buffer else &.{};
const n = readVec(r, &.{ dest, additional_buffer }) catch |err| switch (err) {
error.EndOfStream => break,
error.ReadFailed => return error.ReadFailed,
};
if (n > dest.len) {
r.end = n - dest.len;
list.items.len += dest.len;
return error.StreamTooLong;
const cap = list.unusedCapacitySlice();
const dest = cap[0..@min(cap.len, remaining)];
if (remaining - dest.len == 0) {
// Additionally provides `buffer` to detect end.
const new_remaining = readVecInner(r, &.{}, dest, remaining) catch |err| switch (err) {
error.EndOfStream => {
if (r.bufferedLen() != 0) return error.StreamTooLong;
return;
},
error.ReadFailed => return error.ReadFailed,
};
list.items.len += remaining - new_remaining;
remaining = new_remaining;
} else {
// Leave `buffer` empty, appending directly to `list`.
var dest_w: Writer = .fixed(dest);
const n = r.vtable.stream(r, &dest_w, .limited(dest.len)) catch |err| switch (err) {
error.WriteFailed => unreachable, // Prevented by the limit.
error.EndOfStream => return,
error.ReadFailed => return error.ReadFailed,
};
list.items.len += n;
remaining -= n;
}
list.items.len += n;
remaining = remaining.subtract(n).?;
}
}
@ -313,62 +320,68 @@ pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize {
// buffer capacity requirements met.
r.seek = 0;
r.end = 0;
const first = buf[copy_len..];
const middle = data[i + 1 ..];
var wrapper: Writer.VectorWrapper = .{
.it = .{
.first = first,
.middle = middle,
.last = r.buffer,
},
.writer = .{
.buffer = if (first.len >= r.buffer.len) first else r.buffer,
.vtable = Writer.VectorWrapper.vtable,
},
};
var n = r.vtable.stream(r, &wrapper.writer, .limited(remaining)) catch |err| switch (err) {
error.WriteFailed => {
assert(!wrapper.used);
if (wrapper.writer.buffer.ptr == first.ptr) {
remaining -= wrapper.writer.end;
} else {
assert(wrapper.writer.end <= r.buffer.len);
r.end = wrapper.writer.end;
}
break;
},
else => |e| return e,
};
if (!wrapper.used) {
if (wrapper.writer.buffer.ptr == first.ptr) {
remaining -= n;
} else {
assert(n <= r.buffer.len);
r.end = n;
}
break;
}
if (n < first.len) {
remaining -= n;
break;
}
remaining -= first.len;
n -= first.len;
for (middle) |mid| {
if (n < mid.len) {
remaining -= n;
break;
}
remaining -= mid.len;
n -= mid.len;
}
assert(n <= r.buffer.len);
r.end = n;
remaining = try readVecInner(r, data[i + 1 ..], buf[copy_len..], remaining);
break;
}
return @intFromEnum(limit) - remaining;
}
fn readVecInner(r: *Reader, middle: []const []u8, first: []u8, remaining: usize) Error!usize {
var wrapper: Writer.VectorWrapper = .{
.it = .{
.first = first,
.middle = middle,
.last = r.buffer,
},
.writer = .{
.buffer = if (first.len >= r.buffer.len) first else r.buffer,
.vtable = Writer.VectorWrapper.vtable,
},
};
// If the limit may pass beyond user buffer into Reader buffer, use
// unlimited, allowing the Reader buffer to fill.
const limit: Limit = l: {
var n: usize = first.len;
for (middle) |m| n += m.len;
break :l if (remaining >= n) .unlimited else .limited(remaining);
};
var n = r.vtable.stream(r, &wrapper.writer, limit) catch |err| switch (err) {
error.WriteFailed => {
assert(!wrapper.used);
if (wrapper.writer.buffer.ptr == first.ptr) {
return remaining - wrapper.writer.end;
} else {
assert(wrapper.writer.end <= r.buffer.len);
r.end = wrapper.writer.end;
return remaining;
}
},
else => |e| return e,
};
if (!wrapper.used) {
if (wrapper.writer.buffer.ptr == first.ptr) {
return remaining - n;
} else {
assert(n <= r.buffer.len);
r.end = n;
return remaining;
}
}
if (n < first.len) return remaining - n;
var result = remaining - first.len;
n -= first.len;
for (middle) |mid| {
if (n < mid.len) {
return result - n;
}
result -= mid.len;
n -= mid.len;
}
assert(n <= r.buffer.len);
r.end = n;
return result;
}
pub fn buffered(r: *Reader) []u8 {
return r.buffer[r.seek..r.end];
}
@ -580,48 +593,29 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
/// See also:
/// * `readSliceAll`
pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
const in_buffer = r.buffer[r.seek..r.end];
const copy_len = @min(buffer.len, in_buffer.len);
@memcpy(buffer[0..copy_len], in_buffer[0..copy_len]);
if (buffer.len - copy_len == 0) {
r.seek += copy_len;
return buffer.len;
}
var i: usize = copy_len;
r.end = 0;
r.seek = 0;
var i: usize = 0;
while (true) {
const buffer_contents = r.buffer[r.seek..r.end];
const dest = buffer[i..];
const copy_len = @min(dest.len, buffer_contents.len);
@memcpy(dest[0..copy_len], buffer_contents[0..copy_len]);
if (dest.len - copy_len == 0) {
@branchHint(.likely);
r.seek += copy_len;
return buffer.len;
}
i += copy_len;
r.end = 0;
r.seek = 0;
const remaining = buffer[i..];
var wrapper: Writer.VectorWrapper = .{
.it = .{
.first = remaining,
.last = r.buffer,
},
.writer = .{
.buffer = if (remaining.len >= r.buffer.len) remaining else r.buffer,
.vtable = Writer.VectorWrapper.vtable,
},
};
const n = r.vtable.stream(r, &wrapper.writer, .unlimited) catch |err| switch (err) {
error.WriteFailed => {
if (!wrapper.used) {
assert(r.seek == 0);
r.seek = remaining.len;
r.end = wrapper.writer.end;
@memcpy(remaining, r.buffer[0..remaining.len]);
}
return buffer.len;
},
const new_remaining_len = readVecInner(r, &.{}, remaining, remaining.len) catch |err| switch (err) {
error.EndOfStream => return i,
error.ReadFailed => return error.ReadFailed,
};
if (n < remaining.len) {
i += n;
continue;
}
r.end = n - remaining.len;
return buffer.len;
if (new_remaining_len == 0) return buffer.len;
i += remaining.len - new_remaining_len;
}
return buffer.len;
}
/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
@ -1627,6 +1621,19 @@ test readSliceShort {
try testing.expectEqual(0, try r.readSliceShort(&buf));
}
test "readSliceShort with smaller buffer than Reader" {
var reader_buf: [15]u8 = undefined;
const str = "This is a test";
var one_byte_stream: testing.Reader = .init(&reader_buf, &.{
.{ .buffer = str },
});
one_byte_stream.artificial_limit = .limited(1);
var buf: [14]u8 = undefined;
try testing.expectEqual(14, try one_byte_stream.interface.readSliceShort(&buf));
try testing.expectEqualStrings(str, &buf);
}
test readVec {
var r: Reader = .fixed(std.ascii.letters);
var flat_buffer: [52]u8 = undefined;
@ -1689,33 +1696,13 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize {
}
test "readAlloc when the backing reader provides one byte at a time" {
const OneByteReader = struct {
str: []const u8,
i: usize,
reader: Reader,
fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
assert(@intFromEnum(limit) >= 1);
const self: *@This() = @fieldParentPtr("reader", r);
if (self.str.len - self.i == 0) return error.EndOfStream;
try w.writeByte(self.str[self.i]);
self.i += 1;
return 1;
}
};
const str = "This is a test";
var tiny_buffer: [1]u8 = undefined;
var one_byte_stream: OneByteReader = .{
.str = str,
.i = 0,
.reader = .{
.buffer = &tiny_buffer,
.vtable = &.{ .stream = OneByteReader.stream },
.seek = 0,
.end = 0,
},
};
const res = try one_byte_stream.reader.allocRemaining(std.testing.allocator, .unlimited);
var one_byte_stream: testing.Reader = .init(&tiny_buffer, &.{
.{ .buffer = str },
});
one_byte_stream.artificial_limit = .limited(1);
const res = try one_byte_stream.interface.allocRemaining(std.testing.allocator, .unlimited);
defer std.testing.allocator.free(res);
try std.testing.expectEqualStrings(str, res);
}

View File

@ -483,7 +483,7 @@ pub fn writeSplatAll(w: *Writer, data: [][]const u8, splat: usize) Error!void {
// Deal with any left over splats
if (data.len != 0 and truncate < data[index].len * splat) {
std.debug.assert(index == data.len - 1);
assert(index == data.len - 1);
var remaining_splat = splat;
while (true) {
remaining_splat -= truncate / data[index].len;
@ -618,10 +618,6 @@ pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) E
/// A user type may be a `struct`, `vector`, `union` or `enum` type.
///
/// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`.
///
/// Asserts `buffer` capacity of at least 2 if a union is printed. This
/// requirement could be lifted by adjusting the code, but if you trigger that
/// assertion it is a clue that you should probably be using a buffer.
pub fn print(w: *Writer, comptime fmt: []const u8, args: anytype) Error!void {
const ArgsType = @TypeOf(args);
const args_type_info = @typeInfo(ArgsType);
@ -840,11 +836,11 @@ pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.builtin.Endian
.auto => @compileError("ill-defined memory layout"),
.@"extern" => {
if (native_endian == endian) {
return w.writeStruct(value);
return w.writeAll(@ptrCast((&value)[0..1]));
} else {
var copy = value;
std.mem.byteSwapAllFields(@TypeOf(value), &copy);
return w.writeStruct(copy);
return w.writeAll(@ptrCast((&copy)[0..1]));
}
},
.@"packed" => {
@ -855,6 +851,9 @@ pub inline fn writeStruct(w: *Writer, value: anytype, endian: std.builtin.Endian
}
}
/// If, `endian` is not native,
/// * Asserts that the buffer storage capacity is at least enough to store `@sizeOf(Elem)`
/// * Asserts that the buffer is aligned enough for `@alignOf(Elem)`.
pub inline fn writeSliceEndian(
w: *Writer,
Elem: type,
@ -864,7 +863,22 @@ pub inline fn writeSliceEndian(
if (native_endian == endian) {
return writeAll(w, @ptrCast(slice));
} else {
return w.writeArraySwap(w, Elem, slice);
return writeSliceSwap(w, Elem, slice);
}
}
/// Asserts that the buffer storage capacity is at least enough to store `@sizeOf(Elem)`
///
/// Asserts that the buffer is aligned enough for `@alignOf(Elem)`.
pub fn writeSliceSwap(w: *Writer, Elem: type, slice: []const Elem) Error!void {
var i: usize = 0;
while (i < slice.len) {
const dest_bytes = try w.writableSliceGreedy(@sizeOf(Elem));
const dest: []Elem = @alignCast(@ptrCast(dest_bytes[0 .. dest_bytes.len - dest_bytes.len % @sizeOf(Elem)]));
const copy_len = @min(dest.len, slice.len - i);
@memcpy(dest[0..copy_len], slice[i..][0..copy_len]);
i += copy_len;
std.mem.byteSwapAllElements(Elem, dest);
}
}
@ -1257,14 +1271,13 @@ pub fn printValue(
.@"extern", .@"packed" => {
if (info.fields.len == 0) return w.writeAll(".{}");
try w.writeAll(".{ ");
inline for (info.fields) |field| {
inline for (info.fields, 1..) |field, i| {
try w.writeByte('.');
try w.writeAll(field.name);
try w.writeAll(" = ");
try w.printValue(ANY, options, @field(value, field.name), max_depth - 1);
(try w.writableArray(2)).* = ", ".*;
try w.writeAll(if (i < info.fields.len) ", " else " }");
}
w.buffer[w.end - 2 ..][0..2].* = " }".*;
},
}
},
@ -2475,6 +2488,18 @@ pub const Allocating = struct {
return result;
}
pub fn ensureUnusedCapacity(a: *Allocating, additional_count: usize) Allocator.Error!void {
var list = a.toArrayList();
defer a.setArrayList(list);
return list.ensureUnusedCapacity(a.allocator, additional_count);
}
pub fn ensureTotalCapacity(a: *Allocating, new_capacity: usize) Allocator.Error!void {
var list = a.toArrayList();
defer a.setArrayList(list);
return list.ensureTotalCapacity(a.allocator, new_capacity);
}
pub fn toOwnedSlice(a: *Allocating) error{OutOfMemory}![]u8 {
var list = a.toArrayList();
defer a.setArrayList(list);
@ -2594,8 +2619,40 @@ test "allocating sendFile" {
var file_reader = file_writer.moveToReader();
try file_reader.seekTo(0);
var allocating: std.io.Writer.Allocating = .init(std.testing.allocator);
var allocating: std.io.Writer.Allocating = .init(testing.allocator);
defer allocating.deinit();
_ = try file_reader.interface.streamRemaining(&allocating.writer);
}
test writeStruct {
var buffer: [16]u8 = undefined;
const S = extern struct { a: u64, b: u32, c: u32 };
const s: S = .{ .a = 1, .b = 2, .c = 3 };
{
var w: Writer = .fixed(&buffer);
try w.writeStruct(s, .little);
try testing.expectEqualSlices(u8, &.{
1, 0, 0, 0, 0, 0, 0, 0, //
2, 0, 0, 0, //
3, 0, 0, 0, //
}, &buffer);
}
{
var w: Writer = .fixed(&buffer);
try w.writeStruct(s, .big);
try testing.expectEqualSlices(u8, &.{
0, 0, 0, 0, 0, 0, 0, 1, //
0, 0, 0, 2, //
0, 0, 0, 3, //
}, &buffer);
}
}
test writeSliceEndian {
var buffer: [4]u8 align(2) = undefined;
var w: Writer = .fixed(&buffer);
const array: [2]u16 = .{ 0x1234, 0x5678 };
try writeSliceEndian(&w, u16, &array, .big);
try testing.expectEqualSlices(u8, &.{ 0x12, 0x34, 0x56, 0x78 }, &buffer);
}

View File

@ -633,6 +633,7 @@ pub fn lockStderrWriter(buffer: []u8) *Writer {
pub fn unlockStderrWriter() void {
stderr_writer.flush() catch {};
stderr_writer.end = 0;
stderr_writer.buffer = &.{};
stderr_mutex.unlock();
}

View File

@ -566,6 +566,13 @@ pub fn assertReadable(slice: []const volatile u8) void {
for (slice) |*byte| _ = byte.*;
}
/// Invokes detectable illegal behavior when the provided array is not aligned
/// to the provided amount.
pub fn assertAligned(ptr: anytype, comptime alignment: std.mem.Alignment) void {
const aligned_ptr: *align(alignment.toByteUnits()) anyopaque = @alignCast(@ptrCast(ptr));
_ = aligned_ptr;
}
/// Equivalent to `@panic` but with a formatted message.
pub fn panic(comptime format: []const u8, args: anytype) noreturn {
@branchHint(.cold);

View File

@ -10,6 +10,7 @@ const std = @import("../std.zig");
const math = std.math;
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
/// Returns e raised to the power of x, minus 1 (e^x - 1). This is more accurate than exp(e, x) - 1
/// when x is near 0.
@ -39,9 +40,9 @@ fn expm1_32(x_: f32) f32 {
const Q2: f32 = 1.5807170421e-3;
var x = x_;
const ux = @as(u32, @bitCast(x));
const ux: u32 = @bitCast(x);
const hx = ux & 0x7FFFFFFF;
const sign = hx >> 31;
const sign = ux >> 31;
// TODO: Shouldn't need this check explicitly.
if (math.isNegativeInf(x)) {
@ -147,7 +148,7 @@ fn expm1_32(x_: f32) f32 {
return y - 1.0;
}
const uf = @as(f32, @bitCast(@as(u32, @intCast(0x7F -% k)) << 23));
const uf: f32 = @bitCast(@as(u32, @intCast(0x7F -% k)) << 23);
if (k < 23) {
return (x - e + (1 - uf)) * twopk;
} else {
@ -286,39 +287,77 @@ fn expm1_64(x_: f64) f64 {
}
}
test expm1 {
try expect(expm1(@as(f32, 0.0)) == expm1_32(0.0));
try expect(expm1(@as(f64, 0.0)) == expm1_64(0.0));
}
test expm1_32 {
const epsilon = 0.000001;
test "expm1_32() special" {
try expect(math.isPositiveZero(expm1_32(0.0)));
try expect(math.approxEqAbs(f32, expm1_32(0.0), 0.0, epsilon));
try expect(math.approxEqAbs(f32, expm1_32(0.2), 0.221403, epsilon));
try expect(math.approxEqAbs(f32, expm1_32(0.8923), 1.440737, epsilon));
try expect(math.approxEqAbs(f32, expm1_32(1.5), 3.481689, epsilon));
}
test expm1_64 {
const epsilon = 0.000001;
try expect(math.isPositiveZero(expm1_64(0.0)));
try expect(math.approxEqAbs(f64, expm1_64(0.0), 0.0, epsilon));
try expect(math.approxEqAbs(f64, expm1_64(0.2), 0.221403, epsilon));
try expect(math.approxEqAbs(f64, expm1_64(0.8923), 1.440737, epsilon));
try expect(math.approxEqAbs(f64, expm1_64(1.5), 3.481689, epsilon));
}
test "expm1_32.special" {
try expect(math.isPositiveInf(expm1_32(math.inf(f32))));
try expect(expm1_32(-math.inf(f32)) == -1.0);
try expect(math.isNegativeZero(expm1_32(-0.0)));
try expectEqual(expm1_32(math.ln2), 1.0);
try expectEqual(expm1_32(math.inf(f32)), math.inf(f32));
try expectEqual(expm1_32(-math.inf(f32)), -1.0);
try expect(math.isNan(expm1_32(math.nan(f32))));
try expect(math.isNan(expm1_32(math.snan(f32))));
}
test "expm1_64.special" {
try expect(math.isPositiveInf(expm1_64(math.inf(f64))));
try expect(expm1_64(-math.inf(f64)) == -1.0);
try expect(math.isNan(expm1_64(math.nan(f64))));
test "expm1_32() sanity" {
try expectEqual(expm1_32(-0x1.0223a0p+3), -0x1.ffd6e0p-1);
try expectEqual(expm1_32(0x1.161868p+2), 0x1.30712ap+6);
try expectEqual(expm1_32(-0x1.0c34b4p+3), -0x1.ffe1fap-1);
try expectEqual(expm1_32(-0x1.a206f0p+2), -0x1.ff4116p-1);
try expectEqual(expm1_32(0x1.288bbcp+3), 0x1.4ab480p+13); // Disagrees with GCC in last bit
try expectEqual(expm1_32(0x1.52efd0p-1), 0x1.e09536p-1);
try expectEqual(expm1_32(-0x1.a05cc8p-2), -0x1.561c3ep-2);
try expectEqual(expm1_32(0x1.1f9efap-1), 0x1.81ec4ep-1);
try expectEqual(expm1_32(0x1.8c5db0p-1), 0x1.2b3364p+0);
try expectEqual(expm1_32(-0x1.5b86eap-1), -0x1.f8951ap-2);
}
test "expm1_32() boundary" {
// TODO: The last value before inf is actually 0x1.62e300p+6 -> 0x1.ff681ep+127
// try expectEqual(expm1_32(0x1.62e42ep+6), 0x1.ffff08p+127); // Last value before result is inf
try expectEqual(expm1_32(0x1.62e430p+6), math.inf(f32)); // First value that gives inf
try expectEqual(expm1_32(0x1.fffffep+127), math.inf(f32)); // Max input value
try expectEqual(expm1_32(0x1p-149), 0x1p-149); // Min positive input value
try expectEqual(expm1_32(-0x1p-149), -0x1p-149); // Min negative input value
try expectEqual(expm1_32(0x1p-126), 0x1p-126); // First positive subnormal input
try expectEqual(expm1_32(-0x1p-126), -0x1p-126); // First negative subnormal input
try expectEqual(expm1_32(0x1.fffffep-125), 0x1.fffffep-125); // Last positive value before subnormal
try expectEqual(expm1_32(-0x1.fffffep-125), -0x1.fffffep-125); // Last negative value before subnormal
try expectEqual(expm1_32(-0x1.154244p+4), -0x1.fffffep-1); // Last value before result is -1
try expectEqual(expm1_32(-0x1.154246p+4), -1); // First value where result is -1
}
test "expm1_64() special" {
try expect(math.isPositiveZero(expm1_64(0.0)));
try expect(math.isNegativeZero(expm1_64(-0.0)));
try expectEqual(expm1_64(math.ln2), 1.0);
try expectEqual(expm1_64(math.inf(f64)), math.inf(f64));
try expectEqual(expm1_64(-math.inf(f64)), -1.0);
try expect(math.isNan(expm1_64(math.nan(f64))));
try expect(math.isNan(expm1_64(math.snan(f64))));
}
test "expm1_64() sanity" {
try expectEqual(expm1_64(-0x1.02239f3c6a8f1p+3), -0x1.ffd6df9b02b3ep-1);
try expectEqual(expm1_64(0x1.161868e18bc67p+2), 0x1.30712ed238c04p+6);
try expectEqual(expm1_64(-0x1.0c34b3e01e6e7p+3), -0x1.ffe1f94e493e7p-1);
try expectEqual(expm1_64(-0x1.a206f0a19dcc4p+2), -0x1.ff4115c03f78dp-1);
try expectEqual(expm1_64(0x1.288bbb0d6a1e6p+3), 0x1.4ab477496e07ep+13);
try expectEqual(expm1_64(0x1.52efd0cd80497p-1), 0x1.e095382100a01p-1);
try expectEqual(expm1_64(-0x1.a05cc754481d1p-2), -0x1.561c3e0582be6p-2);
try expectEqual(expm1_64(0x1.1f9ef934745cbp-1), 0x1.81ec4cd4d4a8fp-1);
try expectEqual(expm1_64(0x1.8c5db097f7442p-1), 0x1.2b3363a944bf7p+0);
try expectEqual(expm1_64(-0x1.5b86ea8118a0ep-1), -0x1.f8951aebffbafp-2);
}
test "expm1_64() boundary" {
try expectEqual(expm1_64(0x1.62e42fefa39efp+9), 0x1.fffffffffff2ap+1023); // Last value before result is inf
try expectEqual(expm1_64(0x1.62e42fefa39f0p+9), math.inf(f64)); // First value that gives inf
try expectEqual(expm1_64(0x1.fffffffffffffp+1023), math.inf(f64)); // Max input value
try expectEqual(expm1_64(0x1p-1074), 0x1p-1074); // Min positive input value
try expectEqual(expm1_64(-0x1p-1074), -0x1p-1074); // Min negative input value
try expectEqual(expm1_64(0x1p-1022), 0x1p-1022); // First positive subnormal input
try expectEqual(expm1_64(-0x1p-1022), -0x1p-1022); // First negative subnormal input
try expectEqual(expm1_64(0x1.fffffffffffffp-1021), 0x1.fffffffffffffp-1021); // Last positive value before subnormal
try expectEqual(expm1_64(-0x1.fffffffffffffp-1021), -0x1.fffffffffffffp-1021); // Last negative value before subnormal
try expectEqual(expm1_64(-0x1.2b708872320e1p+5), -0x1.fffffffffffffp-1); // Last value before result is -1
try expectEqual(expm1_64(-0x1.2b708872320e2p+5), -1); // First value where result is -1
}

View File

@ -8,6 +8,7 @@ const std = @import("../std.zig");
const math = std.math;
const mem = std.mem;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
/// Returns the natural logarithm of 1 + x with greater accuracy when x is near zero.
///
@ -182,49 +183,72 @@ fn log1p_64(x: f64) f64 {
return s * (hfsq + R) + (dk * ln2_lo + c) - hfsq + f + dk * ln2_hi;
}
test log1p {
try expect(log1p(@as(f32, 0.0)) == log1p_32(0.0));
try expect(log1p(@as(f64, 0.0)) == log1p_64(0.0));
}
test log1p_32 {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f32, log1p_32(0.0), 0.0, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(0.2), 0.182322, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(0.8923), 0.637793, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(1.5), 0.916291, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(37.45), 3.649359, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(89.123), 4.501175, epsilon));
try expect(math.approxEqAbs(f32, log1p_32(123123.234375), 11.720949, epsilon));
}
test log1p_64 {
const epsilon = 0.000001;
try expect(math.approxEqAbs(f64, log1p_64(0.0), 0.0, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(0.2), 0.182322, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(0.8923), 0.637793, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(1.5), 0.916291, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(37.45), 3.649359, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(89.123), 4.501175, epsilon));
try expect(math.approxEqAbs(f64, log1p_64(123123.234375), 11.720949, epsilon));
}
test "log1p_32.special" {
try expect(math.isPositiveInf(log1p_32(math.inf(f32))));
test "log1p_32() special" {
try expect(math.isPositiveZero(log1p_32(0.0)));
try expect(math.isNegativeZero(log1p_32(-0.0)));
try expect(math.isNegativeInf(log1p_32(-1.0)));
try expectEqual(log1p_32(-1.0), -math.inf(f32));
try expectEqual(log1p_32(1.0), math.ln2);
try expectEqual(log1p_32(math.inf(f32)), math.inf(f32));
try expect(math.isNan(log1p_32(-2.0)));
try expect(math.isNan(log1p_32(-math.inf(f32))));
try expect(math.isNan(log1p_32(math.nan(f32))));
try expect(math.isNan(log1p_32(math.snan(f32))));
}
test "log1p_64.special" {
try expect(math.isPositiveInf(log1p_64(math.inf(f64))));
test "log1p_32() sanity" {
try expect(math.isNan(log1p_32(-0x1.0223a0p+3)));
try expectEqual(log1p_32(0x1.161868p+2), 0x1.ad1bdcp+0);
try expect(math.isNan(log1p_32(-0x1.0c34b4p+3)));
try expect(math.isNan(log1p_32(-0x1.a206f0p+2)));
try expectEqual(log1p_32(0x1.288bbcp+3), 0x1.2a1ab8p+1);
try expectEqual(log1p_32(0x1.52efd0p-1), 0x1.041a4ep-1);
try expectEqual(log1p_32(-0x1.a05cc8p-2), -0x1.0b3596p-1);
try expectEqual(log1p_32(0x1.1f9efap-1), 0x1.c88344p-2);
try expectEqual(log1p_32(0x1.8c5db0p-1), 0x1.258a8ep-1);
try expectEqual(log1p_32(-0x1.5b86eap-1), -0x1.22b542p+0);
}
test "log1p_32() boundary" {
try expectEqual(log1p_32(0x1.fffffep+127), 0x1.62e430p+6); // Max input value
try expectEqual(log1p_32(0x1p-149), 0x1p-149); // Min positive input value
try expectEqual(log1p_32(-0x1p-149), -0x1p-149); // Min negative input value
try expectEqual(log1p_32(0x1p-126), 0x1p-126); // First subnormal
try expectEqual(log1p_32(-0x1p-126), -0x1p-126); // First negative subnormal
try expectEqual(log1p_32(-0x1.fffffep-1), -0x1.0a2b24p+4); // Last value before result is -inf
try expect(math.isNan(log1p_32(-0x1.000002p+0))); // First value where result is nan
}
test "log1p_64() special" {
try expect(math.isPositiveZero(log1p_64(0.0)));
try expect(math.isNegativeZero(log1p_64(-0.0)));
try expect(math.isNegativeInf(log1p_64(-1.0)));
try expectEqual(log1p_64(-1.0), -math.inf(f64));
try expectEqual(log1p_64(1.0), math.ln2);
try expectEqual(log1p_64(math.inf(f64)), math.inf(f64));
try expect(math.isNan(log1p_64(-2.0)));
try expect(math.isNan(log1p_64(-math.inf(f64))));
try expect(math.isNan(log1p_64(math.nan(f64))));
try expect(math.isNan(log1p_64(math.snan(f64))));
}
test "log1p_64() sanity" {
try expect(math.isNan(log1p_64(-0x1.02239f3c6a8f1p+3)));
try expectEqual(log1p_64(0x1.161868e18bc67p+2), 0x1.ad1bdd1e9e686p+0); // Disagrees with GCC in last bit
try expect(math.isNan(log1p_64(-0x1.0c34b3e01e6e7p+3)));
try expect(math.isNan(log1p_64(-0x1.a206f0a19dcc4p+2)));
try expectEqual(log1p_64(0x1.288bbb0d6a1e6p+3), 0x1.2a1ab8365b56fp+1);
try expectEqual(log1p_64(0x1.52efd0cd80497p-1), 0x1.041a4ec2a680ap-1);
try expectEqual(log1p_64(-0x1.a05cc754481d1p-2), -0x1.0b3595423aec1p-1);
try expectEqual(log1p_64(0x1.1f9ef934745cbp-1), 0x1.c8834348a846ep-2);
try expectEqual(log1p_64(0x1.8c5db097f7442p-1), 0x1.258a8e8a35bbfp-1);
try expectEqual(log1p_64(-0x1.5b86ea8118a0ep-1), -0x1.22b5426327502p+0);
}
test "log1p_64() boundary" {
try expectEqual(log1p_64(0x1.fffffffffffffp+1023), 0x1.62e42fefa39efp+9); // Max input value
try expectEqual(log1p_64(0x1p-1074), 0x1p-1074); // Min positive input value
try expectEqual(log1p_64(-0x1p-1074), -0x1p-1074); // Min negative input value
try expectEqual(log1p_64(0x1p-1022), 0x1p-1022); // First subnormal
try expectEqual(log1p_64(-0x1p-1022), -0x1p-1022); // First negative subnormal
try expectEqual(log1p_64(-0x1.fffffffffffffp-1), -0x1.25e4f7b2737fap+5); // Last value before result is -inf
try expect(math.isNan(log1p_64(-0x1.0000000000001p+0))); // First value where result is nan
}

View File

@ -2179,22 +2179,8 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
const BackingInt = std.meta.Int(.unsigned, @bitSizeOf(S));
ptr.* = @bitCast(@byteSwap(@as(BackingInt, @bitCast(ptr.*))));
},
.array => {
for (ptr) |*item| {
switch (@typeInfo(@TypeOf(item.*))) {
.@"struct", .@"union", .array => byteSwapAllFields(@TypeOf(item.*), item),
.@"enum" => {
item.* = @enumFromInt(@byteSwap(@intFromEnum(item.*)));
},
.bool => {},
.float => |float_info| {
item.* = @bitCast(@byteSwap(@as(std.meta.Int(.unsigned, float_info.bits), @bitCast(item.*))));
},
else => {
item.* = @byteSwap(item.*);
},
}
}
.array => |info| {
byteSwapAllElements(info.child, ptr);
},
else => {
ptr.* = @byteSwap(ptr.*);
@ -2258,6 +2244,24 @@ test byteSwapAllFields {
}, k);
}
pub fn byteSwapAllElements(comptime Elem: type, slice: []Elem) void {
for (slice) |*elem| {
switch (@typeInfo(@TypeOf(elem.*))) {
.@"struct", .@"union", .array => byteSwapAllFields(@TypeOf(elem.*), elem),
.@"enum" => {
elem.* = @enumFromInt(@byteSwap(@intFromEnum(elem.*)));
},
.bool => {},
.float => |float_info| {
elem.* = @bitCast(@byteSwap(@as(std.meta.Int(.unsigned, float_info.bits), @bitCast(elem.*))));
},
else => {
elem.* = @byteSwap(elem.*);
},
}
}
}
/// Returns an iterator that iterates over the slices of `buffer` that are not
/// any of the items in `delimiters`.
///

View File

@ -214,7 +214,7 @@ pub const File = extern struct {
pub fn getInfo(
self: *const File,
comptime info: std.meta.Tag(Info),
buffer: []u8,
buffer: []align(@alignOf(@FieldType(Info, @tagName(info)))) u8,
) GetInfoError!*@FieldType(Info, @tagName(info)) {
const InfoType = @FieldType(Info, @tagName(info));

View File

@ -1210,12 +1210,14 @@ pub inline fn fuzz(
return @import("root").fuzz(context, testOne, options);
}
/// A `std.io.Reader` that writes a predetermined list of buffers during `stream`.
/// A `std.Io.Reader` that writes a predetermined list of buffers during `stream`.
pub const Reader = struct {
calls: []const Call,
interface: std.io.Reader,
interface: std.Io.Reader,
next_call_index: usize,
next_offset: usize,
/// Further reduces how many bytes are written in each `stream` call.
artificial_limit: std.Io.Limit = .unlimited,
pub const Call = struct {
buffer: []const u8,
@ -1235,11 +1237,11 @@ pub const Reader = struct {
};
}
fn stream(io_r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {
fn stream(io_r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
const r: *Reader = @alignCast(@fieldParentPtr("interface", io_r));
if (r.calls.len - r.next_call_index == 0) return error.EndOfStream;
const call = r.calls[r.next_call_index];
const buffer = limit.sliceConst(call.buffer[r.next_offset..]);
const buffer = r.artificial_limit.sliceConst(limit.sliceConst(call.buffer[r.next_offset..]));
const n = try w.write(buffer);
r.next_offset += n;
if (call.buffer.len - r.next_offset == 0) {

View File

@ -536,7 +536,8 @@ pub fn readSourceFileToEndAlloc(gpa: Allocator, file_reader: *std.fs.File.Reader
if (file_reader.getSize()) |size| {
const casted_size = std.math.cast(u32, size) orelse return error.StreamTooLong;
try buffer.ensureTotalCapacityPrecise(gpa, casted_size);
// +1 to avoid resizing for the null byte added in toOwnedSliceSentinel below.
try buffer.ensureTotalCapacityPrecise(gpa, casted_size + 1);
} else |_| {}
try file_reader.interface.appendRemaining(gpa, .@"2", &buffer, .limited(max_src_size));
@ -904,4 +905,5 @@ test {
_ = system;
_ = target;
_ = c_translation;
_ = llvm;
}

View File

@ -484,8 +484,7 @@ fn findNativeKernel32LibDir(
for (installs) |install| {
result_buf.shrinkAndFree(0);
const stream = result_buf.writer();
try stream.print("{s}\\Lib\\{s}\\um\\{s}", .{ install.path, install.version, arch_sub_dir });
try result_buf.print("{s}\\Lib\\{s}\\um\\{s}", .{ install.path, install.version, arch_sub_dir });
var dir = fs.cwd().openDir(result_buf.items, .{}) catch |err| switch (err) {
error.FileNotFound,

View File

@ -118,6 +118,8 @@ pub fn init(options: Options) !Server {
.in = options.in,
.out = options.out,
};
assert(s.out.buffer.len >= 4);
std.debug.assertAligned(s.out.buffer.ptr, .@"4");
try s.serveStringMessage(.zig_version, options.zig_version);
return s;
}
@ -141,7 +143,7 @@ pub fn serveStringMessage(s: *Server, tag: OutMessage.Tag, msg: []const u8) !voi
/// Don't forget to flush!
pub fn serveMessageHeader(s: *const Server, header: OutMessage.Header) !void {
try s.out.writeStructEndian(header, .little);
try s.out.writeStruct(header, .little);
}
pub fn serveU64Message(s: *const Server, tag: OutMessage.Tag, int: u64) !void {
@ -162,7 +164,7 @@ pub fn serveEmitDigest(
.tag = .emit_digest,
.bytes_len = @intCast(digest.len + @sizeOf(OutMessage.EmitDigest)),
});
try s.out.writeStructEndian(header, .little);
try s.out.writeStruct(header, .little);
try s.out.writeAll(digest);
try s.out.flush();
}
@ -172,7 +174,7 @@ pub fn serveTestResults(s: *Server, msg: OutMessage.TestResults) !void {
.tag = .test_results,
.bytes_len = @intCast(@sizeOf(OutMessage.TestResults)),
});
try s.out.writeStructEndian(msg, .little);
try s.out.writeStruct(msg, .little);
try s.out.flush();
}
@ -187,7 +189,7 @@ pub fn serveErrorBundle(s: *Server, error_bundle: std.zig.ErrorBundle) !void {
.tag = .error_bundle,
.bytes_len = @intCast(bytes_len),
});
try s.out.writeStructEndian(eb_hdr, .little);
try s.out.writeStruct(eb_hdr, .little);
try s.out.writeSliceEndian(u32, error_bundle.extra, .little);
try s.out.writeAll(error_bundle.string_bytes);
try s.out.flush();
@ -212,7 +214,7 @@ pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void {
.tag = .test_metadata,
.bytes_len = @intCast(bytes_len),
});
try s.out.writeStructEndian(header, .little);
try s.out.writeStruct(header, .little);
try s.out.writeSliceEndian(u32, test_metadata.names, .little);
try s.out.writeSliceEndian(u32, test_metadata.expected_panic_msgs, .little);
try s.out.writeAll(test_metadata.string_bytes);

View File

@ -1,7 +1,7 @@
const WindowsSdk = @This();
const builtin = @import("builtin");
const std = @import("std");
const Writer = std.io.Writer;
const Writer = std.Io.Writer;
windows10sdk: ?Installation,
windows81sdk: ?Installation,
@ -760,13 +760,13 @@ const MsvcLibDir = struct {
while (instances_dir_it.next() catch return error.PathNotFound) |entry| {
if (entry.kind != .directory) continue;
var bw: Writer = .fixed(&state_subpath_buf);
var writer: Writer = .fixed(&state_subpath_buf);
bw.writeAll(entry.name) catch unreachable;
bw.writeByte(std.fs.path.sep) catch unreachable;
bw.writeAll("state.json") catch unreachable;
writer.writeAll(entry.name) catch unreachable;
writer.writeByte(std.fs.path.sep) catch unreachable;
writer.writeAll("state.json") catch unreachable;
const json_contents = instances_dir.readFileAlloc(allocator, bw.getWritten(), std.math.maxInt(usize)) catch continue;
const json_contents = instances_dir.readFileAlloc(allocator, writer.buffered(), std.math.maxInt(usize)) catch continue;
defer allocator.free(json_contents);
var parsed = std.json.parseFromSlice(std.json.Value, allocator, json_contents, .{}) catch continue;

View File

@ -1,3 +1,9 @@
pub const BitcodeReader = @import("llvm/BitcodeReader.zig");
pub const bitcode_writer = @import("llvm/bitcode_writer.zig");
pub const Builder = @import("llvm/Builder.zig");
test {
_ = BitcodeReader;
_ = bitcode_writer;
_ = Builder;
}

View File

@ -177,7 +177,7 @@ pub fn next(bc: *BitcodeReader) !?Item {
pub fn skipBlock(bc: *BitcodeReader, block: Block) !void {
assert(bc.bit_offset == 0);
try bc.reader.discard(4 * @as(u34, block.len));
try bc.reader.discardAll(4 * @as(u34, block.len));
try bc.endBlock();
}
@ -513,3 +513,7 @@ const Abbrev = struct {
}
};
};
test {
_ = &skipBlock;
}

View File

@ -1,7 +1,6 @@
const std = @import("std");
const mem = std.mem;
const Tokenizer = std.zig.Tokenizer;
const io = std.io;
const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
const source = @embedFile("../os.zig");
@ -22,16 +21,15 @@ pub fn main() !void {
const bytes_per_sec_float = @as(f64, @floatFromInt(source.len * iterations)) / elapsed_s;
const bytes_per_sec = @as(u64, @intFromFloat(@floor(bytes_per_sec_float)));
var stdout_file: std.fs.File = .stdout();
const stdout = stdout_file.writer();
try stdout.print("parsing speed: {:.2}/s, {:.2} used \n", .{
fmtIntSizeBin(bytes_per_sec),
fmtIntSizeBin(memory_used),
});
var stdout_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
try stdout.print("parsing speed: {Bi:.2}/s, {Bi:.2} used \n", .{ bytes_per_sec, memory_used });
try stdout.flush();
}
fn testOnce() usize {
var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(&fixed_buffer_mem);
const allocator = fixed_buf_alloc.allocator();
_ = std.zig.Ast.parse(allocator, source, .zig) catch @panic("parse failure");
return fixed_buf_alloc.end_index;

View File

@ -379,15 +379,18 @@ inline fn getAArch64CpuFeature(comptime feat_reg: []const u8) u64 {
}
pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
var f = fs.openFileAbsolute("/proc/cpuinfo", .{}) catch |err| switch (err) {
var file = fs.openFileAbsolute("/proc/cpuinfo", .{}) catch |err| switch (err) {
else => return null,
};
defer f.close();
defer file.close();
var buffer: [4096]u8 = undefined; // "flags" lines can get pretty long.
var file_reader = file.reader(&buffer);
const current_arch = builtin.cpu.arch;
switch (current_arch) {
.arm, .armeb, .thumb, .thumbeb => {
return ArmCpuinfoParser.parse(current_arch, f.deprecatedReader()) catch null;
return ArmCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
},
.aarch64, .aarch64_be => {
const registers = [12]u64{
@ -409,13 +412,13 @@ pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
return core;
},
.sparc64 => {
return SparcCpuinfoParser.parse(current_arch, f.deprecatedReader()) catch null;
return SparcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
},
.powerpc, .powerpcle, .powerpc64, .powerpc64le => {
return PowerpcCpuinfoParser.parse(current_arch, f.deprecatedReader()) catch null;
return PowerpcCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
},
.riscv64, .riscv32 => {
return RiscvCpuinfoParser.parse(current_arch, f.deprecatedReader()) catch null;
return RiscvCpuinfoParser.parse(current_arch, &file_reader.interface) catch null;
},
else => {},
}

View File

@ -411,16 +411,22 @@ const Parser = struct {
diag: ?*Diagnostics,
options: Options,
fn parseExpr(self: *@This(), T: type, node: Zoir.Node.Index) error{ ParseZon, OutOfMemory }!T {
const ParseExprError = error{ ParseZon, OutOfMemory };
fn parseExpr(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprError!T {
return self.parseExprInner(T, node) catch |err| switch (err) {
error.WrongType => return self.failExpectedType(T, node),
else => |e| return e,
};
}
const InnerError = error{ ParseZon, OutOfMemory, WrongType };
const ParseExprInnerError = error{ ParseZon, OutOfMemory, WrongType };
fn parseExprInner(self: *@This(), T: type, node: Zoir.Node.Index) InnerError!T {
fn parseExprInner(
self: *@This(),
T: type,
node: Zoir.Node.Index,
) ParseExprInnerError!T {
if (T == Zoir.Node.Index) {
return node;
}
@ -600,7 +606,7 @@ const Parser = struct {
}
}
fn parseSlicePointer(self: *@This(), T: type, node: Zoir.Node.Index) InnerError!T {
fn parseSlicePointer(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
switch (node.get(self.zoir)) {
.string_literal => return self.parseString(T, node),
.array_literal => |nodes| return self.parseSlice(T, nodes),
@ -609,19 +615,17 @@ const Parser = struct {
}
}
fn parseString(self: *@This(), T: type, node: Zoir.Node.Index) InnerError!T {
fn parseString(self: *@This(), T: type, node: Zoir.Node.Index) ParseExprInnerError!T {
const ast_node = node.getAstNode(self.zoir);
const pointer = @typeInfo(T).pointer;
var size_hint = ZonGen.strLitSizeHint(self.ast, ast_node);
if (pointer.sentinel() != null) size_hint += 1;
const gpa = self.gpa;
var aw = try std.io.Writer.Allocating.initCapacity(gpa, size_hint);
var aw: std.Io.Writer.Allocating = .init(self.gpa);
try aw.ensureUnusedCapacity(size_hint);
defer aw.deinit();
const parsed = ZonGen.parseStrLit(self.ast, ast_node, &aw.interface) catch |err| switch (err) {
error.WriteFailed => return error.OutOfMemory,
};
switch (parsed) {
const result = ZonGen.parseStrLit(self.ast, ast_node, &aw.writer) catch return error.OutOfMemory;
switch (result) {
.success => {},
.failure => |err| {
const token = self.ast.nodeMainToken(ast_node);

View File

@ -687,7 +687,7 @@ pub const Directories = struct {
global,
},
wasi_preopens: switch (builtin.target.os.tag) {
.wasi => std.fs.wasi.Preopens,
.wasi => fs.wasi.Preopens,
else => void,
},
self_exe_path: switch (builtin.target.os.tag) {
@ -744,7 +744,7 @@ pub const Directories = struct {
.local_cache = local_cache,
};
}
fn openWasiPreopen(preopens: std.fs.wasi.Preopens, name: []const u8) Cache.Directory {
fn openWasiPreopen(preopens: fs.wasi.Preopens, name: []const u8) Cache.Directory {
return .{
.path = if (std.mem.eql(u8, name, ".")) null else name,
.handle = .{
@ -758,8 +758,8 @@ pub const Directories = struct {
};
const nonempty_path = if (path.len == 0) "." else path;
const handle_or_err = switch (thing) {
.@"zig lib" => std.fs.cwd().openDir(nonempty_path, .{}),
.@"global cache", .@"local cache" => std.fs.cwd().makeOpenPath(nonempty_path, .{}),
.@"zig lib" => fs.cwd().openDir(nonempty_path, .{}),
.@"global cache", .@"local cache" => fs.cwd().makeOpenPath(nonempty_path, .{}),
};
return .{
.path = if (path.len == 0) null else path,
@ -996,15 +996,15 @@ pub const CObject = struct {
const source_line = source_line: {
if (diag.src_loc.offset == 0 or diag.src_loc.column == 0) break :source_line 0;
const file = std.fs.cwd().openFile(file_name, .{}) catch break :source_line 0;
const file = fs.cwd().openFile(file_name, .{}) catch break :source_line 0;
defer file.close();
var buffer: [1 << 10]u8 = undefined;
var fr = file.reader(&buffer);
fr.seekTo(diag.src_loc.offset + 1 - diag.src_loc.column) catch break :source_line 0;
var bw: Writer = .fixed(&buffer);
break :source_line try eb.addString(
buffer[0 .. fr.interface.readDelimiterEnding(&bw, '\n') catch break :source_line 0],
);
var buffer: [1024]u8 = undefined;
var file_reader = file.reader(&buffer);
file_reader.seekTo(diag.src_loc.offset + 1 - diag.src_loc.column) catch break :source_line 0;
var aw: Writer.Allocating = .init(eb.gpa);
defer aw.deinit();
_ = file_reader.interface.streamDelimiterEnding(&aw.writer, '\n') catch break :source_line 0;
break :source_line try eb.addString(aw.getWritten());
};
return .{
@ -1071,7 +1071,7 @@ pub const CObject = struct {
};
var buffer: [1024]u8 = undefined;
const file = try std.fs.cwd().openFile(path, .{});
const file = try fs.cwd().openFile(path, .{});
defer file.close();
var file_reader = file.reader(&buffer);
var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = &file_reader.interface });
@ -1876,12 +1876,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
if (options.verbose_llvm_cpu_features) {
if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: {
const stderr_bw = std.debug.lockStderrWriter(&.{});
const stderr_w = std.debug.lockStderrWriter(&.{});
defer std.debug.unlockStderrWriter();
stderr_bw.print("compilation: {s}\n", .{options.root_name}) catch break :print;
stderr_bw.print(" target: {s}\n", .{try target.zigTriple(arena)}) catch break :print;
stderr_bw.print(" cpu: {s}\n", .{target.cpu.model.name}) catch break :print;
stderr_bw.print(" features: {s}\n", .{cf}) catch {};
stderr_w.print("compilation: {s}\n", .{options.root_name}) catch break :print;
stderr_w.print(" target: {s}\n", .{try target.zigTriple(arena)}) catch break :print;
stderr_w.print(" cpu: {s}\n", .{target.cpu.model.name}) catch break :print;
stderr_w.print(" features: {s}\n", .{cf}) catch {};
}
}
@ -1901,7 +1901,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
.manifest_dir = try options.dirs.local_cache.handle.makeOpenPath("h", .{}),
};
// These correspond to std.zig.Server.Message.PathPrefix.
cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
cache.addPrefix(options.dirs.zig_lib);
cache.addPrefix(options.dirs.local_cache);
cache.addPrefix(options.dirs.global_cache);
@ -2192,7 +2192,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
comp.digest = hash.peekBin();
const digest = hash.final();
const artifact_sub_dir = "o" ++ std.fs.path.sep_str ++ digest;
const artifact_sub_dir = "o" ++ fs.path.sep_str ++ digest;
var artifact_dir = try options.dirs.local_cache.handle.makeOpenPath(artifact_sub_dir, .{});
errdefer artifact_dir.close();
const artifact_directory: Cache.Directory = .{
@ -2483,7 +2483,7 @@ pub fn destroy(comp: *Compilation) void {
if (comp.zcu) |zcu| zcu.deinit();
comp.cache_use.deinit();
for (comp.work_queues) |work_queue| work_queue.deinit();
for (&comp.work_queues) |*work_queue| work_queue.deinit();
comp.c_object_work_queue.deinit();
comp.win32_resource_work_queue.deinit();
@ -2604,11 +2604,11 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
// temporary directories; it doesn't have a real cache directory anyway.
return;
}
const tmp_dir_sub_path = "tmp" ++ std.fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
comp.dirs.local_cache.handle.deleteTree(tmp_dir_sub_path) catch |err| {
log.warn("failed to delete temporary directory '{s}{c}{s}': {s}", .{
comp.dirs.local_cache.path orelse ".",
std.fs.path.sep,
fs.path.sep,
tmp_dir_sub_path,
@errorName(err),
});
@ -2628,11 +2628,11 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
if (whole.tmp_artifact_directory) |*tmp_dir| {
tmp_dir.handle.close();
whole.tmp_artifact_directory = null;
const tmp_dir_sub_path = "tmp" ++ std.fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
comp.dirs.local_cache.handle.deleteTree(tmp_dir_sub_path) catch |err| {
log.warn("failed to delete temporary directory '{s}{c}{s}': {s}", .{
comp.dirs.local_cache.path orelse ".",
std.fs.path.sep,
fs.path.sep,
tmp_dir_sub_path,
@errorName(err),
});
@ -2668,7 +2668,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
assert(none.tmp_artifact_directory == null);
none.tmp_artifact_directory = d: {
tmp_dir_rand_int = std.crypto.random.int(u64);
const tmp_dir_sub_path = "tmp" ++ std.fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path});
break :d .{
.path = path,
@ -2735,7 +2735,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
// Compile the artifacts to a temporary directory.
whole.tmp_artifact_directory = d: {
tmp_dir_rand_int = std.crypto.random.int(u64);
const tmp_dir_sub_path = "tmp" ++ std.fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path});
break :d .{
.path = path,
@ -2910,7 +2910,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
// Close tmp dir and link.File to avoid open handle during rename.
whole.tmp_artifact_directory.?.handle.close();
whole.tmp_artifact_directory = null;
const s = std.fs.path.sep_str;
const s = fs.path.sep_str;
const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
const o_sub_path = "o" ++ s ++ hex_digest;
renameTmpIntoCache(comp.dirs.local_cache, tmp_dir_sub_path, o_sub_path) catch |err| {
@ -2932,7 +2932,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
if (comp.bin_file) |lf| {
lf.emit = .{
.root_dir = comp.dirs.local_cache,
.sub_path = try std.fs.path.join(arena, &.{ o_sub_path, comp.emit_bin.? }),
.sub_path = try fs.path.join(arena, &.{ o_sub_path, comp.emit_bin.? }),
};
switch (need_writable_dance) {
@ -3105,7 +3105,7 @@ fn renameTmpIntoCache(
) !void {
var seen_eaccess = false;
while (true) {
std.fs.rename(
fs.rename(
cache_directory.handle,
tmp_dir_sub_path,
cache_directory.handle,
@ -3931,12 +3931,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
// This AU is referenced and has a transitive compile error, meaning it referenced something with a compile error.
// However, we haven't reported any such error.
// This is a compiler bug.
var stderr_bw = std.debug.lockStderrWriter(&.{});
var stderr_w = std.debug.lockStderrWriter(&.{});
defer std.debug.unlockStderrWriter();
try stderr_bw.writeAll("referenced transitive analysis errors, but none actually emitted\n");
try stderr_bw.print("{f} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)});
try stderr_w.writeAll("referenced transitive analysis errors, but none actually emitted\n");
try stderr_w.print("{f} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)});
while (ref) |r| {
try stderr_bw.print("referenced by: {f}{s}\n", .{
try stderr_w.print("referenced by: {f}{s}\n", .{
zcu.fmtAnalUnit(r.referencer),
if (zcu.transitive_failed_analysis.contains(r.referencer)) " [transitive failure]" else "",
});
@ -4843,7 +4843,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
defer out_dir.close();
for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| {
const basename = std.fs.path.basename(sub_path);
const basename = fs.path.basename(sub_path);
comp.dirs.zig_lib.handle.copyFile(sub_path, out_dir, basename, .{}) catch |err| {
comp.lockAndSetMiscFailure(.docs_copy, "unable to copy {s}: {s}", .{
sub_path,
@ -4879,7 +4879,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
}
}
fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, tar_file: std.fs.File) !void {
fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, tar_file: fs.File) !void {
const root = module.root;
var mod_dir = d: {
const root_dir, const sub_path = root.openInfo(comp.dirs);
@ -4974,7 +4974,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
});
const src_basename = "main.zig";
const root_name = std.fs.path.stem(src_basename);
const root_name = fs.path.stem(src_basename);
const dirs = comp.dirs.withoutLocalCache();
@ -5069,13 +5069,13 @@ fn workerUpdateFile(
prog_node: std.Progress.Node,
wg: *WaitGroup,
) void {
const child_prog_node = prog_node.start(std.fs.path.basename(file.path.sub_path), 0);
const child_prog_node = prog_node.start(fs.path.basename(file.path.sub_path), 0);
defer child_prog_node.end();
const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
defer pt.deactivate();
pt.updateFile(file_index, file) catch |err| {
pt.reportRetryableFileError(file_index, "unable to load '{s}': {s}", .{ std.fs.path.basename(file.path.sub_path), @errorName(err) }) catch |oom| switch (oom) {
pt.reportRetryableFileError(file_index, "unable to load '{s}': {s}", .{ fs.path.basename(file.path.sub_path), @errorName(err) }) catch |oom| switch (oom) {
error.OutOfMemory => {
comp.mutex.lock();
defer comp.mutex.unlock();
@ -5240,7 +5240,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
const arena = arena_allocator.allocator();
const tmp_digest = man.hash.peek();
const tmp_dir_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &tmp_digest });
const tmp_dir_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &tmp_digest });
var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{});
defer zig_cache_tmp_dir.close();
const cimport_basename = "cimport.h";
@ -5309,7 +5309,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
log.info("C import .d file: {s}", .{out_dep_path});
}
const dep_basename = std.fs.path.basename(out_dep_path);
const dep_basename = fs.path.basename(out_dep_path);
try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
switch (comp.cache_use) {
.whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| {
@ -5322,14 +5322,14 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
const bin_digest = man.finalBin();
const hex_digest = Cache.binToHex(bin_digest);
const o_sub_path = "o" ++ std.fs.path.sep_str ++ hex_digest;
const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;
var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close();
var out_zig_file = try o_dir.createFile(cimport_zig_basename, .{});
defer out_zig_file.close();
const formatted = try tree.render(comp.gpa);
const formatted = try tree.renderAlloc(comp.gpa);
defer comp.gpa.free(formatted);
try out_zig_file.writeAll(formatted);
@ -5675,7 +5675,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
const c_source_basename = std.fs.path.basename(c_object.src.src_path);
const c_source_basename = fs.path.basename(c_object.src.src_path);
const child_progress_node = c_obj_prog_node.start(c_source_basename, 0);
defer child_progress_node.end();
@ -5688,7 +5688,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
const o_basename_noext = if (direct_o)
comp.root_name
else
c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
c_source_basename[0 .. c_source_basename.len - fs.path.extension(c_source_basename).len];
const target = comp.getTarget();
const o_ext = target.ofmt.fileExt(target.cpu.arch);
@ -5815,11 +5815,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
}
// Just to save disk space, we delete the files that are never needed again.
defer if (out_diag_path) |diag_file_path| zig_cache_tmp_dir.deleteFile(std.fs.path.basename(diag_file_path)) catch |err| switch (err) {
defer if (out_diag_path) |diag_file_path| zig_cache_tmp_dir.deleteFile(fs.path.basename(diag_file_path)) catch |err| switch (err) {
error.FileNotFound => {}, // the file wasn't created due to an error we reported
else => log.warn("failed to delete '{s}': {s}", .{ diag_file_path, @errorName(err) }),
};
defer if (out_dep_path) |dep_file_path| zig_cache_tmp_dir.deleteFile(std.fs.path.basename(dep_file_path)) catch |err| switch (err) {
defer if (out_dep_path) |dep_file_path| zig_cache_tmp_dir.deleteFile(fs.path.basename(dep_file_path)) catch |err| switch (err) {
error.FileNotFound => {}, // the file wasn't created due to an error we reported
else => log.warn("failed to delete '{s}': {s}", .{ dep_file_path, @errorName(err) }),
};
@ -5890,7 +5890,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
}
if (out_dep_path) |dep_file_path| {
const dep_basename = std.fs.path.basename(dep_file_path);
const dep_basename = fs.path.basename(dep_file_path);
// Add the files depended on to the cache system.
try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
switch (comp.cache_use) {
@ -5910,11 +5910,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
// Rename into place.
const digest = man.final();
const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });
var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close();
const tmp_basename = std.fs.path.basename(out_obj_path);
try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename);
const tmp_basename = fs.path.basename(out_obj_path);
try fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename);
break :blk digest;
};
@ -5936,7 +5936,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
.success = .{
.object_path = .{
.root_dir = comp.dirs.local_cache,
.sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, o_basename }),
.sub_path = try fs.path.join(gpa, &.{ "o", &digest, o_basename }),
},
.lock = man.toOwnedLock(),
},
@ -5960,7 +5960,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
.rc => |rc_src| rc_src.src_path,
.manifest => |src_path| src_path,
};
const src_basename = std.fs.path.basename(src_path);
const src_basename = fs.path.basename(src_path);
log.debug("updating win32 resource: {s}", .{src_path});
@ -5997,7 +5997,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
// get the digest now and write the .res directly to the cache
const digest = man.final();
const o_sub_path = try std.fs.path.join(arena, &.{ "o", &digest });
const o_sub_path = try fs.path.join(arena, &.{ "o", &digest });
var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close();
@ -6083,7 +6083,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
_ = try man.addFile(rc_src.src_path, null);
man.hash.addListOfBytes(rc_src.extra_flags);
const rc_basename_noext = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len];
const digest = if (try man.hit()) man.final() else blk: {
var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});
@ -6128,7 +6128,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
// Read depfile and update cache manifest
{
const dep_basename = std.fs.path.basename(out_dep_path);
const dep_basename = fs.path.basename(out_dep_path);
const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(arena, dep_basename, 50 * 1024 * 1024);
defer arena.free(dep_file_contents);
@ -6156,11 +6156,11 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
// Rename into place.
const digest = man.final();
const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest });
var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
defer o_dir.close();
const tmp_basename = std.fs.path.basename(out_res_path);
try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename);
const tmp_basename = fs.path.basename(out_res_path);
try fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename);
break :blk digest;
};
@ -6268,7 +6268,7 @@ fn spawnZigRc(
}
pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
const s = std.fs.path.sep_str;
const s = fs.path.sep_str;
const rand_int = std.crypto.random.int(u64);
if (comp.dirs.local_cache.path) |p| {
return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix });
@ -6518,12 +6518,12 @@ pub fn addCCArgs(
if (comp.config.link_libcpp) {
try argv.append("-isystem");
try argv.append(try std.fs.path.join(arena, &[_][]const u8{
try argv.append(try fs.path.join(arena, &[_][]const u8{
comp.dirs.zig_lib.path.?, "libcxx", "include",
}));
try argv.append("-isystem");
try argv.append(try std.fs.path.join(arena, &[_][]const u8{
try argv.append(try fs.path.join(arena, &[_][]const u8{
comp.dirs.zig_lib.path.?, "libcxxabi", "include",
}));
@ -6534,7 +6534,7 @@ pub fn addCCArgs(
// However as noted by @dimenus, appending libc headers before compiler headers breaks
// intrinsics and other compiler specific items.
try argv.append("-isystem");
try argv.append(try std.fs.path.join(arena, &.{ comp.dirs.zig_lib.path.?, "include" }));
try argv.append(try fs.path.join(arena, &.{ comp.dirs.zig_lib.path.?, "include" }));
try argv.ensureUnusedCapacity(comp.libc_include_dir_list.len * 2);
for (comp.libc_include_dir_list) |include_dir| {
@ -6552,7 +6552,7 @@ pub fn addCCArgs(
if (comp.config.link_libunwind) {
try argv.append("-isystem");
try argv.append(try std.fs.path.join(arena, &[_][]const u8{
try argv.append(try fs.path.join(arena, &[_][]const u8{
comp.dirs.zig_lib.path.?, "libunwind", "include",
}));
}
@ -7145,7 +7145,7 @@ fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8)
return (try crtFilePath(&comp.crt_files, basename)) orelse {
const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;
const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir;
const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
const full_path = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
return Cache.Path.initCwd(full_path);
};
}
@ -7207,13 +7207,15 @@ pub fn lockAndSetMiscFailure(
}
pub fn dump_argv(argv: []const []const u8) void {
var stderr = std.debug.lockStdErr2(&.{});
defer std.debug.unlockStdErr();
var buffer: [64]u8 = undefined;
const stderr = std.debug.lockStderrWriter(&buffer);
defer std.debug.unlockStderrWriter();
nosuspend {
for (argv[0 .. argv.len - 1]) |arg| {
stderr.print("{s} ", .{arg}) catch return;
for (argv) |arg| {
stderr.writeAll(arg) catch return;
(stderr.writableArray(1) catch return)[0] = ' ';
}
stderr.print("{s}\n", .{argv[argv.len - 1]}) catch {};
stderr.buffer[stderr.end - 1] = '\n';
}
}
@ -7541,7 +7543,7 @@ pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {
return .{
.full_object_path = .{
.root_dir = comp.dirs.local_cache,
.sub_path = try std.fs.path.join(comp.gpa, &.{
.sub_path = try fs.path.join(comp.gpa, &.{
"o",
&Cache.binToHex(comp.digest.?),
comp.emit_bin.?,

View File

@ -471,10 +471,14 @@ const Parse = struct {
offset: u32,
) InnerError!void {
const raw_string = bytes[offset..];
var aw: std.io.Writer.Allocating = .fromArrayList(p.gpa, buf);
const result = std.zig.string_literal.parseWrite(&aw.interface, raw_string);
buf.* = aw.toArrayList();
switch (result catch return error.OutOfMemory) {
const result = r: {
var aw: std.io.Writer.Allocating = .fromArrayList(p.gpa, buf);
defer buf.* = aw.toArrayList();
break :r std.zig.string_literal.parseWrite(&aw.writer, raw_string) catch |err| switch (err) {
error.WriteFailed => return error.OutOfMemory,
};
};
switch (result) {
.success => {},
.failure => |err| try p.appendStrLitError(err, token, bytes, offset),
}

View File

@ -52,15 +52,6 @@ pub fn LinearFifo(comptime T: type) type {
}
}
/// Reduce allocated capacity to `size`.
pub fn shrink(self: *Self, size: usize) void {
assert(size >= self.count);
self.realign();
self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) {
error.OutOfMemory => return, // no problem, capacity is still correct then.
};
}
/// Ensure that the buffer can fit at least `size` items
pub fn ensureTotalCapacity(self: *Self, size: usize) !void {
if (self.buf.len >= size) return;
@ -76,11 +67,6 @@ pub fn LinearFifo(comptime T: type) type {
return try self.ensureTotalCapacity(math.add(usize, self.count, size) catch return error.OutOfMemory);
}
/// Returns number of items currently in fifo
pub fn readableLength(self: Self) usize {
return self.count;
}
/// Returns a writable slice from the 'read' end of the fifo
fn readableSliceMut(self: Self, offset: usize) []T {
if (offset > self.count) return &[_]T{};
@ -95,22 +81,6 @@ pub fn LinearFifo(comptime T: type) type {
}
}
/// Returns a readable slice from `offset`
pub fn readableSlice(self: Self, offset: usize) []const T {
return self.readableSliceMut(offset);
}
pub fn readableSliceOfLen(self: *Self, len: usize) []const T {
assert(len <= self.count);
const buf = self.readableSlice(0);
if (buf.len >= len) {
return buf[0..len];
} else {
self.realign();
return self.readableSlice(0)[0..len];
}
}
/// Discard first `count` items in the fifo
pub fn discard(self: *Self, count: usize) void {
assert(count <= self.count);
@ -143,28 +113,6 @@ pub fn LinearFifo(comptime T: type) type {
return c;
}
/// Read data from the fifo into `dst`, returns number of items copied.
pub fn read(self: *Self, dst: []T) usize {
var dst_left = dst;
while (dst_left.len > 0) {
const slice = self.readableSlice(0);
if (slice.len == 0) break;
const n = @min(slice.len, dst_left.len);
@memcpy(dst_left[0..n], slice[0..n]);
self.discard(n);
dst_left = dst_left[n..];
}
return dst.len - dst_left.len;
}
/// Same as `read` except it returns an error union
/// The purpose of this function existing is to match `std.io.GenericReader` API.
fn readFn(self: *Self, dest: []u8) error{}!usize {
return self.read(dest);
}
/// Returns number of items available in fifo
pub fn writableLength(self: Self) usize {
return self.buf.len - self.count;
@ -183,20 +131,6 @@ pub fn LinearFifo(comptime T: type) type {
}
}
/// Returns a writable buffer of at least `size` items, allocating memory as needed.
/// Use `fifo.update` once you've written data to it.
pub fn writableWithSize(self: *Self, size: usize) ![]T {
try self.ensureUnusedCapacity(size);
// try to avoid realigning buffer
var slice = self.writableSlice(0);
if (slice.len < size) {
self.realign();
slice = self.writableSlice(0);
}
return slice;
}
/// Update the tail location of the buffer (usually follows use of writable/writableWithSize)
pub fn update(self: *Self, count: usize) void {
assert(self.count + count <= self.buf.len);
@ -231,201 +165,5 @@ pub fn LinearFifo(comptime T: type) type {
self.buf[tail] = item;
self.update(1);
}
/// Appends the data in `src` to the fifo.
/// Allocates more memory as necessary
pub fn write(self: *Self, src: []const T) !void {
try self.ensureUnusedCapacity(src.len);
return self.writeAssumeCapacity(src);
}
/// Same as `write` except it returns the number of bytes written, which is always the same
/// as `bytes.len`. The purpose of this function existing is to match `std.io.GenericWriter` API.
fn appendWrite(self: *Self, bytes: []const u8) error{OutOfMemory}!usize {
try self.write(bytes);
return bytes.len;
}
/// Make `count` items available before the current read location
fn rewind(self: *Self, count: usize) void {
assert(self.writableLength() >= count);
var head = self.head + (self.buf.len - count);
head &= self.buf.len - 1;
self.head = head;
self.count += count;
}
/// Place data back into the read stream
pub fn unget(self: *Self, src: []const T) !void {
try self.ensureUnusedCapacity(src.len);
self.rewind(src.len);
const slice = self.readableSliceMut(0);
if (src.len < slice.len) {
@memcpy(slice[0..src.len], src);
} else {
@memcpy(slice, src[0..slice.len]);
const slice2 = self.readableSliceMut(slice.len);
@memcpy(slice2[0 .. src.len - slice.len], src[slice.len..]);
}
}
/// Returns the item at `offset`.
/// Asserts offset is within bounds.
pub fn peekItem(self: Self, offset: usize) T {
assert(offset < self.count);
var index = self.head + offset;
index &= self.buf.len - 1;
return self.buf[index];
}
pub fn toOwnedSlice(self: *Self) Allocator.Error![]T {
if (self.head != 0) self.realign();
assert(self.head == 0);
assert(self.count <= self.buf.len);
const allocator = self.allocator;
if (allocator.resize(self.buf, self.count)) {
const result = self.buf[0..self.count];
self.* = Self.init(allocator);
return result;
}
const new_memory = try allocator.dupe(T, self.buf[0..self.count]);
allocator.free(self.buf);
self.* = Self.init(allocator);
return new_memory;
}
};
}
test "LinearFifo(u8, .Dynamic) discard(0) from empty buffer should not error on overflow" {
var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator);
defer fifo.deinit();
// If overflow is not explicitly allowed this will crash in debug / safe mode
fifo.discard(0);
}
test "LinearFifo(u8, .Dynamic)" {
var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator);
defer fifo.deinit();
try fifo.write("HELLO");
try testing.expectEqual(@as(usize, 5), fifo.readableLength());
try testing.expectEqualSlices(u8, "HELLO", fifo.readableSlice(0));
{
var i: usize = 0;
while (i < 5) : (i += 1) {
try fifo.write(&[_]u8{fifo.peekItem(i)});
}
try testing.expectEqual(@as(usize, 10), fifo.readableLength());
try testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0));
}
{
try testing.expectEqual(@as(u8, 'H'), fifo.readItem().?);
try testing.expectEqual(@as(u8, 'E'), fifo.readItem().?);
try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
try testing.expectEqual(@as(u8, 'O'), fifo.readItem().?);
}
try testing.expectEqual(@as(usize, 5), fifo.readableLength());
{ // Writes that wrap around
try testing.expectEqual(@as(usize, 11), fifo.writableLength());
try testing.expectEqual(@as(usize, 6), fifo.writableSlice(0).len);
fifo.writeAssumeCapacity("6<chars<11");
try testing.expectEqualSlices(u8, "HELLO6<char", fifo.readableSlice(0));
try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(11));
try testing.expectEqualSlices(u8, "11", fifo.readableSlice(13));
try testing.expectEqualSlices(u8, "", fifo.readableSlice(15));
fifo.discard(11);
try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(0));
fifo.discard(4);
try testing.expectEqual(@as(usize, 0), fifo.readableLength());
}
{
const buf = try fifo.writableWithSize(12);
try testing.expectEqual(@as(usize, 12), buf.len);
var i: u8 = 0;
while (i < 10) : (i += 1) {
buf[i] = i + 'a';
}
fifo.update(10);
try testing.expectEqualSlices(u8, "abcdefghij", fifo.readableSlice(0));
}
{
try fifo.unget("prependedstring");
var result: [30]u8 = undefined;
try testing.expectEqualSlices(u8, "prependedstringabcdefghij", result[0..fifo.read(&result)]);
try fifo.unget("b");
try fifo.unget("a");
try testing.expectEqualSlices(u8, "ab", result[0..fifo.read(&result)]);
}
fifo.shrink(0);
{
try fifo.writer().print("{s}, {s}!", .{ "Hello", "World" });
var result: [30]u8 = undefined;
try testing.expectEqualSlices(u8, "Hello, World!", result[0..fifo.read(&result)]);
try testing.expectEqual(@as(usize, 0), fifo.readableLength());
}
{
try fifo.writer().writeAll("This is a test");
var result: [30]u8 = undefined;
try testing.expectEqualSlices(u8, "This", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
try testing.expectEqualSlices(u8, "is", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
try testing.expectEqualSlices(u8, "a", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
try testing.expectEqualSlices(u8, "test", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
}
{
try fifo.ensureTotalCapacity(1);
var in_fbs = std.io.fixedBufferStream("pump test");
var out_buf: [50]u8 = undefined;
var out_fbs = std.io.fixedBufferStream(&out_buf);
try fifo.pump(in_fbs.reader(), out_fbs.writer());
try testing.expectEqualSlices(u8, in_fbs.buffer, out_fbs.getWritten());
}
}
test LinearFifo {
inline for ([_]type{ u1, u8, u16, u64 }) |T| {
const FifoType = LinearFifo(T);
var fifo: FifoType = .init(testing.allocator);
defer fifo.deinit();
try fifo.write(&[_]T{ 0, 1, 1, 0, 1 });
try testing.expectEqual(@as(usize, 5), fifo.readableLength());
{
try testing.expectEqual(@as(T, 0), fifo.readItem().?);
try testing.expectEqual(@as(T, 1), fifo.readItem().?);
try testing.expectEqual(@as(T, 1), fifo.readItem().?);
try testing.expectEqual(@as(T, 0), fifo.readItem().?);
try testing.expectEqual(@as(T, 1), fifo.readItem().?);
try testing.expectEqual(@as(usize, 0), fifo.readableLength());
}
{
try fifo.writeItem(1);
try fifo.writeItem(1);
try fifo.writeItem(1);
try testing.expectEqual(@as(usize, 3), fifo.readableLength());
}
{
var readBuf: [3]T = undefined;
const n = fifo.read(&readBuf);
try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items.
}
}
}

View File

@ -35,8 +35,8 @@ const Fmt = struct {
color: Color,
gpa: Allocator,
arena: Allocator,
out_buffer: std.ArrayListUnmanaged(u8),
stdout_writer: *File.Writer,
out_buffer: std.Io.Writer.Allocating,
stdout_writer: *fs.File.Writer,
const SeenMap = std.AutoHashMap(fs.File.INode, void);
};
@ -58,7 +58,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
const arg = args[i];
if (mem.startsWith(u8, arg, "-")) {
if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
try File.stdout().writeAll(usage_fmt);
try fs.File.stdout().writeAll(usage_fmt);
return process.cleanExit();
} else if (mem.eql(u8, arg, "--color")) {
if (i + 1 >= args.len) {
@ -98,7 +98,10 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
fatal("cannot use --stdin with positional arguments", .{});
}
const source_code = std.zig.readSourceFileToEndAlloc(gpa, .stdin(), 0) catch |err| {
const stdin: fs.File = .stdin();
var stdio_buffer: [1024]u8 = undefined;
var file_reader: fs.File.Reader = stdin.reader(&stdio_buffer);
const source_code = std.zig.readSourceFileToEndAlloc(gpa, &file_reader) catch |err| {
fatal("unable to read stdin: {}", .{err});
};
defer gpa.free(source_code);
@ -142,17 +145,15 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
try std.zig.printAstErrorsToStderr(gpa, tree, "<stdin>", color);
process.exit(2);
}
var aw: std.io.Writer.Allocating = .init(gpa);
defer aw.deinit();
try tree.render(gpa, &aw.interface, .{});
const formatted = aw.getWritten();
const formatted = try tree.renderAlloc(gpa);
defer gpa.free(formatted);
if (check_flag) {
const code: u8 = @intFromBool(mem.eql(u8, formatted, source_code));
process.exit(code);
}
return File.stdout().writeAll(formatted);
return fs.File.stdout().writeAll(formatted);
}
if (input_files.items.len == 0) {
@ -160,7 +161,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
}
var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = File.stdout().writer(&stdout_buffer);
var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
var fmt: Fmt = .{
.gpa = gpa,
@ -170,7 +171,7 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
.check_ast = check_ast_flag,
.force_zon = force_zon,
.color = color,
.out_buffer = .empty,
.out_buffer = .init(gpa),
.stdout_writer = &stdout_writer,
};
defer fmt.seen.deinit();
@ -198,10 +199,10 @@ pub fn run(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
if (fmt.any_error) {
process.exit(1);
}
try fmt.stdout_writer.flush();
try fmt.stdout_writer.interface.flush();
}
fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) anyerror!void {
fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) !void {
fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) {
error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path),
else => {
@ -218,7 +219,7 @@ fn fmtPathDir(
check_mode: bool,
parent_dir: fs.Dir,
parent_sub_path: []const u8,
) anyerror!void {
) !void {
var dir = try parent_dir.openDir(parent_sub_path, .{ .iterate = true });
defer dir.close();
@ -254,7 +255,7 @@ fn fmtPathFile(
check_mode: bool,
dir: fs.Dir,
sub_path: []const u8,
) anyerror!void {
) !void {
const source_file = try dir.openFile(sub_path, .{});
var file_closed = false;
errdefer if (!file_closed) source_file.close();
@ -264,12 +265,15 @@ fn fmtPathFile(
if (stat.kind == .directory)
return error.IsDir;
var read_buffer: [1024]u8 = undefined;
var file_reader: fs.File.Reader = source_file.reader(&read_buffer);
file_reader.size = stat.size;
const gpa = fmt.gpa;
const source_code = try std.zig.readSourceFileToEndAlloc(
gpa,
source_file,
std.math.cast(usize, stat.size) orelse return error.FileTooBig,
);
const source_code = std.zig.readSourceFileToEndAlloc(gpa, &file_reader) catch |err| switch (err) {
error.ReadFailed => return file_reader.err.?,
else => |e| return e,
};
defer gpa.free(source_code);
source_file.close();
@ -332,15 +336,13 @@ fn fmtPathFile(
}
// As a heuristic, we make enough capacity for the same as the input source.
fmt.out_buffer.shrinkRetainingCapacity(0);
try fmt.out_buffer.ensureTotalCapacity(gpa, source_code.len);
fmt.out_buffer.clearRetainingCapacity();
try fmt.out_buffer.ensureTotalCapacity(source_code.len);
{
var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &fmt.out_buffer);
defer fmt.out_buffer = aw.toArrayList();
try tree.render(gpa, &aw.interface, .{});
}
if (mem.eql(u8, fmt.out_buffer.items, source_code))
tree.render(gpa, &fmt.out_buffer.writer, .{}) catch |err| switch (err) {
error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
};
if (mem.eql(u8, fmt.out_buffer.getWritten(), source_code))
return;
if (check_mode) {
@ -350,7 +352,7 @@ fn fmtPathFile(
var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });
defer af.deinit();
try af.file.writeAll(fmt.out_buffer.items);
try af.file.writeAll(fmt.out_buffer.getWritten());
try af.finish();
try fmt.stdout_writer.interface.print("{s}\n", .{file_path});
}

View File

@ -205,7 +205,6 @@ pub fn createEmpty(
const target = &comp.root_mod.resolved_target.result;
const output_mode = comp.config.output_mode;
const optimize_mode = comp.root_mod.optimize_mode;
const is_native_os = comp.root_mod.resolved_target.is_native_os;
const obj_file_ext: []const u8 = switch (target.ofmt) {
.coff => "obj",
@ -234,7 +233,7 @@ pub fn createEmpty(
.gc_sections = gc_sections,
.print_gc_sections = options.print_gc_sections,
.stack_size = stack_size,
.allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os,
.allow_shlib_undefined = options.allow_shlib_undefined orelse false,
.file = null,
.build_id = options.build_id,
},

View File

@ -65,8 +65,10 @@ pub fn wasi_cwd() std.os.wasi.fd_t {
const fatal = std.process.fatal;
/// This can be global since stdin is a singleton.
var stdin_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
/// This can be global since stdout is a singleton.
var stdio_buffer: [4096]u8 = undefined;
var stdout_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
/// Shaming all the locations that inappropriately use an O(N) search algorithm.
/// Please delete this and fix the compilation errors!
@ -3561,10 +3563,12 @@ fn buildOutputType(
switch (listen) {
.none => {},
.stdio => {
var stdin_reader = fs.File.stdin().reader(&stdin_buffer);
var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
try serve(
comp,
.stdin(),
.stdout(),
&stdin_reader.interface,
&stdout_writer.interface,
test_exec_args.items,
self_exe_path,
arg_mode,
@ -3584,10 +3588,13 @@ fn buildOutputType(
const conn = try server.accept();
defer conn.stream.close();
var input = conn.stream.reader(&stdin_buffer);
var output = conn.stream.writer(&stdout_buffer);
try serve(
comp,
.{ .handle = conn.stream.handle },
.{ .handle = conn.stream.handle },
input.interface(),
&output.interface,
test_exec_args.items,
self_exe_path,
arg_mode,
@ -4053,8 +4060,8 @@ fn saveState(comp: *Compilation, incremental: bool) void {
fn serve(
comp: *Compilation,
in: fs.File,
out: fs.File,
in: *std.Io.Reader,
out: *std.Io.Writer,
test_exec_args: []const ?[]const u8,
self_exe_path: ?[]const u8,
arg_mode: ArgMode,
@ -4064,12 +4071,10 @@ fn serve(
const gpa = comp.gpa;
var server = try Server.init(.{
.gpa = gpa,
.in = in,
.out = out,
.zig_version = build_options.version,
});
defer server.deinit();
var child_pid: ?std.process.Child.Id = null;
@ -5491,10 +5496,10 @@ fn jitCmd(
defer comp.destroy();
if (options.server) {
var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
var server: std.zig.Server = .{
.out = fs.File.stdout(),
.out = &stdout_writer.interface,
.in = undefined, // won't be receiving messages
.receive_fifo = undefined, // won't be receiving messages
};
try comp.update(root_prog_node);
@ -6058,7 +6063,7 @@ fn cmdAstCheck(
};
} else fs.File.stdin();
defer if (zig_source_path != null) f.close();
var file_reader: fs.File.Reader = f.reader(&stdio_buffer);
var file_reader: fs.File.Reader = f.reader(&stdin_buffer);
break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
fatal("unable to load file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
};
@ -6076,7 +6081,7 @@ fn cmdAstCheck(
const tree = try Ast.parse(arena, source, mode);
var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
const stdout_bw = &stdout_writer.interface;
switch (mode) {
.zig => {
@ -6291,7 +6296,7 @@ fn detectNativeCpuWithLLVM(
}
fn printCpu(cpu: std.Target.Cpu) !void {
var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
const stdout_bw = &stdout_writer.interface;
if (cpu.model.llvm_name) |llvm_name| {
@ -6340,7 +6345,7 @@ fn cmdDumpLlvmInts(
const dl = tm.createTargetDataLayout();
const context = llvm.Context.create();
var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
const stdout_bw = &stdout_writer.interface;
for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| {
const int_type = context.intType(bits);
@ -6369,7 +6374,7 @@ fn cmdDumpZir(
defer f.close();
const zir = try Zcu.loadZirCache(arena, f);
var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
const stdout_bw = &stdout_writer.interface;
{
const instruction_bytes = zir.instructions.len *
@ -6416,7 +6421,7 @@ fn cmdChangelist(
var f = fs.cwd().openFile(old_source_path, .{}) catch |err|
fatal("unable to open old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
defer f.close();
var file_reader: fs.File.Reader = f.reader(&stdio_buffer);
var file_reader: fs.File.Reader = f.reader(&stdin_buffer);
break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
fatal("unable to read old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
};
@ -6424,7 +6429,7 @@ fn cmdChangelist(
var f = fs.cwd().openFile(new_source_path, .{}) catch |err|
fatal("unable to open new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
defer f.close();
var file_reader: fs.File.Reader = f.reader(&stdio_buffer);
var file_reader: fs.File.Reader = f.reader(&stdin_buffer);
break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
fatal("unable to read new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
};
@ -6456,7 +6461,7 @@ fn cmdChangelist(
var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;
try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map);
var stdout_writer = fs.File.stdout().writerStreaming(&stdio_buffer);
var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
const stdout_bw = &stdout_writer.interface;
{
try stdout_bw.print("Instruction mappings:\n", .{});
@ -6916,7 +6921,7 @@ fn cmdFetch(
const name = switch (save) {
.no => {
var stdout = fs.File.stdout().writerStreaming(&stdio_buffer);
var stdout = fs.File.stdout().writerStreaming(&stdout_buffer);
try stdout.interface.print("{s}\n", .{package_hash_slice});
try stdout.interface.flush();
return cleanExit();

View File

@ -0,0 +1,128 @@
export fn testVoid() void {
const f: void = @import("zon/neg_inf.zon");
_ = f;
}
export fn testInStruct() void {
const f: struct { f: [*]const u8 } = @import("zon/neg_inf.zon");
_ = f;
}
export fn testError() void {
const f: struct { error{foo} } = @import("zon/neg_inf.zon");
_ = f;
}
export fn testInUnion() void {
const f: union(enum) { a: void, b: [*c]const u8 } = @import("zon/neg_inf.zon");
_ = f;
}
export fn testInVector() void {
const f: @Vector(0, [*c]const u8) = @import("zon/neg_inf.zon");
_ = f;
}
export fn testInOpt() void {
const f: *const ?[*c]const u8 = @import("zon/neg_inf.zon");
_ = f;
}
export fn testComptimeField() void {
const f: struct { comptime foo: ??u8 = null } = @import("zon/neg_inf.zon");
_ = f;
}
export fn testEnumLiteral() void {
const f: @TypeOf(.foo) = @import("zon/neg_inf.zon");
_ = f;
}
export fn testNestedOpt1() void {
const f: ??u8 = @import("zon/neg_inf.zon");
_ = f;
}
export fn testNestedOpt2() void {
const f: ?*const ?u8 = @import("zon/neg_inf.zon");
_ = f;
}
export fn testNestedOpt3() void {
const f: *const ?*const ?*const u8 = @import("zon/neg_inf.zon");
_ = f;
}
export fn testOpt() void {
const f: ?u8 = @import("zon/neg_inf.zon");
_ = f;
}
const E = enum(u8) { _ };
export fn testNonExhaustiveEnum() void {
const f: E = @import("zon/neg_inf.zon");
_ = f;
}
const U = union { foo: void };
export fn testUntaggedUnion() void {
const f: U = @import("zon/neg_inf.zon");
_ = f;
}
const EU = union(enum) { foo: void };
export fn testTaggedUnionVoid() void {
const f: EU = @import("zon/neg_inf.zon");
_ = f;
}
export fn testVisited() void {
const V = struct {
?f32, // Adds `?f32` to the visited list
??f32, // `?f32` is already visited, we need to detect the nested opt anyway
f32,
};
const f: V = @import("zon/neg_inf.zon");
_ = f;
}
export fn testMutablePointer() void {
const f: *i32 = @import("zon/neg_inf.zon");
_ = f;
}
// error
// imports=zon/neg_inf.zon
//
// tmp.zig:2:29: error: type 'void' is not available in ZON
// tmp.zig:7:50: error: type '[*]const u8' is not available in ZON
// tmp.zig:7:50: note: ZON does not allow many-pointers
// tmp.zig:12:46: error: type 'error{foo}' is not available in ZON
// tmp.zig:17:65: error: type '[*c]const u8' is not available in ZON
// tmp.zig:17:65: note: ZON does not allow C pointers
// tmp.zig:22:49: error: type '[*c]const u8' is not available in ZON
// tmp.zig:22:49: note: ZON does not allow C pointers
// tmp.zig:27:45: error: type '[*c]const u8' is not available in ZON
// tmp.zig:27:45: note: ZON does not allow C pointers
// tmp.zig:32:61: error: type '??u8' is not available in ZON
// tmp.zig:32:61: note: ZON does not allow nested optionals
// tmp.zig:42:29: error: type '??u8' is not available in ZON
// tmp.zig:42:29: note: ZON does not allow nested optionals
// tmp.zig:47:36: error: type '?*const ?u8' is not available in ZON
// tmp.zig:47:36: note: ZON does not allow nested optionals
// tmp.zig:52:50: error: type '?*const ?*const u8' is not available in ZON
// tmp.zig:52:50: note: ZON does not allow nested optionals
// tmp.zig:85:26: error: type '??f32' is not available in ZON
// tmp.zig:85:26: note: ZON does not allow nested optionals
// tmp.zig:90:29: error: type '*i32' is not available in ZON
// tmp.zig:90:29: note: ZON does not allow mutable pointers
// neg_inf.zon:1:1: error: expected type '@Type(.enum_literal)'
// tmp.zig:37:38: note: imported here
// neg_inf.zon:1:1: error: expected type '?u8'
// tmp.zig:57:28: note: imported here
// neg_inf.zon:1:1: error: expected type 'tmp.E'
// tmp.zig:63:26: note: imported here
// neg_inf.zon:1:1: error: expected type 'tmp.U'
// tmp.zig:69:26: note: imported here
// neg_inf.zon:1:1: error: expected type 'tmp.EU'
// tmp.zig:75:27: note: imported here

View File

@ -0,0 +1,21 @@
const C = struct {
c: type,
b: u32,
};
const S = struct {
fn foo(b: u32, c: anytype) void {
bar(C{ .c = c, .b = b });
}
fn bar(_: anytype) void {}
};
pub export fn entry() void {
S.foo(0, u32);
}
// error
//
//:7:25: error: unable to resolve comptime value
//:7:25: note: initializer of comptime-only struct 'tmp.C' must be comptime-known
//:2:8: note: struct requires comptime because of this field
//:2:8: note: types are not available at runtime

View File

@ -0,0 +1,26 @@
var self = "aoeu";
fn f(m: []const u8) void {
m.copy(u8, self[0..], m);
}
export fn entry() usize {
return @sizeOf(@TypeOf(&f));
}
pub export fn entry1() void {
.{}.bar();
}
const S = struct { foo: i32 };
pub export fn entry2() void {
const x = S{ .foo = 1 };
x.bar();
}
// error
//
// :4:6: error: no field or member function named 'copy' in '[]const u8'
// :12:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
// :18:6: error: no field or member function named 'bar' in 'tmp.S'
// :15:11: note: struct declared here

View File

@ -0,0 +1,12 @@
const A = struct { x: u32 };
const T = struct { x: u32 };
export fn foo() void {
const a = A{ .x = 123 };
_ = @as(T, a);
}
// error
//
// :5:16: error: expected type 'tmp.T', found 'tmp.A'
// :1:11: note: struct declared here
// :2:11: note: struct declared here

View File

@ -0,0 +1,52 @@
const S = struct { x: u32 = 0 };
const T = struct { []const u8 };
fn test0() !void {
const x: u8 = try 1;
_ = x;
}
fn test1() !void {
const x: S = try .{};
_ = x;
}
fn test2() !void {
const x: S = try S{ .x = 123 };
_ = x;
}
fn test3() !void {
const x: S = try try S{ .x = 123 };
_ = x;
}
fn test4() !void {
const x: T = try .{"hello"};
_ = x;
}
fn test5() !void {
const x: error{Foo}!u32 = 123;
_ = try try x;
}
comptime {
_ = &test0;
_ = &test1;
_ = &test2;
_ = &test3;
_ = &test4;
_ = &test5;
}
// error
//
// :5:23: error: expected error union type, found 'comptime_int'
// :10:23: error: expected error union type, found '@TypeOf(.{})'
// :15:23: error: expected error union type, found 'tmp.S'
// :1:11: note: struct declared here
// :20:27: error: expected error union type, found 'tmp.S'
// :1:11: note: struct declared here
// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
// :31:13: error: expected error union type, found 'u32'

View File

@ -46,14 +46,18 @@ const StructInStruct = struct { a: struct { b: u8 } };
const UnionInStruct = struct { a: union { b: u8 } };
const StructInUnion = union { a: struct { b: u8 } };
const UnionInUnion = union { a: union { b: u8 } };
const StructInTuple = struct { struct { b: u8 } };
const UnionInTuple = struct { union { b: u8 } };
const InnerStruct = struct { b: u8 };
const StructInTuple = struct { a: InnerStruct };
const InnerUnion = union { b: u8 };
const UnionInTuple = struct { a: InnerUnion };
export fn nestedTypes() void {
@compileLog(@typeName(StructInStruct));
@compileLog(@typeName(UnionInStruct));
@compileLog(@typeName(StructInUnion));
@compileLog(@typeName(UnionInUnion));
@compileLog(@typeName(StructInTuple));
@compileLog(@typeName(UnionInTuple));
}
// error
@ -61,22 +65,24 @@ export fn nestedTypes() void {
// :8:5: error: found compile log statement
// :19:5: note: also here
// :39:5: note: also here
// :53:5: note: also here
// :55:5: note: also here
//
// Compile Log Output:
// @as(*const [15:0]u8, "tmp.namespace.S")
// @as(*const [15:0]u8, "tmp.namespace.E")
// @as(*const [15:0]u8, "tmp.namespace.U")
// @as(*const [15:0]u8, "tmp.namespace.O")
// @as(*const [19:0]u8, "tmp.localVarValue.S")
// @as(*const [19:0]u8, "tmp.localVarValue.E")
// @as(*const [19:0]u8, "tmp.localVarValue.U")
// @as(*const [19:0]u8, "tmp.localVarValue.O")
// @as(*const [11:0]u8, "tmp.MakeS()")
// @as(*const [11:0]u8, "tmp.MakeE()")
// @as(*const [11:0]u8, "tmp.MakeU()")
// @as(*const [11:0]u8, "tmp.MakeO()")
// @as(*const [18:0]u8, "tmp.StructInStruct")
// @as(*const [17:0]u8, "tmp.UnionInStruct")
// @as(*const [17:0]u8, "tmp.StructInUnion")
// @as(*const [16:0]u8, "tmp.UnionInUnion")
//Compile Log Output:
//@as(*const [15:0]u8, "tmp.namespace.S")
//@as(*const [15:0]u8, "tmp.namespace.E")
//@as(*const [15:0]u8, "tmp.namespace.U")
//@as(*const [15:0]u8, "tmp.namespace.O")
//@as(*const [19:0]u8, "tmp.localVarValue.S")
//@as(*const [19:0]u8, "tmp.localVarValue.E")
//@as(*const [19:0]u8, "tmp.localVarValue.U")
//@as(*const [19:0]u8, "tmp.localVarValue.O")
//@as(*const [11:0]u8, "tmp.MakeS()")
//@as(*const [11:0]u8, "tmp.MakeE()")
//@as(*const [11:0]u8, "tmp.MakeU()")
//@as(*const [11:0]u8, "tmp.MakeO()")
//@as(*const [18:0]u8, "tmp.StructInStruct")
//@as(*const [17:0]u8, "tmp.UnionInStruct")
//@as(*const [17:0]u8, "tmp.StructInUnion")
//@as(*const [16:0]u8, "tmp.UnionInUnion")
//@as(*const [17:0]u8, "tmp.StructInTuple")
//@as(*const [16:0]u8, "tmp.UnionInTuple")

View File

@ -800,8 +800,6 @@ const TestManifestConfigDefaults = struct {
}
// Windows
defaults = defaults ++ "x86_64-windows" ++ ",";
// Wasm
defaults = defaults ++ "wasm32-wasi";
break :blk defaults;
};
} else if (std.mem.eql(u8, key, "output_mode")) {

View File

@ -1335,15 +1335,16 @@ const test_targets = blk: {
// WASI Targets
.{
.target = .{
.cpu_arch = .wasm32,
.os_tag = .wasi,
.abi = .none,
},
.use_llvm = false,
.use_lld = false,
},
// TODO: lowerTry for pointers
//.{
// .target = .{
// .cpu_arch = .wasm32,
// .os_tag = .wasi,
// .abi = .none,
// },
// .use_llvm = false,
// .use_lld = false,
//},
.{
.target = .{
.cpu_arch = .wasm32,

View File

@ -120,7 +120,7 @@ pub fn main() !void {
error_bundle.renderToStdErr(color.renderOptions());
}
const formatted_output = try tree.render(allocator);
const formatted_output = try tree.renderAlloc(allocator);
_ = try std.fs.File.stdout().write(formatted_output);
}