authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-01 14:21:04-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-01 14:21:04-07:00
log309aacfc8993ff4ec5914a7ee2c487eabbe00998
treefebc13c372a0fb6c4a237e065a7e00575046339a
parent8f14431bc883898aaf78cc985e2d90716187e882
parent073289d0dadfd1ea0088837563a109100b065ed3
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16284 from Snektron/spirv-internpool-fixes

SPIR-V InternPool aftermath damage control

9 files changed, 189 insertions(+), 101 deletions(-)

lib/std/builtin.zig+2-1
...@@ -741,7 +741,8 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr...@@ -741,7 +741,8 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
741 builtin.zig_backend == .stage2_x86_64 or741 builtin.zig_backend == .stage2_x86_64 or
742 builtin.zig_backend == .stage2_x86 or742 builtin.zig_backend == .stage2_x86 or
743 builtin.zig_backend == .stage2_riscv64 or743 builtin.zig_backend == .stage2_riscv64 or
744 builtin.zig_backend == .stage2_sparc64)744 builtin.zig_backend == .stage2_sparc64 or
745 builtin.zig_backend == .stage2_spirv64)
745 {746 {
746 while (true) {747 while (true) {
747 @breakpoint();748 @breakpoint();
lib/std/testing.zig+50-44
...@@ -2,7 +2,6 @@ const std = @import("std.zig");...@@ -2,7 +2,6 @@ const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4const math = std.math;4const math = std.math;
5const print = std.debug.print;
65
7pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator;6pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator;
87
...@@ -22,15 +21,22 @@ pub var base_allocator_instance = std.heap.FixedBufferAllocator.init("");...@@ -22,15 +21,22 @@ pub var base_allocator_instance = std.heap.FixedBufferAllocator.init("");
22/// TODO https://github.com/ziglang/zig/issues/573821/// TODO https://github.com/ziglang/zig/issues/5738
23pub var log_level = std.log.Level.warn;22pub var log_level = std.log.Level.warn;
2423
24fn print(comptime fmt: []const u8, args: anytype) void {
25 // Disable printing in tests for simple backends.
26 if (builtin.zig_backend == .stage2_spirv64) return;
27
28 std.debug.print(fmt, args);
29}
30
25/// This function is intended to be used only in tests. It prints diagnostics to stderr31/// This function is intended to be used only in tests. It prints diagnostics to stderr
26/// and then returns a test failure error when actual_error_union is not expected_error.32/// and then returns a test failure error when actual_error_union is not expected_error.
27pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void {33pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void {
28 if (actual_error_union) |actual_payload| {34 if (actual_error_union) |actual_payload| {
29 std.debug.print("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload });35 print("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload });
30 return error.TestUnexpectedError;36 return error.TestUnexpectedError;
31 } else |actual_error| {37 } else |actual_error| {
32 if (expected_error != actual_error) {38 if (expected_error != actual_error) {
33 std.debug.print("expected error.{s}, found error.{s}\n", .{39 print("expected error.{s}, found error.{s}\n", .{
34 @errorName(expected_error),40 @errorName(expected_error),
35 @errorName(actual_error),41 @errorName(actual_error),
36 });42 });
...@@ -58,7 +64,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -58,7 +64,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
5864
59 .Type => {65 .Type => {
60 if (actual != expected) {66 if (actual != expected) {
61 std.debug.print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });67 print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });
62 return error.TestExpectedEqual;68 return error.TestExpectedEqual;
63 }69 }
64 },70 },
...@@ -74,7 +80,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -74,7 +80,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
74 .ErrorSet,80 .ErrorSet,
75 => {81 => {
76 if (actual != expected) {82 if (actual != expected) {
77 std.debug.print("expected {}, found {}\n", .{ expected, actual });83 print("expected {}, found {}\n", .{ expected, actual });
78 return error.TestExpectedEqual;84 return error.TestExpectedEqual;
79 }85 }
80 },86 },
...@@ -83,17 +89,17 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -83,17 +89,17 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
83 switch (pointer.size) {89 switch (pointer.size) {
84 .One, .Many, .C => {90 .One, .Many, .C => {
85 if (actual != expected) {91 if (actual != expected) {
86 std.debug.print("expected {*}, found {*}\n", .{ expected, actual });92 print("expected {*}, found {*}\n", .{ expected, actual });
87 return error.TestExpectedEqual;93 return error.TestExpectedEqual;
88 }94 }
89 },95 },
90 .Slice => {96 .Slice => {
91 if (actual.ptr != expected.ptr) {97 if (actual.ptr != expected.ptr) {
92 std.debug.print("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr });98 print("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr });
93 return error.TestExpectedEqual;99 return error.TestExpectedEqual;
94 }100 }
95 if (actual.len != expected.len) {101 if (actual.len != expected.len) {
96 std.debug.print("expected slice len {}, found {}\n", .{ expected.len, actual.len });102 print("expected slice len {}, found {}\n", .{ expected.len, actual.len });
97 return error.TestExpectedEqual;103 return error.TestExpectedEqual;
98 }104 }
99 },105 },
...@@ -106,7 +112,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -106,7 +112,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
106 var i: usize = 0;112 var i: usize = 0;
107 while (i < info.len) : (i += 1) {113 while (i < info.len) : (i += 1) {
108 if (!std.meta.eql(expected[i], actual[i])) {114 if (!std.meta.eql(expected[i], actual[i])) {
109 std.debug.print("index {} incorrect. expected {}, found {}\n", .{115 print("index {} incorrect. expected {}, found {}\n", .{
110 i, expected[i], actual[i],116 i, expected[i], actual[i],
111 });117 });
112 return error.TestExpectedEqual;118 return error.TestExpectedEqual;
...@@ -151,12 +157,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -151,12 +157,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
151 if (actual) |actual_payload| {157 if (actual) |actual_payload| {
152 try expectEqual(expected_payload, actual_payload);158 try expectEqual(expected_payload, actual_payload);
153 } else {159 } else {
154 std.debug.print("expected {any}, found null\n", .{expected_payload});160 print("expected {any}, found null\n", .{expected_payload});
155 return error.TestExpectedEqual;161 return error.TestExpectedEqual;
156 }162 }
157 } else {163 } else {
158 if (actual) |actual_payload| {164 if (actual) |actual_payload| {
159 std.debug.print("expected null, found {any}\n", .{actual_payload});165 print("expected null, found {any}\n", .{actual_payload});
160 return error.TestExpectedEqual;166 return error.TestExpectedEqual;
161 }167 }
162 }168 }
...@@ -167,12 +173,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -167,12 +173,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
167 if (actual) |actual_payload| {173 if (actual) |actual_payload| {
168 try expectEqual(expected_payload, actual_payload);174 try expectEqual(expected_payload, actual_payload);
169 } else |actual_err| {175 } else |actual_err| {
170 std.debug.print("expected {any}, found {}\n", .{ expected_payload, actual_err });176 print("expected {any}, found {}\n", .{ expected_payload, actual_err });
171 return error.TestExpectedEqual;177 return error.TestExpectedEqual;
172 }178 }
173 } else |expected_err| {179 } else |expected_err| {
174 if (actual) |actual_payload| {180 if (actual) |actual_payload| {
175 std.debug.print("expected {}, found {any}\n", .{ expected_err, actual_payload });181 print("expected {}, found {any}\n", .{ expected_err, actual_payload });
176 return error.TestExpectedEqual;182 return error.TestExpectedEqual;
177 } else |actual_err| {183 } else |actual_err| {
178 try expectEqual(expected_err, actual_err);184 try expectEqual(expected_err, actual_err);
...@@ -219,7 +225,7 @@ pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance...@@ -219,7 +225,7 @@ pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance
219225
220 switch (@typeInfo(T)) {226 switch (@typeInfo(T)) {
221 .Float => if (!math.approxEqAbs(T, expected, actual, tolerance)) {227 .Float => if (!math.approxEqAbs(T, expected, actual, tolerance)) {
222 std.debug.print("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected });228 print("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected });
223 return error.TestExpectedApproxEqAbs;229 return error.TestExpectedApproxEqAbs;
224 },230 },
225231
...@@ -251,7 +257,7 @@ pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance...@@ -251,7 +257,7 @@ pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance
251257
252 switch (@typeInfo(T)) {258 switch (@typeInfo(T)) {
253 .Float => if (!math.approxEqRel(T, expected, actual, tolerance)) {259 .Float => if (!math.approxEqRel(T, expected, actual, tolerance)) {
254 std.debug.print("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected });260 print("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected });
255 return error.TestExpectedApproxEqRel;261 return error.TestExpectedApproxEqRel;
256 },262 },
257263
...@@ -294,7 +300,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -294,7 +300,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
294 break :diff_index if (expected.len == actual.len) return else shortest;300 break :diff_index if (expected.len == actual.len) return else shortest;
295 };301 };
296302
297 std.debug.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });303 print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
298304
299 // TODO: Should this be configurable by the caller?305 // TODO: Should this be configurable by the caller?
300 const max_lines: usize = 16;306 const max_lines: usize = 16;
...@@ -329,12 +335,12 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -329,12 +335,12 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
329 // that is usually useful.335 // that is usually useful.
330 const index_fmt = if (T == u8) "0x{X}" else "{}";336 const index_fmt = if (T == u8) "0x{X}" else "{}";
331337
332 std.debug.print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len });338 print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len });
333 if (window_start > 0) {339 if (window_start > 0) {
334 if (T == u8) {340 if (T == u8) {
335 std.debug.print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});341 print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
336 } else {342 } else {
337 std.debug.print("... truncated ...\n", .{});343 print("... truncated ...\n", .{});
338 }344 }
339 }345 }
340 differ.write(stderr.writer()) catch {};346 differ.write(stderr.writer()) catch {};
...@@ -342,21 +348,21 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -342,21 +348,21 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
342 const end_offset = window_start + expected_window.len;348 const end_offset = window_start + expected_window.len;
343 const num_missing_items = expected.len - (window_start + expected_window.len);349 const num_missing_items = expected.len - (window_start + expected_window.len);
344 if (T == u8) {350 if (T == u8) {
345 std.debug.print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });351 print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
346 } else {352 } else {
347 std.debug.print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});353 print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
348 }354 }
349 }355 }
350356
351 // now reverse expected/actual and print again357 // now reverse expected/actual and print again
352 differ.expected = actual_window;358 differ.expected = actual_window;
353 differ.actual = expected_window;359 differ.actual = expected_window;
354 std.debug.print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len });360 print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len });
355 if (window_start > 0) {361 if (window_start > 0) {
356 if (T == u8) {362 if (T == u8) {
357 std.debug.print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});363 print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
358 } else {364 } else {
359 std.debug.print("... truncated ...\n", .{});365 print("... truncated ...\n", .{});
360 }366 }
361 }367 }
362 differ.write(stderr.writer()) catch {};368 differ.write(stderr.writer()) catch {};
...@@ -364,12 +370,12 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const...@@ -364,12 +370,12 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
364 const end_offset = window_start + actual_window.len;370 const end_offset = window_start + actual_window.len;
365 const num_missing_items = actual.len - (window_start + actual_window.len);371 const num_missing_items = actual.len - (window_start + actual_window.len);
366 if (T == u8) {372 if (T == u8) {
367 std.debug.print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });373 print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
368 } else {374 } else {
369 std.debug.print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});375 print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
370 }376 }
371 }377 }
372 std.debug.print("\n================================================\n\n", .{});378 print("\n================================================\n\n", .{});
373379
374 return error.TestExpectedEqual;380 return error.TestExpectedEqual;
375}381}
...@@ -493,12 +499,12 @@ pub fn expectEqualSentinel(comptime T: type, comptime sentinel: T, expected: [:s...@@ -493,12 +499,12 @@ pub fn expectEqualSentinel(comptime T: type, comptime sentinel: T, expected: [:s
493 };499 };
494500
495 if (!std.meta.eql(sentinel, expected_value_sentinel)) {501 if (!std.meta.eql(sentinel, expected_value_sentinel)) {
496 std.debug.print("expectEqualSentinel: 'expected' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, expected_value_sentinel });502 print("expectEqualSentinel: 'expected' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, expected_value_sentinel });
497 return error.TestExpectedEqual;503 return error.TestExpectedEqual;
498 }504 }
499505
500 if (!std.meta.eql(sentinel, actual_value_sentinel)) {506 if (!std.meta.eql(sentinel, actual_value_sentinel)) {
501 std.debug.print("expectEqualSentinel: 'actual' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, actual_value_sentinel });507 print("expectEqualSentinel: 'actual' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, actual_value_sentinel });
502 return error.TestExpectedEqual;508 return error.TestExpectedEqual;
503 }509 }
504}510}
...@@ -697,7 +703,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -697,7 +703,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
697703
698 .Type => {704 .Type => {
699 if (actual != expected) {705 if (actual != expected) {
700 std.debug.print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });706 print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });
701 return error.TestExpectedEqual;707 return error.TestExpectedEqual;
702 }708 }
703 },709 },
...@@ -713,7 +719,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -713,7 +719,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
713 .ErrorSet,719 .ErrorSet,
714 => {720 => {
715 if (actual != expected) {721 if (actual != expected) {
716 std.debug.print("expected {}, found {}\n", .{ expected, actual });722 print("expected {}, found {}\n", .{ expected, actual });
717 return error.TestExpectedEqual;723 return error.TestExpectedEqual;
718 }724 }
719 },725 },
...@@ -723,7 +729,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -723,7 +729,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
723 // We have no idea what is behind those pointers, so the best we can do is `==` check.729 // We have no idea what is behind those pointers, so the best we can do is `==` check.
724 .C, .Many => {730 .C, .Many => {
725 if (actual != expected) {731 if (actual != expected) {
726 std.debug.print("expected {*}, found {*}\n", .{ expected, actual });732 print("expected {*}, found {*}\n", .{ expected, actual });
727 return error.TestExpectedEqual;733 return error.TestExpectedEqual;
728 }734 }
729 },735 },
...@@ -732,7 +738,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -732,7 +738,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
732 switch (@typeInfo(pointer.child)) {738 switch (@typeInfo(pointer.child)) {
733 .Fn, .Opaque => {739 .Fn, .Opaque => {
734 if (actual != expected) {740 if (actual != expected) {
735 std.debug.print("expected {*}, found {*}\n", .{ expected, actual });741 print("expected {*}, found {*}\n", .{ expected, actual });
736 return error.TestExpectedEqual;742 return error.TestExpectedEqual;
737 }743 }
738 },744 },
...@@ -741,13 +747,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -741,13 +747,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
741 },747 },
742 .Slice => {748 .Slice => {
743 if (expected.len != actual.len) {749 if (expected.len != actual.len) {
744 std.debug.print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });750 print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });
745 return error.TestExpectedEqual;751 return error.TestExpectedEqual;
746 }752 }
747 var i: usize = 0;753 var i: usize = 0;
748 while (i < expected.len) : (i += 1) {754 while (i < expected.len) : (i += 1) {
749 expectEqualDeep(expected[i], actual[i]) catch |e| {755 expectEqualDeep(expected[i], actual[i]) catch |e| {
750 std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{756 print("index {d} incorrect. expected {any}, found {any}\n", .{
751 i, expected[i], actual[i],757 i, expected[i], actual[i],
752 });758 });
753 return e;759 return e;
...@@ -759,13 +765,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -759,13 +765,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
759765
760 .Array => |_| {766 .Array => |_| {
761 if (expected.len != actual.len) {767 if (expected.len != actual.len) {
762 std.debug.print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });768 print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });
763 return error.TestExpectedEqual;769 return error.TestExpectedEqual;
764 }770 }
765 var i: usize = 0;771 var i: usize = 0;
766 while (i < expected.len) : (i += 1) {772 while (i < expected.len) : (i += 1) {
767 expectEqualDeep(expected[i], actual[i]) catch |e| {773 expectEqualDeep(expected[i], actual[i]) catch |e| {
768 std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{774 print("index {d} incorrect. expected {any}, found {any}\n", .{
769 i, expected[i], actual[i],775 i, expected[i], actual[i],
770 });776 });
771 return e;777 return e;
...@@ -775,13 +781,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -775,13 +781,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
775781
776 .Vector => |info| {782 .Vector => |info| {
777 if (info.len != @typeInfo(@TypeOf(actual)).Vector.len) {783 if (info.len != @typeInfo(@TypeOf(actual)).Vector.len) {
778 std.debug.print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).Vector.len });784 print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).Vector.len });
779 return error.TestExpectedEqual;785 return error.TestExpectedEqual;
780 }786 }
781 var i: usize = 0;787 var i: usize = 0;
782 while (i < info.len) : (i += 1) {788 while (i < info.len) : (i += 1) {
783 expectEqualDeep(expected[i], actual[i]) catch |e| {789 expectEqualDeep(expected[i], actual[i]) catch |e| {
784 std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{790 print("index {d} incorrect. expected {any}, found {any}\n", .{
785 i, expected[i], actual[i],791 i, expected[i], actual[i],
786 });792 });
787 return e;793 return e;
...@@ -792,7 +798,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -792,7 +798,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
792 .Struct => |structType| {798 .Struct => |structType| {
793 inline for (structType.fields) |field| {799 inline for (structType.fields) |field| {
794 expectEqualDeep(@field(expected, field.name), @field(actual, field.name)) catch |e| {800 expectEqualDeep(@field(expected, field.name), @field(actual, field.name)) catch |e| {
795 std.debug.print("Field {s} incorrect. expected {any}, found {any}\n", .{ field.name, @field(expected, field.name), @field(actual, field.name) });801 print("Field {s} incorrect. expected {any}, found {any}\n", .{ field.name, @field(expected, field.name), @field(actual, field.name) });
796 return e;802 return e;
797 };803 };
798 }804 }
...@@ -823,12 +829,12 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -823,12 +829,12 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
823 if (actual) |actual_payload| {829 if (actual) |actual_payload| {
824 try expectEqualDeep(expected_payload, actual_payload);830 try expectEqualDeep(expected_payload, actual_payload);
825 } else {831 } else {
826 std.debug.print("expected {any}, found null\n", .{expected_payload});832 print("expected {any}, found null\n", .{expected_payload});
827 return error.TestExpectedEqual;833 return error.TestExpectedEqual;
828 }834 }
829 } else {835 } else {
830 if (actual) |actual_payload| {836 if (actual) |actual_payload| {
831 std.debug.print("expected null, found {any}\n", .{actual_payload});837 print("expected null, found {any}\n", .{actual_payload});
832 return error.TestExpectedEqual;838 return error.TestExpectedEqual;
833 }839 }
834 }840 }
...@@ -839,12 +845,12 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {...@@ -839,12 +845,12 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
839 if (actual) |actual_payload| {845 if (actual) |actual_payload| {
840 try expectEqualDeep(expected_payload, actual_payload);846 try expectEqualDeep(expected_payload, actual_payload);
841 } else |actual_err| {847 } else |actual_err| {
842 std.debug.print("expected {any}, found {any}\n", .{ expected_payload, actual_err });848 print("expected {any}, found {any}\n", .{ expected_payload, actual_err });
843 return error.TestExpectedEqual;849 return error.TestExpectedEqual;
844 }850 }
845 } else |expected_err| {851 } else |expected_err| {
846 if (actual) |actual_payload| {852 if (actual) |actual_payload| {
847 std.debug.print("expected {any}, found {any}\n", .{ expected_err, actual_payload });853 print("expected {any}, found {any}\n", .{ expected_err, actual_payload });
848 return error.TestExpectedEqual;854 return error.TestExpectedEqual;
849 } else |actual_err| {855 } else |actual_err| {
850 try expectEqualDeep(expected_err, actual_err);856 try expectEqualDeep(expected_err, actual_err);
src/codegen/spirv.zig+124-56
...@@ -537,6 +537,12 @@ pub const DeclGen = struct {...@@ -537,6 +537,12 @@ pub const DeclGen = struct {
537537
538 fn addInt(self: *@This(), ty: Type, val: Value) !void {538 fn addInt(self: *@This(), ty: Type, val: Value) !void {
539 const mod = self.dg.module;539 const mod = self.dg.module;
540 const len = ty.abiSize(mod);
541 if (val.isUndef(mod)) {
542 try self.addUndef(len);
543 return;
544 }
545
540 const int_info = ty.intInfo(mod);546 const int_info = ty.intInfo(mod);
541 const int_bits = switch (int_info.signedness) {547 const int_bits = switch (int_info.signedness) {
542 .signed => @as(u64, @bitCast(val.toSignedInt(mod))),548 .signed => @as(u64, @bitCast(val.toSignedInt(mod))),
...@@ -544,7 +550,6 @@ pub const DeclGen = struct {...@@ -544,7 +550,6 @@ pub const DeclGen = struct {
544 };550 };
545551
546 // TODO: Swap endianess if the compiler is big endian.552 // TODO: Swap endianess if the compiler is big endian.
547 const len = ty.abiSize(mod);
548 try self.addBytes(std.mem.asBytes(&int_bits)[0..@as(usize, @intCast(len))]);553 try self.addBytes(std.mem.asBytes(&int_bits)[0..@as(usize, @intCast(len))]);
549 }554 }
550555
...@@ -667,31 +672,41 @@ pub const DeclGen = struct {...@@ -667,31 +672,41 @@ pub const DeclGen = struct {
667 try self.addConstInt(u16, @as(u16, @intCast(int)));672 try self.addConstInt(u16, @as(u16, @intCast(int)));
668 },673 },
669 .error_union => |error_union| {674 .error_union => |error_union| {
675 const err_ty = switch (error_union.val) {
676 .err_name => ty.errorUnionSet(mod),
677 .payload => Type.err_int,
678 };
679 const err_val = switch (error_union.val) {
680 .err_name => |err_name| (try mod.intern(.{ .err = .{
681 .ty = ty.errorUnionSet(mod).toIntern(),
682 .name = err_name,
683 } })).toValue(),
684 .payload => try mod.intValue(Type.err_int, 0),
685 };
670 const payload_ty = ty.errorUnionPayload(mod);686 const payload_ty = ty.errorUnionPayload(mod);
671 const is_pl = val.errorUnionIsPayload(mod);
672 const error_val = if (!is_pl) val else try mod.intValue(Type.anyerror, 0);
673
674 const eu_layout = dg.errorUnionLayout(payload_ty);687 const eu_layout = dg.errorUnionLayout(payload_ty);
675 if (!eu_layout.payload_has_bits) {688 if (!eu_layout.payload_has_bits) {
676 return try self.lower(Type.anyerror, error_val);689 // We use the error type directly as the type.
690 try self.lower(err_ty, err_val);
691 return;
677 }692 }
678693
679 const payload_size = payload_ty.abiSize(mod);694 const payload_size = payload_ty.abiSize(mod);
680 const error_size = Type.anyerror.abiAlignment(mod);695 const error_size = err_ty.abiSize(mod);
681 const ty_size = ty.abiSize(mod);696 const ty_size = ty.abiSize(mod);
682 const padding = ty_size - payload_size - error_size;697 const padding = ty_size - payload_size - error_size;
683698
684 const payload_val = switch (error_union.val) {699 const payload_val = switch (error_union.val) {
685 .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }),700 .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
686 .payload => |payload| payload,701 .payload => |payload| payload,
687 }.toValue();702 }.toValue();
688703
689 if (eu_layout.error_first) {704 if (eu_layout.error_first) {
690 try self.lower(Type.anyerror, error_val);705 try self.lower(err_ty, err_val);
691 try self.lower(payload_ty, payload_val);706 try self.lower(payload_ty, payload_val);
692 } else {707 } else {
693 try self.lower(payload_ty, payload_val);708 try self.lower(payload_ty, payload_val);
694 try self.lower(Type.anyerror, error_val);709 try self.lower(err_ty, err_val);
695 }710 }
696711
697 try self.addUndef(padding);712 try self.addUndef(padding);
...@@ -705,9 +720,14 @@ pub const DeclGen = struct {...@@ -705,9 +720,14 @@ pub const DeclGen = struct {
705 },720 },
706 .float => try self.addFloat(ty, val),721 .float => try self.addFloat(ty, val),
707 .ptr => |ptr| {722 .ptr => |ptr| {
723 const ptr_ty = switch (ptr.len) {
724 .none => ty,
725 else => ty.slicePtrFieldType(mod),
726 };
708 switch (ptr.addr) {727 switch (ptr.addr) {
709 .decl => |decl| try self.addDeclRef(ty, decl),728 .decl => |decl| try self.addDeclRef(ptr_ty, decl),
710 .mut_decl => |mut_decl| try self.addDeclRef(ty, mut_decl.decl),729 .mut_decl => |mut_decl| try self.addDeclRef(ptr_ty, mut_decl.decl),
730 .int => |int| try self.addInt(Type.usize, int.toValue()),
711 else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}),731 else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}),
712 }732 }
713 if (ptr.len != .none) {733 if (ptr.len != .none) {
...@@ -979,38 +999,84 @@ pub const DeclGen = struct {...@@ -979,38 +999,84 @@ pub const DeclGen = struct {
979 /// the constant is more complicated however, it needs to be lowered to an indirect constant, which999 /// the constant is more complicated however, it needs to be lowered to an indirect constant, which
980 /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default.1000 /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default.
981 /// This function should only be called during function code generation.1001 /// This function should only be called during function code generation.
982 fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef {1002 fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef {
983 const mod = self.module;1003 const mod = self.module;
984 const target = self.getTarget();1004 const target = self.getTarget();
985 const result_ty_ref = try self.resolveType(ty, repr);1005 const result_ty_ref = try self.resolveType(ty, repr);
9861006
987 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });1007 var val = arg_val;
1008 switch (mod.intern_pool.indexToKey(val.toIntern())) {
1009 .runtime_value => |rt| val = rt.val.toValue(),
1010 else => {},
1011 }
9881012
1013 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
989 if (val.isUndef(mod)) {1014 if (val.isUndef(mod)) {
990 return self.spv.constUndef(result_ty_ref);1015 return self.spv.constUndef(result_ty_ref);
991 }1016 }
9921017
993 switch (ty.zigTypeTag(mod)) {1018 switch (mod.intern_pool.indexToKey(val.toIntern())) {
994 .Int => {1019 .int_type,
1020 .ptr_type,
1021 .array_type,
1022 .vector_type,
1023 .opt_type,
1024 .anyframe_type,
1025 .error_union_type,
1026 .simple_type,
1027 .struct_type,
1028 .anon_struct_type,
1029 .union_type,
1030 .opaque_type,
1031 .enum_type,
1032 .func_type,
1033 .error_set_type,
1034 .inferred_error_set_type,
1035 => unreachable, // types, not values
1036
1037 .undef => unreachable, // handled above
1038 .runtime_value => unreachable, // ???
1039
1040 .variable,
1041 .extern_func,
1042 .func,
1043 .enum_literal,
1044 .empty_enum_value,
1045 => unreachable, // non-runtime values
1046
1047 .simple_value => |simple_value| switch (simple_value) {
1048 .undefined,
1049 .void,
1050 .null,
1051 .empty_struct,
1052 .@"unreachable",
1053 .generic_poison,
1054 => unreachable, // non-runtime values
1055
1056 .false, .true => switch (repr) {
1057 .direct => return try self.spv.constBool(result_ty_ref, val.toBool()),
1058 .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())),
1059 },
1060 },
1061
1062 .int => {
995 if (ty.isSignedInt(mod)) {1063 if (ty.isSignedInt(mod)) {
996 return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod));1064 return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod));
997 } else {1065 } else {
998 return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod));1066 return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod));
999 }1067 }
1000 },1068 },
1001 .Bool => switch (repr) {1069 .float => return switch (ty.floatBits(target)) {
1002 .direct => return try self.spv.constBool(result_ty_ref, val.toBool()),
1003 .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())),
1004 },
1005 .Float => return switch (ty.floatBits(target)) {
1006 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }),1070 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }),
1007 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }),1071 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }),
1008 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }),1072 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }),
1009 80, 128 => unreachable, // TODO1073 80, 128 => unreachable, // TODO
1010 else => unreachable,1074 else => unreachable,
1011 },1075 },
1012 .ErrorSet => @panic("TODO"),1076 .err => |err| {
1013 .ErrorUnion => @panic("TODO"),1077 const value = try mod.getErrorValue(err.name);
1078 return try self.spv.constInt(result_ty_ref, value);
1079 },
1014 // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra1080 // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra
1015 // OpVariable that is not really required.1081 // OpVariable that is not really required.
1016 else => {1082 else => {
...@@ -1263,51 +1329,53 @@ pub const DeclGen = struct {...@@ -1263,51 +1329,53 @@ pub const DeclGen = struct {
1263 } });1329 } });
1264 },1330 },
1265 .Struct => {1331 .Struct => {
1266 const struct_ty = mod.typeToStruct(ty).?;1332 const struct_ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1267 const fields = struct_ty.fields.values();1333 .anon_struct_type => |tuple| {
12681334 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);
1269 if (ty.isSimpleTupleOrAnonStruct(mod)) {1335 defer self.gpa.free(member_types);
1270 const member_types = try self.gpa.alloc(CacheRef, fields.len);
1271 defer self.gpa.free(member_types);
12721336
1273 var member_index: usize = 0;1337 var member_index: usize = 0;
1274 for (fields) |field| {1338 for (tuple.types, tuple.values) |field_ty, field_val| {
1275 if (field.ty.ip_index != .unreachable_value or !field.ty.hasRuntimeBits(mod)) continue;1339 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
12761340
1277 member_types[member_index] = try self.resolveType(field.ty, .indirect);1341 member_types[member_index] = try self.resolveType(field_ty.toType(), .indirect);
1278 member_index += 1;1342 member_index += 1;
1279 }1343 }
12801344
1281 return try self.spv.resolve(.{ .struct_type = .{1345 return try self.spv.resolve(.{ .struct_type = .{
1282 .member_types = member_types[0..member_index],1346 .member_types = member_types[0..member_index],
1283 } });1347 } });
1284 }1348 },
1349 .struct_type => |struct_ty| struct_ty,
1350 else => unreachable,
1351 };
12851352
1286 if (struct_ty.layout == .Packed) {1353 const struct_obj = mod.structPtrUnwrap(struct_ty.index).?;
1287 return try self.resolveType(struct_ty.backing_int_ty, .direct);1354 if (struct_obj.layout == .Packed) {
1355 return try self.resolveType(struct_obj.backing_int_ty, .direct);
1288 }1356 }
12891357
1290 const member_types = try self.gpa.alloc(CacheRef, fields.len);1358 var member_types = std.ArrayList(CacheRef).init(self.gpa);
1291 defer self.gpa.free(member_types);1359 defer member_types.deinit();
1292
1293 const member_names = try self.gpa.alloc(CacheString, fields.len);
1294 defer self.gpa.free(member_names);
12951360
1296 var member_index: usize = 0;1361 var member_names = std.ArrayList(CacheString).init(self.gpa);
1297 for (fields, 0..) |field, i| {1362 defer member_names.deinit();
1298 if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;
12991363
1300 member_types[member_index] = try self.resolveType(field.ty, .indirect);1364 var it = struct_obj.runtimeFieldIterator(mod);
1301 member_names[member_index] = try self.spv.resolveString(mod.intern_pool.stringToSlice(struct_ty.fields.keys()[i]));1365 while (it.next()) |field_and_index| {
1302 member_index += 1;1366 const field = field_and_index.field;
1367 const index = field_and_index.index;
1368 const field_name = mod.intern_pool.stringToSlice(struct_obj.fields.keys()[index]);
1369 try member_types.append(try self.resolveType(field.ty, .indirect));
1370 try member_names.append(try self.spv.resolveString(field_name));
1303 }1371 }
13041372
1305 const name = mod.intern_pool.stringToSlice(try struct_ty.getFullyQualifiedName(self.module));1373 const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module));
13061374
1307 return try self.spv.resolve(.{ .struct_type = .{1375 return try self.spv.resolve(.{ .struct_type = .{
1308 .name = try self.spv.resolveString(name),1376 .name = try self.spv.resolveString(name),
1309 .member_types = member_types[0..member_index],1377 .member_types = member_types.items,
1310 .member_names = member_names[0..member_index],1378 .member_names = member_names.items,
1311 } });1379 } });
1312 },1380 },
1313 .Optional => {1381 .Optional => {
...@@ -2512,9 +2580,9 @@ pub const DeclGen = struct {...@@ -2512,9 +2580,9 @@ pub const DeclGen = struct {
2512 // just an element.2580 // just an element.
2513 var elem_ptr_info = ptr_ty.ptrInfo(mod);2581 var elem_ptr_info = ptr_ty.ptrInfo(mod);
2514 elem_ptr_info.flags.size = .One;2582 elem_ptr_info.flags.size = .One;
2515 const elem_ptr_ty = elem_ptr_info.child.toType();2583 const elem_ptr_ty = try mod.intern_pool.get(mod.gpa, .{ .ptr_type = elem_ptr_info });
25162584
2517 return try self.load(elem_ptr_ty, elem_ptr_id);2585 return try self.load(elem_ptr_ty.toType(), elem_ptr_id);
2518 }2586 }
25192587
2520 fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2588 fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
test/behavior/c_char_signedness.zig+3
...@@ -1,10 +1,13 @@...@@ -1,10 +1,13 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const expectEqual = std.testing.expectEqual;3const expectEqual = std.testing.expectEqual;
3const c = @cImport({4const c = @cImport({
4 @cInclude("limits.h");5 @cInclude("limits.h");
5});6});
67
7test "c_char signedness" {8test "c_char signedness" {
9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10
8 try expectEqual(@as(c_char, c.CHAR_MIN), std.math.minInt(c_char));11 try expectEqual(@as(c_char, c.CHAR_MIN), std.math.minInt(c_char));
9 try expectEqual(@as(c_char, c.CHAR_MAX), std.math.maxInt(c_char));12 try expectEqual(@as(c_char, c.CHAR_MAX), std.math.maxInt(c_char));
10}13}
test/behavior/call.zig+2
...@@ -417,6 +417,8 @@ test "inline while with @call" {...@@ -417,6 +417,8 @@ test "inline while with @call" {
417}417}
418418
419test "method call as parameter type" {419test "method call as parameter type" {
420 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
421
420 const S = struct {422 const S = struct {
421 fn foo(x: anytype, y: @TypeOf(x).Inner()) @TypeOf(y) {423 fn foo(x: anytype, y: @TypeOf(x).Inner()) @TypeOf(y) {
422 return y;424 return y;
test/behavior/comptime_memory.zig+2
...@@ -433,6 +433,8 @@ test "dereference undefined pointer to zero-bit type" {...@@ -433,6 +433,8 @@ test "dereference undefined pointer to zero-bit type" {
433}433}
434434
435test "type pun extern struct" {435test "type pun extern struct" {
436 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
437
436 const S = extern struct { f: u8 };438 const S = extern struct { f: u8 };
437 comptime var s = S{ .f = 123 };439 comptime var s = S{ .f = 123 };
438 @as(*u8, @ptrCast(&s)).* = 72;440 @as(*u8, @ptrCast(&s)).* = 72;
test/behavior/enum.zig+2
...@@ -1199,6 +1199,8 @@ test "enum tag from a local variable" {...@@ -1199,6 +1199,8 @@ test "enum tag from a local variable" {
1199}1199}
12001200
1201test "auto-numbered enum with signed tag type" {1201test "auto-numbered enum with signed tag type" {
1202 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1203
1202 const E = enum(i32) { a, b };1204 const E = enum(i32) { a, b };
12031205
1204 try std.testing.expectEqual(@as(i32, 0), @intFromEnum(E.a));1206 try std.testing.expectEqual(@as(i32, 0), @intFromEnum(E.a));
test/behavior/maximum_minimum.zig+2
...@@ -297,6 +297,8 @@ test "@min/@max notices bounds from vector types when element of comptime-known...@@ -297,6 +297,8 @@ test "@min/@max notices bounds from vector types when element of comptime-known
297}297}
298298
299test "@min/@max of signed and unsigned runtime integers" {299test "@min/@max of signed and unsigned runtime integers" {
300 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
301
300 var x: i32 = -1;302 var x: i32 = -1;
301 var y: u31 = 1;303 var y: u31 = 1;
302304
test/behavior/ptrfromint.zig+2
...@@ -33,6 +33,7 @@ test "@ptrFromInt creates null pointer" {...@@ -33,6 +33,7 @@ test "@ptrFromInt creates null pointer" {
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
3637
37 const ptr = @as(?*u32, @ptrFromInt(0));38 const ptr = @as(?*u32, @ptrFromInt(0));
38 try expectEqual(@as(?*u32, null), ptr);39 try expectEqual(@as(?*u32, null), ptr);
...@@ -42,6 +43,7 @@ test "@ptrFromInt creates allowzero zero pointer" {...@@ -42,6 +43,7 @@ test "@ptrFromInt creates allowzero zero pointer" {
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;43 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;44 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
44 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
4547
46 const ptr = @as(*allowzero u32, @ptrFromInt(0));48 const ptr = @as(*allowzero u32, @ptrFromInt(0));
47 try expectEqual(@as(usize, 0), @intFromPtr(ptr));49 try expectEqual(@as(usize, 0), @intFromPtr(ptr));