master
  1const std = @import("std");
  2const builtin = @import("builtin");
  3const expect = std.testing.expect;
  4const assert = std.debug.assert;
  5const native_endian = builtin.target.cpu.arch.endian();
  6
  7test "reinterpret bytes as integer with nonzero offset" {
  8    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
  9
 10    try testReinterpretBytesAsInteger();
 11    try comptime testReinterpretBytesAsInteger();
 12}
 13
 14fn testReinterpretBytesAsInteger() !void {
 15    const bytes = "\x12\x34\x56\x78\xab";
 16    const expected = switch (native_endian) {
 17        .little => 0xab785634,
 18        .big => 0x345678ab,
 19    };
 20    try expect(@as(*align(1) const u32, @ptrCast(bytes[1..5])).* == expected);
 21}
 22
 23test "reinterpret an array over multiple elements, with no well-defined layout" {
 24    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 25    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 26    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 27
 28    try testReinterpretWithOffsetAndNoWellDefinedLayout();
 29    try comptime testReinterpretWithOffsetAndNoWellDefinedLayout();
 30}
 31
 32fn testReinterpretWithOffsetAndNoWellDefinedLayout() !void {
 33    const bytes: ?[5]?u8 = [5]?u8{ 0x12, 0x34, 0x56, 0x78, 0x9a };
 34    const ptr = &bytes.?[1];
 35    const copy: [4]?u8 = @as(*const [4]?u8, @ptrCast(ptr)).*;
 36    _ = copy;
 37    //try expect(@ptrCast(*align(1)?u8, bytes[1..5]).* == );
 38}
 39
 40test "reinterpret bytes inside auto-layout struct as integer with nonzero offset" {
 41    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 42
 43    try testReinterpretStructWrappedBytesAsInteger();
 44    try comptime testReinterpretStructWrappedBytesAsInteger();
 45}
 46
 47fn testReinterpretStructWrappedBytesAsInteger() !void {
 48    const S = struct { bytes: [5:0]u8 };
 49    const obj = S{ .bytes = "\x12\x34\x56\x78\xab".* };
 50    const expected = switch (native_endian) {
 51        .little => 0xab785634,
 52        .big => 0x345678ab,
 53    };
 54    try expect(@as(*align(1) const u32, @ptrCast(obj.bytes[1..5])).* == expected);
 55}
 56
 57test "reinterpret bytes of an array into an extern struct" {
 58    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 59    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 60
 61    try testReinterpretBytesAsExternStruct();
 62    try comptime testReinterpretBytesAsExternStruct();
 63}
 64
 65fn testReinterpretBytesAsExternStruct() !void {
 66    var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 };
 67
 68    const S = extern struct {
 69        a: u8,
 70        b: u16,
 71        c: u8,
 72    };
 73
 74    const ptr: *const S = @ptrCast(&bytes);
 75    const val = ptr.c;
 76    try expect(val == 5);
 77}
 78
 79test "reinterpret bytes of an extern struct (with under-aligned fields) into another" {
 80    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 81
 82    try testReinterpretExternStructAsExternStruct();
 83    try comptime testReinterpretExternStructAsExternStruct();
 84}
 85
 86fn testReinterpretExternStructAsExternStruct() !void {
 87    const S1 = extern struct {
 88        a: u8,
 89        b: u16,
 90        c: u8,
 91    };
 92    comptime var bytes align(2) = S1{ .a = 0, .b = 0, .c = 5 };
 93
 94    const S2 = extern struct {
 95        a: u32 align(2),
 96        c: u8,
 97    };
 98    const ptr: *const S2 = @ptrCast(&bytes);
 99    const val = ptr.c;
100    try expect(val == 5);
101}
102
103test "reinterpret bytes of an extern struct into another" {
104    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
105
106    try testReinterpretOverAlignedExternStructAsExternStruct();
107    try comptime testReinterpretOverAlignedExternStructAsExternStruct();
108}
109
110fn testReinterpretOverAlignedExternStructAsExternStruct() !void {
111    const S1 = extern struct {
112        a: u32,
113        b: u32,
114        c: u8,
115    };
116    comptime var bytes: S1 = .{ .a = 0, .b = 0, .c = 5 };
117
118    const S2 = extern struct {
119        a0: u32,
120        a1: u16,
121        a2: u16,
122        c: u8,
123    };
124    const ptr: *const S2 = @ptrCast(&bytes);
125    const val = ptr.c;
126    try expect(val == 5);
127}
128
129test "lower reinterpreted comptime field ptr (with under-aligned fields)" {
130    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
131    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132
133    // Test lowering a field ptr
134    comptime var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 };
135    const S = extern struct {
136        a: u32 align(2),
137        c: u8,
138    };
139    comptime var ptr = @as(*const S, @ptrCast(&bytes));
140    const val = &ptr.c;
141    try expect(val.* == 5);
142
143    // Test lowering an elem ptr
144    comptime var src_value = S{ .a = 15, .c = 5 };
145    comptime var ptr2 = @as(*[@sizeOf(S)]u8, @ptrCast(&src_value));
146    const val2 = &ptr2[4];
147    try expect(val2.* == 5);
148}
149
150test "lower reinterpreted comptime field ptr" {
151    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
152    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
153
154    // Test lowering a field ptr
155    comptime var bytes align(4) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
156    const S = extern struct {
157        a: u32,
158        c: u8,
159    };
160    comptime var ptr = @as(*const S, @ptrCast(&bytes));
161    const val = &ptr.c;
162    try expect(val.* == 5);
163
164    // Test lowering an elem ptr
165    comptime var src_value = S{ .a = 15, .c = 5 };
166    comptime var ptr2 = @as(*[@sizeOf(S)]u8, @ptrCast(&src_value));
167    const val2 = &ptr2[4];
168    try expect(val2.* == 5);
169}
170
171test "reinterpret struct field at comptime" {
172    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
173    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
174
175    const numNative = comptime Bytes.init(0x12345678);
176    if (native_endian != .little) {
177        try expect(std.mem.eql(u8, &[_]u8{ 0x12, 0x34, 0x56, 0x78 }, &numNative.bytes));
178    } else {
179        try expect(std.mem.eql(u8, &[_]u8{ 0x78, 0x56, 0x34, 0x12 }, &numNative.bytes));
180    }
181}
182
183const Bytes = struct {
184    bytes: [4]u8,
185
186    pub fn init(v: u32) Bytes {
187        var res: Bytes = undefined;
188        @as(*align(1) u32, @ptrCast(&res.bytes)).* = v;
189
190        return res;
191    }
192};
193
194test "ptrcast of const integer has the correct object size" {
195    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
196
197    const is_value = ~@as(isize, @intCast(std.math.minInt(isize)));
198    const is_bytes = @as([*]const u8, @ptrCast(&is_value))[0..@sizeOf(isize)];
199    if (@sizeOf(isize) == 8) {
200        switch (native_endian) {
201            .little => {
202                try expect(is_bytes[0] == 0xff);
203                try expect(is_bytes[1] == 0xff);
204                try expect(is_bytes[2] == 0xff);
205                try expect(is_bytes[3] == 0xff);
206
207                try expect(is_bytes[4] == 0xff);
208                try expect(is_bytes[5] == 0xff);
209                try expect(is_bytes[6] == 0xff);
210                try expect(is_bytes[7] == 0x7f);
211            },
212            .big => {
213                try expect(is_bytes[0] == 0x7f);
214                try expect(is_bytes[1] == 0xff);
215                try expect(is_bytes[2] == 0xff);
216                try expect(is_bytes[3] == 0xff);
217
218                try expect(is_bytes[4] == 0xff);
219                try expect(is_bytes[5] == 0xff);
220                try expect(is_bytes[6] == 0xff);
221                try expect(is_bytes[7] == 0xff);
222            },
223        }
224    }
225}
226
227test "implicit optional pointer to optional anyopaque pointer" {
228    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
229    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
230    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
231
232    var buf: [4]u8 = "aoeu".*;
233    const x: ?[*]u8 = &buf;
234    const y: ?*anyopaque = x;
235    const z: *[4]u8 = @ptrCast(y);
236    try expect(std.mem.eql(u8, z, "aoeu"));
237}
238
239test "@ptrCast slice to slice" {
240    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
241    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
242    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
243
244    const S = struct {
245        fn foo(slice: []u32) []i32 {
246            return @as([]i32, @ptrCast(slice));
247        }
248    };
249    var buf: [4]u32 = .{ 0, 0, 0, 0 };
250    const alias = S.foo(&buf);
251    alias[1] = 42;
252    try expect(buf[1] == 42);
253    try expect(alias.len == 4);
254}
255
256test "comptime @ptrCast a subset of an array, then write through it" {
257    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
258    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
259
260    comptime {
261        var buff: [16]u8 align(4) = undefined;
262        const len_bytes = @as(*u32, @ptrCast(&buff));
263        len_bytes.* = 16;
264        const source = "abcdef";
265        @memcpy(buff[4 .. 4 + source.len], source);
266    }
267}
268
269test "@ptrCast undefined value at comptime" {
270    const S = struct {
271        fn transmute(comptime T: type, comptime U: type, value: T) U {
272            return @as(*const U, @ptrCast(&value)).*;
273        }
274    };
275    comptime {
276        const x = S.transmute(u64, i32, undefined);
277        _ = x;
278    }
279}
280
281test "comptime @ptrCast with packed struct leaves value unmodified" {
282    const S = packed struct { three: u3 };
283    const st: S = .{ .three = 6 };
284    try expect(st.three == 6);
285    const p: *const [1]u3 = @ptrCast(&st);
286    try expect(p.*[0] == 6);
287    try expect(st.three == 6);
288}
289
290test "@ptrCast restructures comptime-only array" {
291    {
292        const a3a2: [3][2]comptime_int = .{
293            .{ 1, 2 },
294            .{ 3, 4 },
295            .{ 5, 6 },
296        };
297        const a2a3: *const [2][3]comptime_int = @ptrCast(&a3a2);
298        comptime assert(a2a3[0][0] == 1);
299        comptime assert(a2a3[0][1] == 2);
300        comptime assert(a2a3[0][2] == 3);
301        comptime assert(a2a3[1][0] == 4);
302        comptime assert(a2a3[1][1] == 5);
303        comptime assert(a2a3[1][2] == 6);
304    }
305
306    {
307        const a6a1: [6][1]comptime_int = .{
308            .{1}, .{2}, .{3}, .{4}, .{5}, .{6},
309        };
310        const a1a2a3: *const [1][2][3]comptime_int = @ptrCast(&a6a1);
311        comptime assert(a1a2a3[0][0][0] == 1);
312        comptime assert(a1a2a3[0][0][1] == 2);
313        comptime assert(a1a2a3[0][0][2] == 3);
314        comptime assert(a1a2a3[0][1][0] == 4);
315        comptime assert(a1a2a3[0][1][1] == 5);
316        comptime assert(a1a2a3[0][1][2] == 6);
317    }
318
319    {
320        const a1: [1]comptime_int = .{123};
321        const raw: *const comptime_int = @ptrCast(&a1);
322        comptime assert(raw.* == 123);
323    }
324
325    {
326        const raw: comptime_int = 123;
327        const a1: *const [1]comptime_int = @ptrCast(&raw);
328        comptime assert(a1[0] == 123);
329    }
330}
331
332test "@ptrCast restructures sliced comptime-only array" {
333    const a3a2: [4][2]comptime_int = .{
334        .{ 1, 2 },
335        .{ 3, 4 },
336        .{ 5, 6 },
337        .{ 7, 8 },
338    };
339
340    const sub: *const [4]comptime_int = @ptrCast(a3a2[1..]);
341    comptime assert(sub[0] == 3);
342    comptime assert(sub[1] == 4);
343    comptime assert(sub[2] == 5);
344    comptime assert(sub[3] == 6);
345}
346
347test "@ptrCast slice multiplying length" {
348    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
349    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
351
352    const S = struct {
353        fn doTheTest(zero: u32) !void {
354            const in: []const u32 = &.{ zero, zero };
355            const out: []const u8 = @ptrCast(in);
356            try expect(out.len == 8);
357            try expect(@as([*]const u8, @ptrCast(in.ptr)) == out.ptr);
358        }
359    };
360    try S.doTheTest(0);
361    try comptime S.doTheTest(0);
362}
363
364test "@ptrCast array pointer to slice multiplying length" {
365    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
366    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
367    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
368
369    const S = struct {
370        fn doTheTest(zero: u32) !void {
371            const in: *const [2]u32 = &.{ zero, zero };
372            const out: []const u8 = @ptrCast(in);
373            try expect(out.len == 8);
374            try expect(out.ptr == @as([*]const u8, @ptrCast(in.ptr)));
375        }
376    };
377    try S.doTheTest(0);
378    try comptime S.doTheTest(0);
379}
380
381test "@ptrCast slice dividing length" {
382    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
383    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
384    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
385
386    const S = struct {
387        fn doTheTest(zero: u8) !void {
388            const in: []const u8 = &.{ zero, zero, zero, zero, zero, zero, zero, zero };
389            const out: []align(1) const u32 = @ptrCast(in);
390            try expect(out.len == 2);
391            try expect(out.ptr == @as([*]align(1) const u32, @ptrCast(in.ptr)));
392        }
393    };
394    try S.doTheTest(0);
395    try comptime S.doTheTest(0);
396}
397
398test "@ptrCast array pointer to slice dividing length" {
399    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
400    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
401    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
402
403    const S = struct {
404        fn doTheTest(zero: u8) !void {
405            const in: *const [8]u8 = &.{ zero, zero, zero, zero, zero, zero, zero, zero };
406            const out: []align(1) const u32 = @ptrCast(in);
407            try expect(out.len == 2);
408            try expect(out.ptr == @as([*]align(1) const u32, @ptrCast(in.ptr)));
409        }
410    };
411    try S.doTheTest(0);
412    try comptime S.doTheTest(0);
413}
414
415test "@ptrCast slice with complex length increase" {
416    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
417    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
418    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
419
420    const TwoBytes = [2]u8;
421    const ThreeBytes = [3]u8;
422
423    const S = struct {
424        fn doTheTest(zero: ThreeBytes) !void {
425            const in: []const ThreeBytes = &.{ zero, zero };
426            const out: []const TwoBytes = @ptrCast(in);
427            try expect(out.len == 3);
428            try expect(out.ptr == @as([*]const TwoBytes, @ptrCast(in.ptr)));
429        }
430    };
431    try S.doTheTest(@splat(0));
432    try comptime S.doTheTest(@splat(0));
433}
434
435test "@ptrCast array pointer to slice with complex length increase" {
436    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
437    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
438    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
439
440    const TwoBytes = [2]u8;
441    const ThreeBytes = [3]u8;
442
443    const S = struct {
444        fn doTheTest(zero: ThreeBytes) !void {
445            const in: *const [2]ThreeBytes = &.{ zero, zero };
446            const out: []const TwoBytes = @ptrCast(in);
447            try expect(out.len == 3);
448            try expect(out.ptr == @as([*]const TwoBytes, @ptrCast(in.ptr)));
449        }
450    };
451    try S.doTheTest(@splat(0));
452    try comptime S.doTheTest(@splat(0));
453}
454
455test "@ptrCast slice with complex length decrease" {
456    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
457    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
458    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
459
460    const TwoBytes = [2]u8;
461    const ThreeBytes = [3]u8;
462
463    const S = struct {
464        fn doTheTest(zero: TwoBytes) !void {
465            const in: []const TwoBytes = &.{ zero, zero, zero };
466            const out: []const ThreeBytes = @ptrCast(in);
467            try expect(out.len == 2);
468            try expect(out.ptr == @as([*]const ThreeBytes, @ptrCast(in.ptr)));
469        }
470    };
471    try S.doTheTest(@splat(0));
472    try comptime S.doTheTest(@splat(0));
473}
474
475test "@ptrCast array pointer to slice with complex length decrease" {
476    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
477    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
478    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
479
480    const TwoBytes = [2]u8;
481    const ThreeBytes = [3]u8;
482
483    const S = struct {
484        fn doTheTest(zero: TwoBytes) !void {
485            const in: *const [3]TwoBytes = &.{ zero, zero, zero };
486            const out: []const ThreeBytes = @ptrCast(in);
487            try expect(out.len == 2);
488            try expect(out.ptr == @as([*]const ThreeBytes, @ptrCast(in.ptr)));
489        }
490    };
491    try S.doTheTest(@splat(0));
492    try comptime S.doTheTest(@splat(0));
493}
494
495test "@ptrCast slice of zero-bit type to different slice" {
496    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
497    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
498    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
499
500    const S = struct {
501        fn doTheTest(comptime T: type, zero_bits: []const T) !void {
502            const out: []const u8 = @ptrCast(zero_bits);
503            try expect(out.len == 0);
504        }
505    };
506    try S.doTheTest(void, &.{ {}, {}, {} });
507    try S.doTheTest(u0, &.{ 0, 0, 0, 0 });
508    try S.doTheTest(packed struct(u0) {}, &.{ .{}, .{} });
509    try comptime S.doTheTest(void, &.{ {}, {}, {} });
510    try comptime S.doTheTest(u0, &.{ 0, 0, 0, 0 });
511    try comptime S.doTheTest(packed struct(u0) {}, &.{ .{}, .{} });
512}
513
514test "@ptrCast single-item pointer to slice with length 1" {
515    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
516    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
517    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
518    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
519
520    const S = struct {
521        fn doTheTest(comptime T: type, ptr: *const T) !void {
522            const slice: []const T = @ptrCast(ptr);
523            try expect(slice.len == 1);
524            try expect(&slice[0] == ptr);
525        }
526    };
527    try S.doTheTest(u8, &123);
528    try S.doTheTest(void, &{});
529    try S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
530    try comptime S.doTheTest(u8, &123);
531    try comptime S.doTheTest(void, &{});
532    try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
533}
534
535test "@ptrCast single-item pointer to slice of bytes" {
536    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
537    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
538    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
539    if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
540
541    const S = struct {
542        fn doTheTest(comptime T: type, ptr: *const T) !void {
543            const slice: []const u8 = @ptrCast(ptr);
544            try expect(slice.len == @sizeOf(T));
545            try expect(slice.ptr == @as([*]const u8, @ptrCast(ptr)));
546        }
547    };
548    try S.doTheTest(u16, &123);
549    try S.doTheTest(void, &{});
550    try S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
551    try comptime S.doTheTest(u16, &123);
552    try comptime S.doTheTest(void, &{});
553    try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
554}
555
556test "@ptrCast array pointer removing sentinel" {
557    const in: *const [4:0]u8 = &.{ 1, 2, 3, 4 };
558    const out: []const i8 = @ptrCast(in);
559    comptime assert(out.len == 4);
560    comptime assert(out[0] == 1);
561    comptime assert(out[1] == 2);
562    comptime assert(out[2] == 3);
563    comptime assert(out[3] == 4);
564}