diff --git a/build.zig b/build.zig index 5cb50620df..e4f7bb91f0 100644 --- a/build.zig +++ b/build.zig @@ -522,33 +522,6 @@ pub fn build(b: *std.Build) !void { .max_rss = 4_000_000_000, })); - test_modules_step.dependOn(tests.addModuleTests(b, .{ - .test_filters = test_filters, - .test_target_filters = test_target_filters, - .test_extra_targets = test_extra_targets, - .root_src = "lib/c.zig", - .name = "zigc", - .desc = "Run the zig libc implementation unit tests", - .optimize_modes = optimization_modes, - .include_paths = &.{}, - .sanitize_thread = sanitize_thread, - .skip_single_threaded = true, - .skip_non_native = skip_non_native, - .test_only = test_only, - .skip_spirv = skip_spirv, - .skip_wasm = skip_wasm, - .skip_freebsd = skip_freebsd, - .skip_netbsd = skip_netbsd, - .skip_openbsd = skip_openbsd, - .skip_windows = skip_windows, - .skip_darwin = skip_darwin, - .skip_linux = skip_linux, - .skip_llvm = skip_llvm, - .skip_libc = true, - .no_builtin = true, - .max_rss = 4_000_000_000, - })); - test_modules_step.dependOn(tests.addModuleTests(b, .{ .test_filters = test_filters, .test_target_filters = test_target_filters, @@ -562,7 +535,7 @@ pub fn build(b: *std.Build) !void { .skip_single_threaded = skip_single_threaded, .skip_non_native = skip_non_native, .test_only = test_only, - .skip_spirv = skip_spirv, + .skip_spirv = true, .skip_wasm = skip_wasm, .skip_freebsd = skip_freebsd, .skip_netbsd = skip_netbsd, @@ -575,6 +548,33 @@ pub fn build(b: *std.Build) !void { .max_rss = 9_300_000_000, })); + test_modules_step.dependOn(tests.addModuleTests(b, .{ + .test_filters = test_filters, + .test_target_filters = test_target_filters, + .test_extra_targets = test_extra_targets, + .root_src = "test/c.zig", + .name = "libc", + .desc = "Run the libc API tests", + .optimize_modes = optimization_modes, + .include_paths = &.{}, + .sanitize_thread = sanitize_thread, + .skip_single_threaded = true, + .skip_non_native = skip_non_native, + .test_only = test_only, + .skip_spirv = true, + .skip_wasm = skip_wasm, + .skip_freebsd = skip_freebsd, + .skip_netbsd = skip_netbsd, + .skip_openbsd = skip_openbsd, + .skip_windows = skip_windows, + .skip_darwin = skip_darwin, + .skip_linux = skip_linux, + .skip_llvm = skip_llvm, + .skip_libc = skip_libc, + .no_builtin = true, + .max_rss = 4_000_000_000, + })); + const unit_tests_step = b.step("test-unit", "Run the compiler source unit tests"); test_step.dependOn(unit_tests_step); @@ -662,13 +662,13 @@ pub fn build(b: *std.Build) !void { try tests.addIncrementalTests(b, test_incremental_step, test_filters); if (!skip_test_incremental) test_step.dependOn(test_incremental_step); - if (tests.addLibcTests(b, .{ + if (tests.addLibcTestNszTests(b, .{ .optimize_modes = optimization_modes, .test_filters = test_filters, .test_target_filters = test_target_filters, .skip_wasm = skip_wasm, .max_rss = 3_500_000_000, - })) |test_libc_step| test_step.dependOn(test_libc_step); + })) |test_libc_nsz_step| test_step.dependOn(test_libc_nsz_step); } fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { diff --git a/lib/c.zig b/lib/c.zig index c79e7a129f..4a73995e2d 100644 --- a/lib/c.zig +++ b/lib/c.zig @@ -2,8 +2,7 @@ //! bundled libcs. //! //! mingw-w64 libc is not fully statically linked, so some symbols don't need -//! to be exported. However, a future enhancement could be eliminating Zig's -//! dependency on msvcrt dll even when linking libc and targeting Windows. +//! to be exported. const builtin = @import("builtin"); const std = @import("std"); diff --git a/lib/c/inttypes.zig b/lib/c/inttypes.zig index 7bdcae873e..d8807154d3 100644 --- a/lib/c/inttypes.zig +++ b/lib/c/inttypes.zig @@ -24,13 +24,3 @@ fn imaxdiv(a: intmax_t, b: intmax_t) callconv(.c) imaxdiv_t { .rem = @rem(a, b), }; } - -test imaxabs { - const val: intmax_t = -10; - try std.testing.expectEqual(10, imaxabs(val)); -} - -test imaxdiv { - const expected: imaxdiv_t = .{ .quot = 9, .rem = 0 }; - try std.testing.expectEqual(expected, imaxdiv(9, 1)); -} diff --git a/lib/c/math.zig b/lib/c/math.zig index 5eff669a97..20f0b70b5f 100644 --- a/lib/c/math.zig +++ b/lib/c/math.zig @@ -2,10 +2,6 @@ const builtin = @import("builtin"); const std = @import("std"); const math = std.math; -const expect = std.testing.expect; -const expectEqual = std.testing.expectEqual; -const expectApproxEqAbs = std.testing.expectApproxEqAbs; -const expectApproxEqRel = std.testing.expectApproxEqRel; const symbol = @import("../c.zig").symbol; @@ -304,59 +300,6 @@ fn modfl(x: c_longdouble, iptr: *c_longdouble) callconv(.c) c_longdouble { }; } -fn testModf(comptime T: type) !void { - // Choose the appropriate `modf` impl to test based on type - const f = switch (T) { - f32 => modff, - f64 => modf, - c_longdouble => modfl, - else => @compileError("modf not implemented for " ++ @typeName(T)), - }; - - var int: T = undefined; - const iptr = ∫ - const eps_val: comptime_float = @max(1e-6, math.floatEps(T)); - - const normal_frac = f(@as(T, 1234.567), iptr); - // Account for precision error - const expected = 1234.567 - @as(T, 1234); - try expectApproxEqAbs(expected, normal_frac, eps_val); - try expectApproxEqRel(@as(T, 1234.0), iptr.*, eps_val); - - // When `x` is a NaN, NaN is returned and `*iptr` is set to NaN - const nan_frac = f(math.nan(T), iptr); - try expect(math.isNan(nan_frac)); - try expect(math.isNan(iptr.*)); - - // When `x` is positive infinity, +0 is returned and `*iptr` is set to - // positive infinity - const pos_zero_frac = f(math.inf(T), iptr); - try expect(math.isPositiveZero(pos_zero_frac)); - try expect(math.isPositiveInf(iptr.*)); - - // When `x` is negative infinity, -0 is returned and `*iptr` is set to - // negative infinity - const neg_zero_frac = f(-math.inf(T), iptr); - try expect(math.isNegativeZero(neg_zero_frac)); - try expect(math.isNegativeInf(iptr.*)); - - // Return -0 when `x` is a negative integer - const nz_frac = f(@as(T, -1000.0), iptr); - try expect(math.isNegativeZero(nz_frac)); - try expectEqual(@as(T, -1000.0), iptr.*); - - // Return +0 when `x` is a positive integer - const pz_frac = f(@as(T, 1000.0), iptr); - try expect(math.isPositiveZero(pz_frac)); - try expectEqual(@as(T, 1000.0), iptr.*); -} - -test "modf" { - try testModf(f32); - try testModf(f64); - try testModf(c_longdouble); -} - fn nan(_: [*:0]const c_char) callconv(.c) f64 { return math.nan(f64); } @@ -421,49 +364,6 @@ fn rintf(x: f32) callconv(.c) f32 { return y; } -fn testRint(comptime T: type) !void { - const f = switch (T) { - f32 => rintf, - f64 => rint, - else => @compileError("rint not implemented for" ++ @typeName(T)), - }; - - // Positive numbers round correctly - try expectEqual(@as(T, 42.0), f(42.2)); - try expectEqual(@as(T, 42.0), f(41.8)); - - // Negative numbers round correctly - try expectEqual(@as(T, -6.0), f(-5.9)); - try expectEqual(@as(T, -6.0), f(-6.1)); - - // No rounding needed test - try expectEqual(@as(T, 5.0), f(5.0)); - try expectEqual(@as(T, -10.0), f(-10.0)); - try expectEqual(@as(T, 0.0), f(0.0)); - - // Very large numbers return unchanged - const large: T = 9007199254740992.0; // 2^53 - try expectEqual(large, f(large)); - try expectEqual(-large, f(-large)); - - // Small positive numbers round to zero - const pos_result = f(0.3); - try expect(math.isPositiveZero(pos_result)); - - // Small negative numbers round to negative zero - const neg_result = f(-0.3); - try expect(math.isNegativeZero(neg_result)); - - // Exact half rounds to nearest even (banker's rounding) - try expectEqual(@as(T, 2.0), f(2.5)); - try expectEqual(@as(T, 4.0), f(3.5)); -} - -test "rint" { - try testRint(f32); - try testRint(f64); -} - fn tanh(x: f64) callconv(.c) f64 { return math.tanh(x); } diff --git a/lib/c/search.zig b/lib/c/search.zig index 271aec873e..12a9018d63 100644 --- a/lib/c/search.zig +++ b/lib/c/search.zig @@ -9,6 +9,7 @@ comptime { } } +/// Not defined in `std.c` because C headers don't either. const Node = extern struct { next: ?*Node, prev: ?*Node, @@ -38,30 +39,3 @@ fn remque(element: *anyopaque) callconv(.c) void { if (e.next) |next| next.prev = e.prev; if (e.prev) |prev| prev.next = e.next; } - -test "insque and remque" { - var first = Node{ .next = null, .prev = null }; - var second = Node{ .next = null, .prev = null }; - var third = Node{ .next = null, .prev = null }; - - insque(&first, null); - try std.testing.expectEqual(@as(?*Node, null), first.next); - try std.testing.expectEqual(@as(?*Node, null), first.prev); - - insque(&second, &first); - try std.testing.expectEqual(@as(?*Node, &second), first.next); - try std.testing.expectEqual(@as(?*Node, &first), second.prev); - - insque(&third, &first); - try std.testing.expectEqual(@as(?*Node, &third), first.next); - try std.testing.expectEqual(@as(?*Node, &second), third.next); - try std.testing.expectEqual(@as(?*Node, &first), third.prev); - try std.testing.expectEqual(@as(?*Node, &third), second.prev); - - remque(&third); - try std.testing.expectEqual(@as(?*Node, &second), first.next); - try std.testing.expectEqual(@as(?*Node, &first), second.prev); - - remque(&second); - try std.testing.expectEqual(@as(?*Node, null), first.next); -} diff --git a/lib/c/stdlib.zig b/lib/c/stdlib.zig index ccc8c08a14..eed91193c3 100644 --- a/lib/c/stdlib.zig +++ b/lib/c/stdlib.zig @@ -294,103 +294,3 @@ fn bsearch(key: *const anyopaque, base: *const anyopaque, n: usize, size: usize, } return null; } - -test abs { - const val: c_int = -10; - try std.testing.expectEqual(10, abs(val)); -} - -test labs { - const val: c_long = -10; - try std.testing.expectEqual(10, labs(val)); -} - -test llabs { - const val: c_longlong = -10; - try std.testing.expectEqual(10, llabs(val)); -} - -test div { - const expected: div_t = .{ .quot = 5, .rem = 5 }; - try std.testing.expectEqual(expected, div(55, 10)); -} - -test ldiv { - const expected: ldiv_t = .{ .quot = -6, .rem = 2 }; - try std.testing.expectEqual(expected, ldiv(38, -6)); -} - -test lldiv { - const expected: lldiv_t = .{ .quot = 1, .rem = 2 }; - try std.testing.expectEqual(expected, lldiv(5, 3)); -} - -test atoi { - try std.testing.expectEqual(0, atoi(@ptrCast("stop42true"))); - try std.testing.expectEqual(42, atoi(@ptrCast("42true"))); - try std.testing.expectEqual(-1, atoi(@ptrCast("-01"))); - try std.testing.expectEqual(1, atoi(@ptrCast("+001"))); - try std.testing.expectEqual(100, atoi(@ptrCast(" 100"))); - try std.testing.expectEqual(500, atoi(@ptrCast("000000000000500"))); - try std.testing.expectEqual(1111, atoi(@ptrCast("0000000000001111_0000"))); - try std.testing.expectEqual(0, atoi(@ptrCast("0xAA"))); - try std.testing.expectEqual(700, atoi(@ptrCast("700B"))); - try std.testing.expectEqual(32453, atoi(@ptrCast("+32453more"))); - try std.testing.expectEqual(std.math.maxInt(c_int), atoi(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_int)})))); - try std.testing.expectEqual(std.math.minInt(c_int), atoi(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_int)})))); -} - -test atol { - try std.testing.expectEqual(0, atol(@ptrCast("stop42true"))); - try std.testing.expectEqual(42, atol(@ptrCast("42true"))); - try std.testing.expectEqual(-1, atol(@ptrCast("-01"))); - try std.testing.expectEqual(1, atol(@ptrCast("+001"))); - try std.testing.expectEqual(100, atol(@ptrCast(" 100"))); - try std.testing.expectEqual(500, atol(@ptrCast("000000000000500"))); - try std.testing.expectEqual(1111, atol(@ptrCast("0000000000001111_0000"))); - try std.testing.expectEqual(0, atol(@ptrCast("0xAA"))); - try std.testing.expectEqual(700, atol(@ptrCast("700B"))); - try std.testing.expectEqual(32453, atol(@ptrCast("+32453more"))); - try std.testing.expectEqual(std.math.maxInt(c_long), atol(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_long)})))); - try std.testing.expectEqual(std.math.minInt(c_long), atol(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_long)})))); -} - -test atoll { - try std.testing.expectEqual(0, atoll(@ptrCast("stop42true"))); - try std.testing.expectEqual(42, atoll(@ptrCast("42true"))); - try std.testing.expectEqual(-1, atoll(@ptrCast("-01"))); - try std.testing.expectEqual(1, atoll(@ptrCast("+001"))); - try std.testing.expectEqual(100, atoll(@ptrCast(" 100"))); - try std.testing.expectEqual(500, atoll(@ptrCast("000000000000500"))); - try std.testing.expectEqual(1111, atoll(@ptrCast("0000000000001111_0000"))); - try std.testing.expectEqual(0, atoll(@ptrCast("0xAA"))); - try std.testing.expectEqual(700, atoll(@ptrCast("700B"))); - try std.testing.expectEqual(32453, atoll(@ptrCast(" +32453more"))); - try std.testing.expectEqual(std.math.maxInt(c_longlong), atoll(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.maxInt(c_longlong)})))); - try std.testing.expectEqual(std.math.minInt(c_longlong), atoll(@ptrCast(std.fmt.comptimePrint("{d}", .{std.math.minInt(c_longlong)})))); -} - -// FIXME: We cannot test strtol, strtoll, strtoul, etc.. here as it must modify errno and libc is not linked in tests - -test bsearch { - const Comparison = struct { - pub fn compare(a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int { - const a_u16: *const u16 = @ptrCast(@alignCast(a)); - const b_u16: *const u16 = @ptrCast(@alignCast(b)); - - return switch (std.math.order(a_u16.*, b_u16.*)) { - .gt => 1, - .eq => 0, - .lt => -1, - }; - } - }; - - const items: []const u16 = &.{ 0, 5, 7, 9, 10, 200, 512, 768 }; - - try std.testing.expectEqual(@as(?*anyopaque, null), bsearch(&@as(u16, 2000), items.ptr, items.len, @sizeOf(u16), Comparison.compare)); - - for (items) |*value| { - try std.testing.expectEqual(@as(*const anyopaque, value), bsearch(value, items.ptr, items.len, @sizeOf(u16), Comparison.compare)); - } -} diff --git a/lib/c/stdlib/drand48.zig b/lib/c/stdlib/drand48.zig index 266cc7af4a..692230d121 100644 --- a/lib/c/stdlib/drand48.zig +++ b/lib/c/stdlib/drand48.zig @@ -90,60 +90,3 @@ fn srand48(seedval: c_long) callconv(.c) void { const xi = (@as(u32, @truncate(@as(c_ulong, @bitCast(seedval)))) << 16) | 0x330E; lcg = .init(xi, default_multiplier, default_addend); } - -test erand48 { - var xsubi: [3]c_ushort = .{ 37174, 64810, 11603 }; - - try std.testing.expectApproxEqAbs(0.8965, erand48(&xsubi), 0.0005); - try std.testing.expectEqualSlices(c_ushort, &.{ 22537, 47966, 58735 }, &xsubi); - - try std.testing.expectApproxEqAbs(0.3375, erand48(&xsubi), 0.0005); - try std.testing.expectEqualSlices(c_ushort, &.{ 37344, 32911, 22119 }, &xsubi); - - try std.testing.expectApproxEqAbs(0.6475, erand48(&xsubi), 0.0005); - try std.testing.expectEqualSlices(c_ushort, &.{ 23659, 29872, 42445 }, &xsubi); - - try std.testing.expectApproxEqAbs(0.5005, erand48(&xsubi), 0.0005); - try std.testing.expectEqualSlices(c_ushort, &.{ 31642, 7875, 32802 }, &xsubi); - - try std.testing.expectApproxEqAbs(0.5065, erand48(&xsubi), 0.0005); - try std.testing.expectEqualSlices(c_ushort, &.{ 64669, 14399, 33170 }, &xsubi); -} - -test jrand48 { - var xsubi: [3]c_ushort = .{ 25175, 11052, 45015 }; - - try std.testing.expectEqual(1699503220, jrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 2326, 23668, 25932 }, &xsubi); - - try std.testing.expectEqual(-992276007, jrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 41577, 4569, 50395 }, &xsubi); - - try std.testing.expectEqual(-19535776, jrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 31936, 59488, 65237 }, &xsubi); - - try std.testing.expectEqual(79438377, jrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 40395, 8745, 1212 }, &xsubi); - - try std.testing.expectEqual(-1258917728, jrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 37242, 28832, 46326 }, &xsubi); -} - -test nrand48 { - var xsubi: [3]c_ushort = .{ 546, 33817, 23389 }; - - try std.testing.expectEqual(914920692, nrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 29829, 10728, 27921 }, &xsubi); - - try std.testing.expectEqual(754104482, nrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 6828, 28997, 23013 }, &xsubi); - - try std.testing.expectEqual(609453945, nrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 58183, 3826, 18599 }, &xsubi); - - try std.testing.expectEqual(1878644360, nrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 36678, 44304, 57331 }, &xsubi); - - try std.testing.expectEqual(2114923686, nrand48(&xsubi)); - try std.testing.expectEqualSlices(c_ushort, &.{ 58585, 22861, 64542 }, &xsubi); -} diff --git a/lib/c/string.zig b/lib/c/string.zig index 722ef0ba77..da301a19eb 100644 --- a/lib/c/string.zig +++ b/lib/c/string.zig @@ -290,10 +290,3 @@ fn mempcpy(noalias dst: *anyopaque, noalias src: *const anyopaque, len: usize) c @memcpy(dst_bytes[0..len], src_bytes[0..len]); return dst_bytes + len; } - -test strncmp { - try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0); - try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0); - try std.testing.expect(strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0); - try std.testing.expect(strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0); -} diff --git a/lib/c/strings.zig b/lib/c/strings.zig index 8a052795ae..111da9ad0f 100644 --- a/lib/c/strings.zig +++ b/lib/c/strings.zig @@ -81,41 +81,3 @@ fn __strncasecmp_l(a: [*:0]const c_char, b: [*:0]const c_char, n: usize, locale: _ = locale; return strncasecmp(a, b, n); } - -test bzero { - var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }; - var a = std.mem.zeroes([array.len]u8); - a[9] = '0'; - bzero(&array[0], 9); - try std.testing.expect(std.mem.eql(u8, &array, &a)); -} - -test firstBitSet { - try std.testing.expectEqual(0, firstBitSet(usize, 0)); - - for (0..@bitSizeOf(usize)) |i| { - const bit = @as(usize, 1) << @intCast(i); - - try std.testing.expectEqual(i + 1, firstBitSet(usize, bit)); - } -} - -test strcasecmp { - try std.testing.expect(strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0); - try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0); - try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0); - try std.testing.expect(strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0); - try std.testing.expect(strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0); - try std.testing.expect(strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0); - try std.testing.expect(strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0); -} - -test strncasecmp { - try std.testing.expect(strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0); - try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0); - try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0); - try std.testing.expect(strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0); - try std.testing.expect(strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0); - try std.testing.expect(strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0); - try std.testing.expect(strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0); -} diff --git a/lib/c/unistd.zig b/lib/c/unistd.zig index 676f943f36..f802fdb92e 100644 --- a/lib/c/unistd.zig +++ b/lib/c/unistd.zig @@ -206,32 +206,6 @@ fn swab(noalias src_ptr: *const anyopaque, noalias dest_ptr: *anyopaque, n: isiz } } -test swab { - var a: [4]u8 = undefined; - @memset(a[0..], '\x00'); - swab("abcd", &a, 4); - try std.testing.expectEqualSlices(u8, "badc", &a); - - // Partial copy - @memset(a[0..], '\x00'); - swab("abcd", &a, 2); - try std.testing.expectEqualSlices(u8, "ba\x00\x00", &a); - - // n < 1 - @memset(a[0..], '\x00'); - swab("abcd", &a, 0); - try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a); - swab("abcd", &a, -1); - try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a); - - // Odd n - @memset(a[0..], '\x00'); - swab("abcd", &a, 1); - try std.testing.expectEqualSlices(u8, "\x00" ** 4, &a); - swab("abcd", &a, 3); - try std.testing.expectEqualSlices(u8, "ba\x00\x00", &a); -} - fn close(fd: std.c.fd_t) callconv(.c) c_int { const signed: isize = @bitCast(linux.close(fd)); if (signed < 0) { diff --git a/lib/std/c.zig b/lib/std/c.zig index bb028dbdaa..11b58b2162 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -11102,13 +11102,60 @@ pub const ioctl = switch (native_os) { else => private.ioctl, }; +pub extern "c" fn bzero(s: *anyopaque, n: usize) void; + +pub extern "c" fn swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void; + +pub extern "c" fn strncmp(a: [*:0]const c_char, b: [*:0]const c_char, max: usize) c_int; +pub extern "c" fn strcasecmp(a: [*:0]const c_char, b: [*:0]const c_char) c_int; +pub extern "c" fn strncasecmp(a: [*:0]const c_char, b: [*:0]const c_char, max: usize) c_int; + +pub extern "c" fn ffs(i: c_int) c_int; +pub extern "c" fn ffsl(i: c_long) c_long; +pub extern "c" fn ffsll(i: c_longlong) c_longlong; + +pub extern "c" fn erand48(xsubi: *[3]c_ushort) f64; +pub extern "c" fn jrand48(xsubi: *[3]c_ushort) c_long; +pub extern "c" fn nrand48(xsubi: *[3]c_ushort) c_long; + +pub extern "c" fn insque(element: *anyopaque, pred: ?*anyopaque) void; +pub extern "c" fn remque(element: *anyopaque) void; + +pub extern "c" fn imaxabs(a: intmax_t) intmax_t; +pub extern "c" fn imaxdiv(a: intmax_t, b: intmax_t) imaxdiv_t; + +pub extern "c" fn abs(a: c_int) c_int; +pub extern "c" fn labs(a: c_long) c_long; +pub extern "c" fn llabs(a: c_longlong) c_longlong; + +pub extern "c" fn div(a: c_int, b: c_int) div_t; +pub extern "c" fn ldiv(a: c_long, b: c_long) ldiv_t; +pub extern "c" fn lldiv(a: c_longlong, b: c_longlong) lldiv_t; + +pub extern "c" fn atoi(str: [*:0]const c_char) c_int; +pub extern "c" fn atol(str: [*:0]const c_char) c_long; +pub extern "c" fn atoll(str: [*:0]const c_char) c_longlong; + +pub extern "c" fn bsearch( + key: *const anyopaque, + base: *const anyopaque, + n: usize, + size: usize, + compare: *const fn (a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int, +) ?*anyopaque; + // Math -pub extern "c" fn atan(x: f64) callconv(.c) f64; -pub extern "c" fn copysign(x: f64, y: f64) callconv(.c) f64; -pub extern "c" fn fdim(x: f64, y: f64) callconv(.c) f64; -pub extern "c" fn frexp(x: f64, e: *c_int) callconv(.c) f64; -pub extern "c" fn hypot(x: f64, y: f64) callconv(.c) f64; -pub extern "c" fn modf(x: f64, iptr: *f64) callconv(.c) f64; +pub extern "c" fn atan(x: f64) f64; +pub extern "c" fn copysign(x: f64, y: f64) f64; +pub extern "c" fn fdim(x: f64, y: f64) f64; +pub extern "c" fn frexp(x: f64, e: *c_int) f64; +pub extern "c" fn hypot(x: f64, y: f64) f64; +pub extern "c" fn modff(x: f32, iptr: *f32) f32; +pub extern "c" fn modf(x: f64, iptr: *f64) f64; +pub extern "c" fn modfl(x: c_longdouble, iptr: *c_longdouble) c_longdouble; +pub extern "c" fn rintf(x: f32) f32; +pub extern "c" fn rint(x: f64) f64; +pub extern "c" fn rintl(x: c_longdouble) c_longdouble; // OS-specific bits. These are protected from being used on the wrong OS by // comptime assertions inside each OS-specific file. diff --git a/test/c.zig b/test/c.zig new file mode 100644 index 0000000000..797f16f5cb --- /dev/null +++ b/test/c.zig @@ -0,0 +1,12 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +test { + _ = @import("c/inttypes.zig"); + _ = @import("c/math.zig"); + _ = @import("c/search.zig"); + _ = @import("c/stdlib.zig"); + _ = @import("c/string.zig"); + _ = @import("c/strings.zig"); + _ = @import("c/unistd.zig"); +} diff --git a/test/c/inttypes.zig b/test/c/inttypes.zig new file mode 100644 index 0000000000..9b9cbfe966 --- /dev/null +++ b/test/c/inttypes.zig @@ -0,0 +1,15 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const testing = std.testing; + +test "imaxabs" { + const val: c.intmax_t = -10; + try testing.expectEqual(10, c.imaxabs(val)); +} + +test "imaxdiv" { + const expected: c.imaxdiv_t = .{ .quot = 9, .rem = 0 }; + try testing.expectEqual(expected, c.imaxdiv(9, 1)); +} diff --git a/test/c/math.zig b/test/c/math.zig new file mode 100644 index 0000000000..cf372dc0be --- /dev/null +++ b/test/c/math.zig @@ -0,0 +1,101 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const math = std.math; +const testing = std.testing; + +fn testModf(comptime T: type) !void { + const f = switch (T) { + f32 => c.modff, + f64 => c.modf, + c_longdouble => c.modfl, + else => unreachable, + }; + + var int: T = undefined; + const iptr = ∫ + const eps_val: comptime_float = @max(1e-6, math.floatEps(T)); + + const normal_frac = f(@as(T, 1234.567), iptr); + // Account for precision error + const expected = 1234.567 - @as(T, 1234); + try testing.expectApproxEqAbs(expected, normal_frac, eps_val); + try testing.expectApproxEqRel(@as(T, 1234.0), iptr.*, eps_val); + + // When `x` is a NaN, NaN is returned and `*iptr` is set to NaN + const nan_frac = f(math.nan(T), iptr); + try testing.expect(math.isNan(nan_frac)); + try testing.expect(math.isNan(iptr.*)); + + // When `x` is positive infinity, +0 is returned and `*iptr` is set to + // positive infinity + const pos_zero_frac = f(math.inf(T), iptr); + try testing.expect(math.isPositiveZero(pos_zero_frac)); + try testing.expect(math.isPositiveInf(iptr.*)); + + // When `x` is negative infinity, -0 is returned and `*iptr` is set to + // negative infinity + const neg_zero_frac = f(-math.inf(T), iptr); + try testing.expect(math.isNegativeZero(neg_zero_frac)); + try testing.expect(math.isNegativeInf(iptr.*)); + + // Return -0 when `x` is a negative integer + const nz_frac = f(@as(T, -1000.0), iptr); + try testing.expect(math.isNegativeZero(nz_frac)); + try testing.expectEqual(@as(T, -1000.0), iptr.*); + + // Return +0 when `x` is a positive integer + const pz_frac = f(@as(T, 1000.0), iptr); + try testing.expect(math.isPositiveZero(pz_frac)); + try testing.expectEqual(@as(T, 1000.0), iptr.*); +} + +test "modf" { + try testModf(f32); + try testModf(f64); + try testModf(c_longdouble); +} + +fn testRint(comptime T: type) !void { + const f = switch (T) { + f32 => c.rintf, + f64 => c.rint, + else => @compileError("rint not implemented for" ++ @typeName(T)), + }; + + // Positive numbers round correctly + try testing.expectEqual(@as(T, 42.0), f(42.2)); + try testing.expectEqual(@as(T, 42.0), f(41.8)); + + // Negative numbers round correctly + try testing.expectEqual(@as(T, -6.0), f(-5.9)); + try testing.expectEqual(@as(T, -6.0), f(-6.1)); + + // No rounding needed test + try testing.expectEqual(@as(T, 5.0), f(5.0)); + try testing.expectEqual(@as(T, -10.0), f(-10.0)); + try testing.expectEqual(@as(T, 0.0), f(0.0)); + + // Very large numbers return unchanged + const large: T = 9007199254740992.0; // 2^53 + try testing.expectEqual(large, f(large)); + try testing.expectEqual(-large, f(-large)); + + // Small positive numbers round to zero + const pos_result = f(0.3); + try testing.expect(math.isPositiveZero(pos_result)); + + // Small negative numbers round to negative zero + const neg_result = f(-0.3); + try testing.expect(math.isNegativeZero(neg_result)); + + // Exact half rounds to nearest even (banker's rounding) + try testing.expectEqual(@as(T, 2.0), f(2.5)); + try testing.expectEqual(@as(T, 4.0), f(3.5)); +} + +test "rint" { + try testRint(f32); + try testRint(f64); +} diff --git a/test/c/search.zig b/test/c/search.zig new file mode 100644 index 0000000000..aa79c34368 --- /dev/null +++ b/test/c/search.zig @@ -0,0 +1,38 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const testing = std.testing; + +/// Not defined in `std.c` because C headers don't either. +const Node = extern struct { + next: ?*Node, + prev: ?*Node, +}; + +test "insque and remque" { + var first: Node = .{ .next = null, .prev = null }; + var second: Node = .{ .next = null, .prev = null }; + var third: Node = .{ .next = null, .prev = null }; + + c.insque(&first, null); + try testing.expectEqual(@as(?*Node, null), first.next); + try testing.expectEqual(@as(?*Node, null), first.prev); + + c.insque(&second, &first); + try testing.expectEqual(@as(?*Node, &second), first.next); + try testing.expectEqual(@as(?*Node, &first), second.prev); + + c.insque(&third, &first); + try testing.expectEqual(@as(?*Node, &third), first.next); + try testing.expectEqual(@as(?*Node, &second), third.next); + try testing.expectEqual(@as(?*Node, &first), third.prev); + try testing.expectEqual(@as(?*Node, &third), second.prev); + + c.remque(&third); + try testing.expectEqual(@as(?*Node, &second), first.next); + try testing.expectEqual(@as(?*Node, &first), second.prev); + + c.remque(&second); + try testing.expectEqual(@as(?*Node, null), first.next); +} diff --git a/test/c/stdlib.zig b/test/c/stdlib.zig new file mode 100644 index 0000000000..1491c9fa4a --- /dev/null +++ b/test/c/stdlib.zig @@ -0,0 +1,109 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const fmt = std.fmt; +const math = std.math; +const testing = std.testing; + +test "abs" { + const val: c_int = -10; + try testing.expectEqual(10, c.abs(val)); +} + +test "labs" { + const val: c_long = -10; + try testing.expectEqual(10, c.labs(val)); +} + +test "llabs" { + const val: c_longlong = -10; + try testing.expectEqual(10, c.llabs(val)); +} + +test "div" { + const expected: c.div_t = .{ .quot = 5, .rem = 5 }; + try testing.expectEqual(expected, c.div(55, 10)); +} + +test "ldiv" { + const expected: c.ldiv_t = .{ .quot = -6, .rem = 2 }; + try testing.expectEqual(expected, c.ldiv(38, -6)); +} + +test "lldiv" { + const expected: c.lldiv_t = .{ .quot = 1, .rem = 2 }; + try testing.expectEqual(expected, c.lldiv(5, 3)); +} + +test "atoi" { + try testing.expectEqual(0, c.atoi(@ptrCast("stop42true"))); + try testing.expectEqual(42, c.atoi(@ptrCast("42true"))); + try testing.expectEqual(-1, c.atoi(@ptrCast("-01"))); + try testing.expectEqual(1, c.atoi(@ptrCast("+001"))); + try testing.expectEqual(100, c.atoi(@ptrCast(" 100"))); + try testing.expectEqual(500, c.atoi(@ptrCast("000000000000500"))); + try testing.expectEqual(1111, c.atoi(@ptrCast("0000000000001111_0000"))); + try testing.expectEqual(0, c.atoi(@ptrCast("0xAA"))); + try testing.expectEqual(700, c.atoi(@ptrCast("700B"))); + try testing.expectEqual(32453, c.atoi(@ptrCast("+32453more"))); + try testing.expectEqual(math.maxInt(c_int), c.atoi(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_int)})))); + try testing.expectEqual(math.minInt(c_int), c.atoi(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_int)})))); +} + +test "atol" { + try testing.expectEqual(0, c.atol(@ptrCast("stop42true"))); + try testing.expectEqual(42, c.atol(@ptrCast("42true"))); + try testing.expectEqual(-1, c.atol(@ptrCast("-01"))); + try testing.expectEqual(1, c.atol(@ptrCast("+001"))); + try testing.expectEqual(100, c.atol(@ptrCast(" 100"))); + try testing.expectEqual(500, c.atol(@ptrCast("000000000000500"))); + try testing.expectEqual(1111, c.atol(@ptrCast("0000000000001111_0000"))); + try testing.expectEqual(0, c.atol(@ptrCast("0xAA"))); + try testing.expectEqual(700, c.atol(@ptrCast("700B"))); + try testing.expectEqual(32453, c.atol(@ptrCast("+32453more"))); + try testing.expectEqual(math.maxInt(c_long), c.atol(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_long)})))); + try testing.expectEqual(math.minInt(c_long), c.atol(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_long)})))); +} + +test "atoll" { + try testing.expectEqual(0, c.atoll(@ptrCast("stop42true"))); + try testing.expectEqual(42, c.atoll(@ptrCast("42true"))); + try testing.expectEqual(-1, c.atoll(@ptrCast("-01"))); + try testing.expectEqual(1, c.atoll(@ptrCast("+001"))); + try testing.expectEqual(100, c.atoll(@ptrCast(" 100"))); + try testing.expectEqual(500, c.atoll(@ptrCast("000000000000500"))); + try testing.expectEqual(1111, c.atoll(@ptrCast("0000000000001111_0000"))); + try testing.expectEqual(0, c.atoll(@ptrCast("0xAA"))); + try testing.expectEqual(700, c.atoll(@ptrCast("700B"))); + try testing.expectEqual(32453, c.atoll(@ptrCast(" +32453more"))); + try testing.expectEqual(math.maxInt(c_longlong), c.atoll(@ptrCast(fmt.comptimePrint("{d}", .{math.maxInt(c_longlong)})))); + try testing.expectEqual(math.minInt(c_longlong), c.atoll(@ptrCast(fmt.comptimePrint("{d}", .{math.minInt(c_longlong)})))); +} + +test "bsearch" { + const Comparison = struct { + pub fn compare(a: *const anyopaque, b: *const anyopaque) callconv(.c) c_int { + const a_u16: *const u16 = @ptrCast(@alignCast(a)); + const b_u16: *const u16 = @ptrCast(@alignCast(b)); + + return switch (math.order(a_u16.*, b_u16.*)) { + .gt => 1, + .eq => 0, + .lt => -1, + }; + } + }; + + const items: []const u16 = &.{ 0, 5, 7, 9, 10, 200, 512, 768 }; + + try testing.expectEqual(@as(?*anyopaque, null), c.bsearch(&@as(u16, 2000), items.ptr, items.len, @sizeOf(u16), Comparison.compare)); + + for (items) |*value| { + try testing.expectEqual(@as(*const anyopaque, value), c.bsearch(value, items.ptr, items.len, @sizeOf(u16), Comparison.compare)); + } +} + +test { + _ = @import("stdlib/drand48.zig"); +} diff --git a/test/c/stdlib/drand48.zig b/test/c/stdlib/drand48.zig new file mode 100644 index 0000000000..6552730b52 --- /dev/null +++ b/test/c/stdlib/drand48.zig @@ -0,0 +1,62 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const testing = std.testing; + +test "erand48" { + var xsubi: [3]c_ushort = .{ 37174, 64810, 11603 }; + + try testing.expectApproxEqAbs(0.8965, c.erand48(&xsubi), 0.0005); + try testing.expectEqualSlices(c_ushort, &.{ 22537, 47966, 58735 }, &xsubi); + + try testing.expectApproxEqAbs(0.3375, c.erand48(&xsubi), 0.0005); + try testing.expectEqualSlices(c_ushort, &.{ 37344, 32911, 22119 }, &xsubi); + + try testing.expectApproxEqAbs(0.6475, c.erand48(&xsubi), 0.0005); + try testing.expectEqualSlices(c_ushort, &.{ 23659, 29872, 42445 }, &xsubi); + + try testing.expectApproxEqAbs(0.5005, c.erand48(&xsubi), 0.0005); + try testing.expectEqualSlices(c_ushort, &.{ 31642, 7875, 32802 }, &xsubi); + + try testing.expectApproxEqAbs(0.5065, c.erand48(&xsubi), 0.0005); + try testing.expectEqualSlices(c_ushort, &.{ 64669, 14399, 33170 }, &xsubi); +} + +test "jrand48" { + var xsubi: [3]c_ushort = .{ 25175, 11052, 45015 }; + + try testing.expectEqual(1699503220, c.jrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 2326, 23668, 25932 }, &xsubi); + + try testing.expectEqual(-992276007, c.jrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 41577, 4569, 50395 }, &xsubi); + + try testing.expectEqual(-19535776, c.jrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 31936, 59488, 65237 }, &xsubi); + + try testing.expectEqual(79438377, c.jrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 40395, 8745, 1212 }, &xsubi); + + try testing.expectEqual(-1258917728, c.jrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 37242, 28832, 46326 }, &xsubi); +} + +test "nrand48" { + var xsubi: [3]c_ushort = .{ 546, 33817, 23389 }; + + try testing.expectEqual(914920692, c.nrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 29829, 10728, 27921 }, &xsubi); + + try testing.expectEqual(754104482, c.nrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 6828, 28997, 23013 }, &xsubi); + + try testing.expectEqual(609453945, c.nrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 58183, 3826, 18599 }, &xsubi); + + try testing.expectEqual(1878644360, c.nrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 36678, 44304, 57331 }, &xsubi); + + try testing.expectEqual(2114923686, c.nrand48(&xsubi)); + try testing.expectEqualSlices(c_ushort, &.{ 58585, 22861, 64542 }, &xsubi); +} diff --git a/test/c/string.zig b/test/c/string.zig new file mode 100644 index 0000000000..255c147eae --- /dev/null +++ b/test/c/string.zig @@ -0,0 +1,12 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const testing = std.testing; + +test "strncmp" { + try testing.expect(c.strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0); + try testing.expect(c.strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0); + try testing.expect(c.strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0); + try testing.expect(c.strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0); +} diff --git a/test/c/strings.zig b/test/c/strings.zig new file mode 100644 index 0000000000..08bad240af --- /dev/null +++ b/test/c/strings.zig @@ -0,0 +1,57 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const mem = std.mem; +const testing = std.testing; + +test "bzero" { + var array: [10]u8 = [_]u8{ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }; + var a = mem.zeroes([array.len]u8); + a[9] = '0'; + c.bzero(&array[0], 9); + try testing.expect(mem.eql(u8, &array, &a)); +} + +fn testFfs(comptime T: type) !void { + const ffs = switch (T) { + c_int => c.ffs, + c_long => c.ffsl, + c_longlong => c.ffsll, + else => unreachable, + }; + + try testing.expectEqual(0, ffs(0)); + + for (0..@bitSizeOf(T)) |i| { + const bit = @as(T, 1) << @intCast(i); + + try testing.expectEqual(@as(T, @intCast(i + 1)), ffs(bit)); + } +} + +test "ffs" { + try testFfs(c_int); + try testFfs(c_long); + try testFfs(c_longlong); +} + +test "strcasecmp" { + try testing.expect(c.strcasecmp(@ptrCast("a"), @ptrCast("b")) < 0); + try testing.expect(c.strcasecmp(@ptrCast("b"), @ptrCast("a")) > 0); + try testing.expect(c.strcasecmp(@ptrCast("A"), @ptrCast("b")) < 0); + try testing.expect(c.strcasecmp(@ptrCast("b"), @ptrCast("A")) > 0); + try testing.expect(c.strcasecmp(@ptrCast("A"), @ptrCast("A")) == 0); + try testing.expect(c.strcasecmp(@ptrCast("B"), @ptrCast("b")) == 0); + try testing.expect(c.strcasecmp(@ptrCast("bb"), @ptrCast("AA")) > 0); +} + +test "strncasecmp" { + try testing.expect(c.strncasecmp(@ptrCast("a"), @ptrCast("b"), 1) < 0); + try testing.expect(c.strncasecmp(@ptrCast("b"), @ptrCast("a"), 1) > 0); + try testing.expect(c.strncasecmp(@ptrCast("A"), @ptrCast("b"), 1) < 0); + try testing.expect(c.strncasecmp(@ptrCast("b"), @ptrCast("A"), 1) > 0); + try testing.expect(c.strncasecmp(@ptrCast("A"), @ptrCast("A"), 1) == 0); + try testing.expect(c.strncasecmp(@ptrCast("B"), @ptrCast("b"), 1) == 0); + try testing.expect(c.strncasecmp(@ptrCast("bb"), @ptrCast("AA"), 2) > 0); +} diff --git a/test/c/unistd.zig b/test/c/unistd.zig new file mode 100644 index 0000000000..3c99bd2f48 --- /dev/null +++ b/test/c/unistd.zig @@ -0,0 +1,31 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const c = std.c; +const testing = std.testing; + +test "swab" { + var a: [4]u8 = undefined; + @memset(a[0..], '\x00'); + c.swab("abcd", &a, 4); + try testing.expectEqualSlices(u8, "badc", &a); + + // Partial copy + @memset(a[0..], '\x00'); + c.swab("abcd", &a, 2); + try testing.expectEqualSlices(u8, "ba\x00\x00", &a); + + // n < 1 + @memset(a[0..], '\x00'); + c.swab("abcd", &a, 0); + try testing.expectEqualSlices(u8, "\x00" ** 4, &a); + c.swab("abcd", &a, -1); + try testing.expectEqualSlices(u8, "\x00" ** 4, &a); + + // Odd n + @memset(a[0..], '\x00'); + c.swab("abcd", &a, 1); + try testing.expectEqualSlices(u8, "\x00" ** 4, &a); + c.swab("abcd", &a, 3); + try testing.expectEqualSlices(u8, "ba\x00\x00", &a); +} diff --git a/test/tests.zig b/test/tests.zig index 9887b0f024..f8187b1618 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -18,7 +18,7 @@ pub const DebuggerContext = @import("src/Debugger.zig"); pub const LlvmIrContext = @import("src/LlvmIr.zig"); pub const LibcContext = @import("src/Libc.zig"); -const TestTarget = struct { +const ModuleTestTarget = struct { linkage: ?std.builtin.LinkMode = null, target: std.Target.Query = .{}, optimize_mode: std.builtin.OptimizeMode = .Debug, @@ -36,33 +36,14 @@ const TestTarget = struct { // invocation. This could be because of a slow backend, requiring a newer LLVM version, being // too niche, etc. extra_target: bool = false, - - pub fn supportsModule( - self: *const TestTarget, - target: *const std.Build.ResolvedTarget, - name: []const u8, - ) bool { - if (mem.eql(u8, name, "zigc")) { - if (target.result.isMuslLibC()) return self.linkage == .static or (self.linkage == null and !target.query.isNative()); - if (target.result.isMinGW()) return true; - if (target.result.isWasiLibC()) return true; - return false; - } - if (mem.eql(u8, name, "std")) { - if (target.result.cpu.arch.isSpirV()) return false; - return true; - } - - return true; - } }; -const test_targets = blk: { +const module_test_targets = blk: { // getBaselineCpuFeatures calls populateDependencies which has a O(N ^ 2) algorithm // (where N is roughly 160, which technically makes it O(1), but it adds up to a // lot of branches) @setEvalBranchQuota(80_000); - break :blk [_]TestTarget{ + break :blk [_]ModuleTestTarget{ // Native Targets .{}, // 0 index must be all defaults @@ -2475,24 +2456,21 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { const step = b.step(b.fmt("test-{s}", .{options.name}), options.desc); if (options.test_only) |test_only| { - const test_target: TestTarget = switch (test_only) { - .default => test_targets[0], + const test_target: ModuleTestTarget = switch (test_only) { + .default => module_test_targets[0], .fuzz => |optimize| .{ .optimize_mode = optimize, .use_llvm = true, }, }; const resolved_target = b.resolveTargetQuery(test_target.target); - - if (test_target.supportsModule(&resolved_target, options.name)) { - const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"); - addOneModuleTest(b, step, test_target, &resolved_target, triple_txt, options); - } + const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"); + addOneModuleTest(b, step, test_target, &resolved_target, triple_txt, options); return step; } - for_targets: for (test_targets) |test_target| { + for_targets: for (module_test_targets) |test_target| { if (test_target.skip_modules.len > 0) { for (test_target.skip_modules) |skip_mod| { if (std.mem.eql(u8, options.name, skip_mod)) continue :for_targets; @@ -2501,8 +2479,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { const resolved_target = b.resolveTargetQuery(test_target.target); - if (!test_target.supportsModule(&resolved_target, options.name)) continue; - if (!options.test_extra_targets and test_target.extra_target) continue; if (options.skip_non_native and !test_target.target.isNative()) @@ -2510,6 +2486,13 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { const target = &resolved_target.result; + if (std.mem.eql(u8, options.name, "libc")) { + // The libc API tests obviously need to link libc. So for test + // target entries where we wouldn't link libc by default, skip the + // libc API tests. + if (test_target.link_libc == null and !std.os.targetRequiresLibC(target)) continue; + } + if (options.skip_spirv and target.cpu.arch.isSpirV()) continue; if (options.skip_wasm and target.cpu.arch.isWasm()) continue; @@ -2544,8 +2527,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { if (!would_use_llvm and target.cpu.arch == .aarch64) { // TODO get std tests passing for the aarch64 self-hosted backend. if (mem.eql(u8, options.name, "std")) continue; - // TODO get zigc tests passing for the aarch64 self-hosted backend. - if (mem.eql(u8, options.name, "zigc")) continue; } const want_this_mode = for (options.optimize_modes) |m| { @@ -2561,7 +2542,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { fn addOneModuleTest( b: *std.Build, step: *Step, - test_target: TestTarget, + test_target: ModuleTestTarget, resolved_target: *const std.Build.ResolvedTarget, triple_txt: []const u8, options: ModuleTestOptions, @@ -2598,11 +2579,11 @@ fn addOneModuleTest( }); these_tests.linkage = test_target.linkage; // https://codeberg.org/ziglang/zig/issues/31701 - if (!(mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "zigc"))) { + if (!(mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc"))) { if (options.no_builtin) these_tests.root_module.no_builtin = true; } // https://codeberg.org/ziglang/zig/issues/31702 - if (mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "zigc")) { + if (mem.eql(u8, options.name, "compiler-rt") or mem.eql(u8, options.name, "libc")) { these_tests.root_module.stack_protector = false; } if (options.build_options) |build_options| { @@ -2992,7 +2973,7 @@ pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step { return step; } -const libc_targets: []const std.Target.Query = &.{ +const libc_test_nsz_targets: []const std.Target.Query = &.{ .{ .cpu_arch = .arm, .os_tag = .linux, @@ -3155,8 +3136,8 @@ const libc_targets: []const std.Target.Query = &.{ }, }; -pub fn addLibcTests(b: *std.Build, options: LibcContext.Options) ?*Step { - const step = b.step("test-libc", "Run libc-test test cases"); +pub fn addLibcTestNszTests(b: *std.Build, options: LibcContext.Options) ?*Step { + const step = b.step("test-libc-nsz", "Run external libc-test test cases"); const opt_libc_test_path = b.option(std.Build.LazyPath, "libc-test-path", "path to libc-test source directory"); if (opt_libc_test_path) |libc_test_path| { var context: LibcContext = .{ @@ -3168,7 +3149,7 @@ pub fn addLibcTests(b: *std.Build, options: LibcContext.Options) ?*Step { libc.addCases(&context); - for (libc_targets) |target_query| { + for (libc_test_nsz_targets) |target_query| { const target = b.resolveTargetQuery(target_query); context.addTarget(target); }