master
1const builtin = @import("builtin");
2const std = @import("std");
3const testing = std.testing;
4const assert = std.debug.assert;
5const expect = testing.expect;
6const expectError = testing.expectError;
7
8test "dereference pointer" {
9 try comptime testDerefPtr();
10 try testDerefPtr();
11}
12
13fn testDerefPtr() !void {
14 var x: i32 = 1234;
15 const y = &x;
16 y.* += 1;
17 try expect(x == 1235);
18}
19
20test "pointer-integer arithmetic" {
21 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
24
25 var ptr: [*]const u8 = "abcd";
26
27 try expect(ptr[0] == 'a');
28 ptr += 1;
29 try expect(ptr[0] == 'b');
30 ptr += 1;
31 try expect(ptr[0] == 'c');
32 ptr += 1;
33 try expect(ptr[0] == 'd');
34 ptr += 1;
35 try expect(ptr[0] == 0);
36 ptr -= 1;
37 try expect(ptr[0] == 'd');
38 ptr -= 1;
39 try expect(ptr[0] == 'c');
40 ptr -= 1;
41 try expect(ptr[0] == 'b');
42 ptr -= 1;
43 try expect(ptr[0] == 'a');
44}
45
46test "pointer subtraction" {
47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
49
50 {
51 const a: *u8 = @ptrFromInt(100);
52 const b: *u8 = @ptrFromInt(50);
53 try expect(a - b == 50);
54 }
55 {
56 var ptr: [*]const u8 = "abc";
57 try expect(&ptr[1] - &ptr[0] == 1);
58 try expect(&ptr[2] - &ptr[0] == 2);
59 }
60 {
61 const a: *[100]u16 = @ptrFromInt(100);
62 const b: *[100]u16 = @ptrFromInt(50);
63 try expect(a - b == 25);
64 }
65 {
66 var x: struct { a: u32, b: u32 } = undefined;
67 const a = &x.a;
68 const b = &x.b;
69 try expect(a - a == 0);
70 try expect(b - b == 0);
71 try expect(b - a == 1);
72 }
73 comptime {
74 var x: packed struct { a: u1, b: u1 } = undefined;
75 const a = &x.a;
76 const b = &x.b;
77 try expect(a - a == 0);
78 try expect(b - b == 0);
79 try expect(b - a == 0);
80 }
81 comptime {
82 var x: extern struct { a: u32, b: u32 } = undefined;
83 const a = &x.a;
84 const b = &x.b;
85 try expect(a - a == 0);
86 try expect(b - b == 0);
87 try expect(b - a == 1);
88 }
89 comptime {
90 const a: *const [3]u8 = "abc";
91 const b: [*]const u8 = @ptrCast(a);
92 try expect(&a[1] - &b[0] == 1);
93 }
94 comptime {
95 var x: [64][64]u8 = undefined;
96 const a = &x[0][12];
97 const b = &x[15][3];
98 try expect(b - a == 951);
99 }
100}
101
102test "pointer arithmetic with non-trivial RHS" {
103 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
104
105 var t: bool = undefined;
106 t = true;
107
108 var ptr: [*]const u8 = "Hello, World!";
109 ptr += if (t) 5 else 2;
110 try expect(ptr[0] == ',');
111 ptr += if (!t) 4 else 2;
112 try expect(ptr[0] == 'W');
113 ptr -= if (t) @as(usize, 6) else 3;
114 try expect(ptr[0] == 'e');
115 ptr -= if (!t) @as(usize, 0) else 1;
116 try expect(ptr[0] == 'H');
117}
118
119test "double pointer parsing" {
120 comptime assert(PtrOf(PtrOf(i32)) == **i32);
121}
122
123fn PtrOf(comptime T: type) type {
124 return *T;
125}
126
127test "implicit cast single item pointer to C pointer and back" {
128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
130
131 var y: u8 = 11;
132 const x: [*c]u8 = &y;
133 const z: *u8 = x;
134 z.* += 1;
135 try expect(y == 12);
136}
137
138test "initialize const optional C pointer to null" {
139 const a: ?[*c]i32 = null;
140 try expect(a == null);
141 comptime assert(a == null);
142}
143
144test "assigning integer to C pointer" {
145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
147
148 var x: i32 = 0;
149 var y: i32 = 1;
150 var ptr: [*c]u8 = 0;
151 var ptr2: [*c]u8 = x;
152 var ptr3: [*c]u8 = 1;
153 var ptr4: [*c]u8 = y;
154 _ = .{ &x, &y, &ptr, &ptr2, &ptr3, &ptr4 };
155
156 try expect(ptr == ptr2);
157 try expect(ptr3 == ptr4);
158 try expect(ptr3 > ptr and ptr4 > ptr2 and y > x);
159 try expect(1 > ptr and y > ptr2 and 0 < ptr3 and x < ptr4);
160}
161
162test "C pointer comparison and arithmetic" {
163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
165
166 const S = struct {
167 fn doTheTest() !void {
168 var ptr1: [*c]u32 = 0;
169 var ptr2 = ptr1 + 10;
170 _ = &ptr1;
171 try expect(ptr1 == 0);
172 try expect(ptr1 >= 0);
173 try expect(ptr1 <= 0);
174 // expect(ptr1 < 1);
175 // expect(ptr1 < one);
176 // expect(1 > ptr1);
177 // expect(one > ptr1);
178 try expect(ptr1 < ptr2);
179 try expect(ptr2 > ptr1);
180 try expect(ptr2 >= 40);
181 try expect(ptr2 == 40);
182 try expect(ptr2 <= 40);
183 ptr2 -= 10;
184 try expect(ptr1 == ptr2);
185 }
186 };
187 try S.doTheTest();
188 try comptime S.doTheTest();
189}
190
191test "dereference pointer again" {
192 try testDerefPtrOneVal();
193 try comptime testDerefPtrOneVal();
194}
195
196const Foo1 = struct {
197 x: void,
198};
199
200fn testDerefPtrOneVal() !void {
201 // Foo1 satisfies the OnePossibleValueYes criteria
202 const x = &Foo1{ .x = {} };
203 const y = x.*;
204 try expect(@TypeOf(y.x) == void);
205}
206
207test "peer type resolution with C pointers" {
208 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
209
210 const ptr_one: *u8 = undefined;
211 const ptr_many: [*]u8 = undefined;
212 const ptr_c: [*c]u8 = undefined;
213 var t = true;
214 _ = &t;
215 const x1 = if (t) ptr_one else ptr_c;
216 const x2 = if (t) ptr_many else ptr_c;
217 const x3 = if (t) ptr_c else ptr_one;
218 const x4 = if (t) ptr_c else ptr_many;
219 try expect(@TypeOf(x1) == [*c]u8);
220 try expect(@TypeOf(x2) == [*c]u8);
221 try expect(@TypeOf(x3) == [*c]u8);
222 try expect(@TypeOf(x4) == [*c]u8);
223}
224
225test "peer type resolution with C pointer and const pointer" {
226 var ptr_c: [*c]u8 = undefined;
227 var ptr_const: *const u8 = &undefined;
228 _ = .{ &ptr_c, &ptr_const };
229 try expect(@TypeOf(ptr_c, ptr_const) == [*c]const u8);
230}
231
232test "implicit casting between C pointer and optional non-C pointer" {
233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
237
238 var slice: []const u8 = "aoeu";
239 _ = &slice;
240 const opt_many_ptr: ?[*]const u8 = slice.ptr;
241 var ptr_opt_many_ptr = &opt_many_ptr;
242 const c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
243 try expect(c_ptr.*.* == 'a');
244 ptr_opt_many_ptr = c_ptr;
245 try expect(ptr_opt_many_ptr.*.?[1] == 'o');
246}
247
248test "implicit cast error unions with non-optional to optional pointer" {
249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
251 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
253
254 const S = struct {
255 fn doTheTest() !void {
256 try expectError(error.Fail, foo());
257 }
258 fn foo() anyerror!?*u8 {
259 return bar() orelse error.Fail;
260 }
261 fn bar() ?*u8 {
262 return null;
263 }
264 };
265 try S.doTheTest();
266 try comptime S.doTheTest();
267}
268
269test "compare equality of optional and non-optional pointer" {
270 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
271
272 const a = @as(*const usize, @ptrFromInt(0x12345678));
273 const b = @as(?*usize, @ptrFromInt(0x12345678));
274 try expect(a == b);
275 try expect(b == a);
276}
277
278test "allowzero pointer and slice" {
279 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
280 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
281 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
282 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
283
284 var ptr: [*]allowzero i32 = @ptrFromInt(0);
285 const opt_ptr: ?[*]allowzero i32 = ptr;
286 try expect(opt_ptr != null);
287 try expect(@intFromPtr(ptr) == 0);
288 var runtime_zero: usize = 0;
289 _ = &runtime_zero;
290 var slice = ptr[runtime_zero..10];
291 comptime assert(@TypeOf(slice) == []allowzero i32);
292 try expect(@intFromPtr(&slice[5]) == 20);
293
294 comptime assert(@typeInfo(@TypeOf(ptr)).pointer.is_allowzero);
295 comptime assert(@typeInfo(@TypeOf(slice)).pointer.is_allowzero);
296}
297
298test "assign null directly to C pointer and test null equality" {
299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
300 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
302
303 var x: [*c]i32 = null;
304 _ = &x;
305 try expect(x == null);
306 try expect(null == x);
307 try expect(!(x != null));
308 try expect(!(null != x));
309 if (x) |same_x| {
310 _ = same_x;
311 @panic("fail");
312 }
313 var otherx: i32 = undefined;
314 try expect((x orelse &otherx) == &otherx);
315
316 const y: [*c]i32 = null;
317 comptime assert(y == null);
318 comptime assert(null == y);
319 comptime assert(!(y != null));
320 comptime assert(!(null != y));
321 if (y) |same_y| {
322 _ = same_y;
323 @panic("fail");
324 }
325 const othery: i32 = undefined;
326 const ptr_othery = &othery;
327 comptime assert((y orelse ptr_othery) == ptr_othery);
328
329 var n: i32 = 1234;
330 const x1: [*c]i32 = &n;
331 try expect(!(x1 == null));
332 try expect(!(null == x1));
333 try expect(x1 != null);
334 try expect(null != x1);
335 try expect(x1.?.* == 1234);
336 if (x1) |same_x1| {
337 try expect(same_x1.* == 1234);
338 } else {
339 @panic("fail");
340 }
341 try expect((x1 orelse &otherx) == x1);
342
343 const nc: i32 = 1234;
344 const y1: [*c]const i32 = &nc;
345 comptime assert(!(y1 == null));
346 comptime assert(!(null == y1));
347 comptime assert(y1 != null);
348 comptime assert(null != y1);
349 comptime assert(y1.?.* == 1234);
350 if (y1) |same_y1| {
351 try expect(same_y1.* == 1234);
352 } else {
353 @compileError("fail");
354 }
355 comptime assert((y1 orelse &othery) == y1);
356}
357
358test "array initialization types" {
359 const E = enum { A, B, C };
360 try expect(@TypeOf([_]u8{}) == [0]u8);
361 try expect(@TypeOf([_:0]u8{}) == [0:0]u8);
362 try expect(@TypeOf([_:.A]E{}) == [0:.A]E);
363 try expect(@TypeOf([_:0]u8{ 1, 2, 3 }) == [3:0]u8);
364}
365
366test "null terminated pointer" {
367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
369
370 const S = struct {
371 fn doTheTest() !void {
372 var array_with_zero = [_:0]u8{ 'h', 'e', 'l', 'l', 'o' };
373 const zero_ptr: [*:0]const u8 = @ptrCast(&array_with_zero);
374 const no_zero_ptr: [*]const u8 = zero_ptr;
375 const zero_ptr_again: [*:0]const u8 = @ptrCast(no_zero_ptr);
376 try expect(std.mem.eql(u8, std.mem.sliceTo(zero_ptr_again, 0), "hello"));
377 }
378 };
379 try S.doTheTest();
380 try comptime S.doTheTest();
381}
382
383test "allow any sentinel" {
384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
387
388 const S = struct {
389 fn doTheTest() !void {
390 var array = [_:std.math.minInt(i32)]i32{ 1, 2, 3, 4 };
391 const ptr: [*:std.math.minInt(i32)]i32 = &array;
392 try expect(ptr[4] == std.math.minInt(i32));
393 }
394 };
395 try S.doTheTest();
396 try comptime S.doTheTest();
397}
398
399test "pointer sentinel with enums" {
400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
401 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
402 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
403
404 const S = struct {
405 const Number = enum {
406 one,
407 two,
408 sentinel,
409 };
410
411 fn doTheTest() !void {
412 var ptr: [*:.sentinel]const Number = &[_:.sentinel]Number{ .one, .two, .two, .one };
413 _ = &ptr;
414 try expect(ptr[4] == .sentinel); // TODO this should be comptime assert, see #3731
415 }
416 };
417 try S.doTheTest();
418 try comptime S.doTheTest();
419}
420
421test "pointer sentinel with optional element" {
422 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
424 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
425 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
426
427 const S = struct {
428 fn doTheTest() !void {
429 var ptr: [*:null]const ?i32 = &[_:null]?i32{ 1, 2, 3, 4 };
430 _ = &ptr;
431 try expect(ptr[4] == null); // TODO this should be comptime assert, see #3731
432 }
433 };
434 try S.doTheTest();
435 try comptime S.doTheTest();
436}
437
438test "pointer sentinel with +inf" {
439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
441 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
442 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
443
444 const S = struct {
445 fn doTheTest() !void {
446 const inf_f32 = comptime std.math.inf(f32);
447 var ptr: [*:inf_f32]const f32 = &[_:inf_f32]f32{ 1.1, 2.2, 3.3, 4.4 };
448 _ = &ptr;
449 try expect(ptr[4] == inf_f32); // TODO this should be comptime assert, see #3731
450 }
451 };
452 try S.doTheTest();
453 try comptime S.doTheTest();
454}
455
456test "pointer to array at fixed address" {
457 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
458
459 const array = @as(*volatile [2]u32, @ptrFromInt(0x10));
460 // Silly check just to reference `array`
461 try expect(@intFromPtr(&array[0]) == 0x10);
462 try expect(@intFromPtr(&array[1]) == 0x14);
463}
464
465test "pointer-integer arithmetic affects the alignment" {
466 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
467
468 {
469 var ptr: [*]align(8) u32 = undefined;
470 var x: usize = 1;
471 _ = .{ &ptr, &x };
472
473 try expect(@typeInfo(@TypeOf(ptr)).pointer.alignment == 8);
474 const ptr1 = ptr + 1; // 1 * 4 = 4 -> lcd(4,8) = 4
475 try expect(@typeInfo(@TypeOf(ptr1)).pointer.alignment == 4);
476 const ptr2 = ptr + 4; // 4 * 4 = 16 -> lcd(16,8) = 8
477 try expect(@typeInfo(@TypeOf(ptr2)).pointer.alignment == 8);
478 const ptr3 = ptr + 0; // no-op
479 try expect(@typeInfo(@TypeOf(ptr3)).pointer.alignment == 8);
480 const ptr4 = ptr + x; // runtime-known addend
481 try expect(@typeInfo(@TypeOf(ptr4)).pointer.alignment == 4);
482 }
483 {
484 var ptr: [*]align(8) [3]u8 = undefined;
485 var x: usize = 1;
486 _ = .{ &ptr, &x };
487
488 const ptr1 = ptr + 17; // 3 * 17 = 51
489 try expect(@typeInfo(@TypeOf(ptr1)).pointer.alignment == 1);
490 const ptr2 = ptr + x; // runtime-known addend
491 try expect(@typeInfo(@TypeOf(ptr2)).pointer.alignment == 1);
492 const ptr3 = ptr + 8; // 3 * 8 = 24 -> lcd(8,24) = 8
493 try expect(@typeInfo(@TypeOf(ptr3)).pointer.alignment == 8);
494 const ptr4 = ptr + 4; // 3 * 4 = 12 -> lcd(8,12) = 4
495 try expect(@typeInfo(@TypeOf(ptr4)).pointer.alignment == 4);
496 }
497}
498
499test "@intFromPtr on null optional at comptime" {
500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
501
502 {
503 const pointer = @as(?*u8, @ptrFromInt(0x000));
504 const x = @intFromPtr(pointer);
505 _ = x;
506 comptime assert(0 == @intFromPtr(pointer));
507 }
508 {
509 const pointer = @as(?*u8, @ptrFromInt(0xf00));
510 comptime assert(0xf00 == @intFromPtr(pointer));
511 }
512}
513
514test "indexing array with sentinel returns correct type" {
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
519 var s: [:0]const u8 = "abc";
520 try testing.expectEqualSlices(u8, "*const u8", @typeName(@TypeOf(&s[0])));
521}
522
523test "element pointer to slice" {
524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
525 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
526
527 const S = struct {
528 fn doTheTest() !void {
529 var cases: [2][2]i32 = [_][2]i32{
530 [_]i32{ 0, 1 },
531 [_]i32{ 2, 3 },
532 };
533
534 const items: []i32 = &cases[0]; // *[2]i32
535 try testing.expect(items.len == 2);
536 try testing.expect(items[1] == 1);
537 try testing.expect(items[0] == 0);
538 }
539 };
540
541 try S.doTheTest();
542 try comptime S.doTheTest();
543}
544
545test "element pointer arithmetic to slice" {
546 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
547 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
548
549 const S = struct {
550 fn doTheTest() !void {
551 var cases: [2][2]i32 = [_][2]i32{
552 [_]i32{ 0, 1 },
553 [_]i32{ 2, 3 },
554 };
555
556 const elem_ptr = &cases[0]; // *[2]i32
557 const many = @as([*][2]i32, @ptrCast(elem_ptr));
558 const many_elem = @as(*[2]i32, @ptrCast(&many[1]));
559 const items: []i32 = many_elem;
560 try testing.expect(items.len == 2);
561 try testing.expect(items[1] == 3);
562 try testing.expect(items[0] == 2);
563 }
564 };
565
566 try S.doTheTest();
567 try comptime S.doTheTest();
568}
569
570test "array slicing to slice" {
571 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
572 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
573
574 const S = struct {
575 fn doTheTest() !void {
576 var str: [5]i32 = [_]i32{ 1, 2, 3, 4, 5 };
577 const sub: *[2]i32 = str[1..3];
578 const slice: []i32 = sub; // used to cause failures
579 try testing.expect(slice.len == 2);
580 try testing.expect(slice[0] == 2);
581 }
582 };
583
584 try S.doTheTest();
585 try comptime S.doTheTest();
586}
587
588test "pointer to constant decl preserves alignment" {
589 const S = struct {
590 a: u8,
591 b: u8,
592 const aligned align(8) = @This(){ .a = 3, .b = 4 };
593 };
594
595 const alignment = @typeInfo(@TypeOf(&S.aligned)).pointer.alignment;
596 try std.testing.expect(alignment == 8);
597}
598
599test "ptrCast comptime known slice to C pointer" {
600 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
601 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
602 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
603
604 const s: [:0]const u8 = "foo";
605 var p: [*c]const u8 = @ptrCast(s);
606 _ = &p;
607 try std.testing.expectEqualStrings(s, std.mem.sliceTo(p, 0));
608}
609
610test "pointer alignment and element type include call expression" {
611 const S = struct {
612 fn T() type {
613 return struct { _: i32 };
614 }
615 const P = *align(@alignOf(T())) [@sizeOf(T())]u8;
616 };
617 try expect(@alignOf(S.P) > 0);
618}
619
620test "pointer to array has explicit alignment" {
621 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
622
623 const S = struct {
624 const Base = extern struct { a: u8 };
625 const Base2 = extern struct { a: u8 };
626 fn func(ptr: *[4]Base) *align(1) [4]Base2 {
627 return @alignCast(@as(*[4]Base2, @ptrCast(ptr)));
628 }
629 };
630 var bases = [_]S.Base{.{ .a = 2 }} ** 4;
631 const casted = S.func(&bases);
632 try expect(casted[0].a == 2);
633}
634
635test "result type preserved through multiple references" {
636 const S = struct { x: u32 };
637 var my_u64: u64 = 12345;
638 _ = &my_u64;
639 const foo: *const *const *const S = &&&.{
640 .x = @intCast(my_u64),
641 };
642 try expect(foo.*.*.*.x == 12345);
643}
644
645test "result type found through optional pointer" {
646 const ptr1: ?*const u32 = &@intCast(123);
647 const ptr2: ?[]const u8 = &.{ @intCast(123), @truncate(0xABCD) };
648 try expect(ptr1.?.* == 123);
649 try expect(ptr2.?.len == 2);
650 try expect(ptr2.?[0] == 123);
651 try expect(ptr2.?[1] == 0xCD);
652}
653
654const Box0 = struct {
655 items: [4]Item,
656
657 const Item = struct {
658 num: u32,
659 };
660};
661const Box1 = struct {
662 items: [4]Item,
663
664 const Item = struct {};
665};
666const Box2 = struct {
667 items: [4]Item,
668
669 const Item = struct {
670 nothing: void,
671 };
672};
673
674fn mutable() !void {
675 var box0: Box0 = .{ .items = undefined };
676 try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).pointer.is_const == false);
677
678 var box1: Box1 = .{ .items = undefined };
679 try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).pointer.is_const == false);
680
681 var box2: Box2 = .{ .items = undefined };
682 try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).pointer.is_const == false);
683}
684
685fn constant() !void {
686 const box0: Box0 = .{ .items = undefined };
687 try std.testing.expect(@typeInfo(@TypeOf(box0.items[0..])).pointer.is_const == true);
688
689 const box1: Box1 = .{ .items = undefined };
690 try std.testing.expect(@typeInfo(@TypeOf(box1.items[0..])).pointer.is_const == true);
691
692 const box2: Box2 = .{ .items = undefined };
693 try std.testing.expect(@typeInfo(@TypeOf(box2.items[0..])).pointer.is_const == true);
694}
695
696test "pointer-to-array constness for zero-size elements, var" {
697 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
698 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
699
700 try mutable();
701 try comptime mutable();
702}
703
704test "pointer-to-array constness for zero-size elements, const" {
705 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
706
707 try constant();
708 try comptime constant();
709}
710
711test "cast pointers with zero sized elements" {
712 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
713
714 const a: *void = undefined;
715 const b: *[1]void = a;
716 _ = b;
717 const c: *[0]u8 = undefined;
718 const d: []u8 = c;
719 _ = d;
720}
721
722test "comptime pointer equality through distinct fields with well-defined layout" {
723 const A = extern struct {
724 x: u32,
725 z: u16,
726 };
727 const B = extern struct {
728 x: u16,
729 y: u16,
730 z: u16,
731 };
732
733 const a: A = .{
734 .x = undefined,
735 .z = 123,
736 };
737
738 const ap: *const A = &a;
739 const bp: *const B = @ptrCast(ap);
740
741 comptime assert(&ap.z == &bp.z);
742 comptime assert(ap.z == 123);
743 comptime assert(bp.z == 123);
744}
745
746test "comptime pointer equality through distinct elements with well-defined layout" {
747 const buf: [2]u32 = .{ 123, 456 };
748
749 const ptr: *const [2]u32 = &buf;
750 const byte_ptr: *align(4) const [8]u8 = @ptrCast(ptr);
751 const second_elem: *const u32 = @ptrCast(byte_ptr[4..8]);
752
753 comptime assert(&buf[1] == second_elem);
754 comptime assert(buf[1] == 456);
755 comptime assert(second_elem.* == 456);
756}
757
758test "pointers to elements of slice of zero-bit type" {
759 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
760
761 var slice: []const u0 = undefined;
762 slice = &.{ 0, 0 };
763
764 const a = &slice[0];
765 const b = &slice[1];
766
767 try expect(a == b);
768}
769
770test "pointers to elements of many-ptr to zero-bit type" {
771 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
772
773 var many_ptr: [*]const u0 = undefined;
774 many_ptr = &.{ 0, 0 };
775
776 const a = &many_ptr[0];
777 const b = &many_ptr[1];
778
779 try expect(a == b);
780}
781
782test "comptime C pointer to optional pointer" {
783 const opt: ?*u8 = @ptrFromInt(0x1000);
784 const outer_ptr: [*c]const ?*u8 = &opt;
785 const inner_ptr = &outer_ptr.*.?;
786 comptime assert(@TypeOf(inner_ptr) == [*c]const *u8);
787 comptime assert(@intFromPtr(inner_ptr.*) == 0x1000);
788}