diff --git a/ci/riscv64-linux-debug.sh b/ci/riscv64-linux-debug.sh index 564a7ca611..4076ec2268 100755 --- a/ci/riscv64-linux-debug.sh +++ b/ci/riscv64-linux-debug.sh @@ -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" diff --git a/ci/riscv64-linux-release.sh b/ci/riscv64-linux-release.sh index a90335e8f2..78c398cab4 100755 --- a/ci/riscv64-linux-release.sh +++ b/ci/riscv64-linux-release.sh @@ -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" diff --git a/lib/compiler/aro_translate_c.zig b/lib/compiler/aro_translate_c.zig index 015a558d4e..31ec1ceab9 100644 --- a/lib/compiler/aro_translate_c.zig +++ b/lib/compiler/aro_translate_c.zig @@ -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(); } diff --git a/lib/compiler/objcopy.zig b/lib/compiler/objcopy.zig index 98bf5d2bcf..52ffe208f6 100644 --- a/lib/compiler/objcopy.zig +++ b/lib/compiler/objcopy.zig @@ -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) { diff --git a/lib/compiler/resinator/main.zig b/lib/compiler/resinator/main.zig index 903e0a2f71..4c952c03c4 100644 --- a/lib/compiler/resinator/main.zig +++ b/lib/compiler/resinator/main.zig @@ -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 => .{ diff --git a/lib/compiler_rt/exp.zig b/lib/compiler_rt/exp.zig index 178d46617e..fa4356a336 100644 --- a/lib/compiler_rt/exp.zig +++ b/lib/compiler_rt/exp.zig @@ -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 } diff --git a/lib/compiler_rt/exp2.zig b/lib/compiler_rt/exp2.zig index 66e58ee463..ce79dff497 100644 --- a/lib/compiler_rt/exp2.zig +++ b/lib/compiler_rt/exp2.zig @@ -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 } diff --git a/lib/compiler_rt/log.zig b/lib/compiler_rt/log.zig index 6b5c8fc683..f8bbf430ac 100644 --- a/lib/compiler_rt/log.zig +++ b/lib/compiler_rt/log.zig @@ -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 } diff --git a/lib/compiler_rt/log10.zig b/lib/compiler_rt/log10.zig index f80c514ff6..1c2ce4bbca 100644 --- a/lib/compiler_rt/log10.zig +++ b/lib/compiler_rt/log10.zig @@ -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 } diff --git a/lib/compiler_rt/log2.zig b/lib/compiler_rt/log2.zig index 7d52e437fd..4cedcfe0c1 100644 --- a/lib/compiler_rt/log2.zig +++ b/lib/compiler_rt/log2.zig @@ -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 } diff --git a/lib/compiler_rt/stack_probe.zig b/lib/compiler_rt/stack_probe.zig index afc124196f..94212b7a23 100644 --- a/lib/compiler_rt/stack_probe.zig +++ b/lib/compiler_rt/stack_probe.zig @@ -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 }); diff --git a/lib/docs/wasm/Walk.zig b/lib/docs/wasm/Walk.zig index ffa0f7d428..2c41e9c940 100644 --- a/lib/docs/wasm/Walk.zig +++ b/lib/docs/wasm/Walk.zig @@ -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); } diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index 8f57479fa3..a56e81157d 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -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; } diff --git a/lib/std/Io/DeprecatedReader.zig b/lib/std/Io/DeprecatedReader.zig index 3f2429c3ae..f6cb9f61d5 100644 --- a/lib/std/Io/DeprecatedReader.zig +++ b/lib/std/Io/DeprecatedReader.zig @@ -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; diff --git a/lib/std/Io/Reader.zig b/lib/std/Io/Reader.zig index e569c36773..f2a1ec7287 100644 --- a/lib/std/Io/Reader.zig +++ b/lib/std/Io/Reader.zig @@ -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); } diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index 1d6abb2080..11bc05a00d 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -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), ©); - return w.writeStruct(copy); + return w.writeAll(@ptrCast((©)[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); +} diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index c9a866b0c8..2634553d25 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -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(); } diff --git a/lib/std/debug.zig b/lib/std/debug.zig index a453c322d7..eb68baffc0 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -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); diff --git a/lib/std/math/expm1.zig b/lib/std/math/expm1.zig index c64a123631..7c57459271 100644 --- a/lib/std/math/expm1.zig +++ b/lib/std/math/expm1.zig @@ -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 } diff --git a/lib/std/math/log1p.zig b/lib/std/math/log1p.zig index 2d7507bc88..bd4139311c 100644 --- a/lib/std/math/log1p.zig +++ b/lib/std/math/log1p.zig @@ -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 } diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 33e68eedad..1a61076f32 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -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`. /// diff --git a/lib/std/os/uefi/protocol/file.zig b/lib/std/os/uefi/protocol/file.zig index f8802fa64f..0654dec14a 100644 --- a/lib/std/os/uefi/protocol/file.zig +++ b/lib/std/os/uefi/protocol/file.zig @@ -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)); diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 7f2d3e86c5..4a4324c193 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -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) { diff --git a/lib/std/zig.zig b/lib/std/zig.zig index d113129b7e..ad264a9b33 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -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; } diff --git a/lib/std/zig/LibCInstallation.zig b/lib/std/zig/LibCInstallation.zig index 233336d898..896288b622 100644 --- a/lib/std/zig/LibCInstallation.zig +++ b/lib/std/zig/LibCInstallation.zig @@ -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, diff --git a/lib/std/zig/Server.zig b/lib/std/zig/Server.zig index 3c19288866..8fc016d284 100644 --- a/lib/std/zig/Server.zig +++ b/lib/std/zig/Server.zig @@ -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); diff --git a/lib/std/zig/WindowsSdk.zig b/lib/std/zig/WindowsSdk.zig index 96a47395b6..61e1defb12 100644 --- a/lib/std/zig/WindowsSdk.zig +++ b/lib/std/zig/WindowsSdk.zig @@ -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; diff --git a/lib/std/zig/llvm.zig b/lib/std/zig/llvm.zig index c2e1ed9c56..c45ffe9083 100644 --- a/lib/std/zig/llvm.zig +++ b/lib/std/zig/llvm.zig @@ -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; +} diff --git a/lib/std/zig/llvm/BitcodeReader.zig b/lib/std/zig/llvm/BitcodeReader.zig index ebbaf6277b..f1d47e93c0 100644 --- a/lib/std/zig/llvm/BitcodeReader.zig +++ b/lib/std/zig/llvm/BitcodeReader.zig @@ -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; +} diff --git a/lib/std/zig/perf_test.zig b/lib/std/zig/perf_test.zig index d0a6c41a74..1566a15d2d 100644 --- a/lib/std/zig/perf_test.zig +++ b/lib/std/zig/perf_test.zig @@ -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; diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index f001af4d70..df70e71f5b 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -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 => {}, } diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index 792a83d70d..171c189f5d 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -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); diff --git a/src/Compilation.zig b/src/Compilation.zig index afa2ac9fab..7d561af307 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -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.?, diff --git a/src/Package/Manifest.zig b/src/Package/Manifest.zig index bb18764322..f5a4a8c314 100644 --- a/src/Package/Manifest.zig +++ b/src/Package/Manifest.zig @@ -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), } diff --git a/src/deprecated.zig b/src/deprecated.zig index 07efa84eee..68c712b3b1 100644 --- a/src/deprecated.zig +++ b/src/deprecated.zig @@ -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= 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, "", 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}); } diff --git a/src/link/Lld.zig b/src/link/Lld.zig index 1aeeb5d214..296041822e 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -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, }, diff --git a/src/main.zig b/src/main.zig index cb0885e82d..dc931f119b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -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(); diff --git a/test/cases/compile_errors/@import_zon_bad_type.zig b/test/cases/compile_errors/@import_zon_bad_type.zig new file mode 100644 index 0000000000..7f8f718a74 --- /dev/null +++ b/test/cases/compile_errors/@import_zon_bad_type.zig @@ -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 diff --git a/test/cases/compile_errors/anytype_param_requires_comptime.zig b/test/cases/compile_errors/anytype_param_requires_comptime.zig new file mode 100644 index 0000000000..e1151a93c5 --- /dev/null +++ b/test/cases/compile_errors/anytype_param_requires_comptime.zig @@ -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 diff --git a/test/cases/compile_errors/bogus_method_call_on_slice.zig b/test/cases/compile_errors/bogus_method_call_on_slice.zig new file mode 100644 index 0000000000..62adaa3d3e --- /dev/null +++ b/test/cases/compile_errors/bogus_method_call_on_slice.zig @@ -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 diff --git a/test/cases/compile_errors/coerce_anon_struct.zig b/test/cases/compile_errors/coerce_anon_struct.zig new file mode 100644 index 0000000000..5737f861f3 --- /dev/null +++ b/test/cases/compile_errors/coerce_anon_struct.zig @@ -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 diff --git a/test/cases/compile_errors/redundant_try.zig b/test/cases/compile_errors/redundant_try.zig new file mode 100644 index 0000000000..5472701ce0 --- /dev/null +++ b/test/cases/compile_errors/redundant_try.zig @@ -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' diff --git a/test/cases/type_names.zig b/test/cases/type_names.zig index 6873e55641..45f9a1c790 100644 --- a/test/cases/type_names.zig +++ b/test/cases/type_names.zig @@ -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") diff --git a/test/src/Cases.zig b/test/src/Cases.zig index 9f6a7fe189..c9c0c3cad5 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -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")) { diff --git a/test/tests.zig b/test/tests.zig index 2a6c4166fa..db4407172f 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -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, diff --git a/tools/gen_spirv_spec.zig b/tools/gen_spirv_spec.zig index 8840a476c4..c8a3cf5ced 100644 --- a/tools/gen_spirv_spec.zig +++ b/tools/gen_spirv_spec.zig @@ -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); }