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}