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}