const builtin = @import("builtin"); const std = @import("std"); const testing = std.testing; const expect = testing.expect; const expectError = testing.expectError; test "dereference pointer" { comptime try testDerefPtr(); try testDerefPtr(); } fn testDerefPtr() !void { var x: i32 = 1234; var y = &x; y.* += 1; try expect(x == 1235); } test "pointer arithmetic" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var ptr: [*]const u8 = "abcd"; try expect(ptr[0] == 'a'); ptr += 1; try expect(ptr[0] == 'b'); ptr += 1; try expect(ptr[0] == 'c'); ptr += 1; try expect(ptr[0] == 'd'); ptr += 1; try expect(ptr[0] == 0); ptr -= 1; try expect(ptr[0] == 'd'); ptr -= 1; try expect(ptr[0] == 'c'); ptr -= 1; try expect(ptr[0] == 'b'); ptr -= 1; try expect(ptr[0] == 'a'); } test "double pointer parsing" { comptime try expect(PtrOf(PtrOf(i32)) == **i32); } fn PtrOf(comptime T: type) type { return *T; } test "implicit cast single item pointer to C pointer and back" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var y: u8 = 11; var x: [*c]u8 = &y; var z: *u8 = x; z.* += 1; try expect(y == 12); } test "initialize const optional C pointer to null" { const a: ?[*c]i32 = null; try expect(a == null); comptime try expect(a == null); } test "assigning integer to C pointer" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var x: i32 = 0; var y: i32 = 1; var ptr: [*c]u8 = 0; var ptr2: [*c]u8 = x; var ptr3: [*c]u8 = 1; var ptr4: [*c]u8 = y; try expect(ptr == ptr2); try expect(ptr3 == ptr4); try expect(ptr3 > ptr and ptr4 > ptr2 and y > x); try expect(1 > ptr and y > ptr2 and 0 < ptr3 and x < ptr4); } test "C pointer comparison and arithmetic" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var ptr1: [*c]u32 = 0; var ptr2 = ptr1 + 10; try expect(ptr1 == 0); try expect(ptr1 >= 0); try expect(ptr1 <= 0); // expect(ptr1 < 1); // expect(ptr1 < one); // expect(1 > ptr1); // expect(one > ptr1); try expect(ptr1 < ptr2); try expect(ptr2 > ptr1); try expect(ptr2 >= 40); try expect(ptr2 == 40); try expect(ptr2 <= 40); ptr2 -= 10; try expect(ptr1 == ptr2); } }; try S.doTheTest(); comptime try S.doTheTest(); } test "dereference pointer again" { try testDerefPtrOneVal(); comptime try testDerefPtrOneVal(); } const Foo1 = struct { x: void, }; fn testDerefPtrOneVal() !void { // Foo1 satisfies the OnePossibleValueYes criteria const x = &Foo1{ .x = {} }; const y = x.*; try expect(@TypeOf(y.x) == void); } test "peer type resolution with C pointers" { var ptr_one: *u8 = undefined; var ptr_many: [*]u8 = undefined; var ptr_c: [*c]u8 = undefined; var t = true; var x1 = if (t) ptr_one else ptr_c; var x2 = if (t) ptr_many else ptr_c; var x3 = if (t) ptr_c else ptr_one; var x4 = if (t) ptr_c else ptr_many; try expect(@TypeOf(x1) == [*c]u8); try expect(@TypeOf(x2) == [*c]u8); try expect(@TypeOf(x3) == [*c]u8); try expect(@TypeOf(x4) == [*c]u8); } test "peer type resolution with C pointer and const pointer" { var ptr_c: [*c]u8 = undefined; const ptr_const: u8 = undefined; try expect(@TypeOf(ptr_c, &ptr_const) == [*c]const u8); } test "implicit casting between C pointer and optional non-C pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var slice: []const u8 = "aoeu"; const opt_many_ptr: ?[*]const u8 = slice.ptr; var ptr_opt_many_ptr = &opt_many_ptr; var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; try expect(c_ptr.*.* == 'a'); ptr_opt_many_ptr = c_ptr; try expect(ptr_opt_many_ptr.*.?[1] == 'o'); } test "implicit cast error unions with non-optional to optional pointer" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { try expectError(error.Fail, foo()); } fn foo() anyerror!?*u8 { return bar() orelse error.Fail; } fn bar() ?*u8 { return null; } }; try S.doTheTest(); comptime try S.doTheTest(); } test "compare equality of optional and non-optional pointer" { const a = @intToPtr(*const usize, 0x12345678); const b = @intToPtr(?*usize, 0x12345678); try expect(a == b); try expect(b == a); } test "allowzero pointer and slice" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var ptr = @intToPtr([*]allowzero i32, 0); var opt_ptr: ?[*]allowzero i32 = ptr; try expect(opt_ptr != null); try expect(@ptrToInt(ptr) == 0); var runtime_zero: usize = 0; var slice = ptr[runtime_zero..10]; comptime try expect(@TypeOf(slice) == []allowzero i32); try expect(@ptrToInt(&slice[5]) == 20); comptime try expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); comptime try expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); } test "assign null directly to C pointer and test null equality" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var x: [*c]i32 = null; try expect(x == null); try expect(null == x); try expect(!(x != null)); try expect(!(null != x)); if (x) |same_x| { _ = same_x; @panic("fail"); } var otherx: i32 = undefined; try expect((x orelse &otherx) == &otherx); const y: [*c]i32 = null; comptime try expect(y == null); comptime try expect(null == y); comptime try expect(!(y != null)); comptime try expect(!(null != y)); if (y) |same_y| { _ = same_y; @panic("fail"); } const othery: i32 = undefined; const ptr_othery = &othery; comptime try expect((y orelse ptr_othery) == ptr_othery); var n: i32 = 1234; var x1: [*c]i32 = &n; try expect(!(x1 == null)); try expect(!(null == x1)); try expect(x1 != null); try expect(null != x1); try expect(x1.?.* == 1234); if (x1) |same_x1| { try expect(same_x1.* == 1234); } else { @panic("fail"); } try expect((x1 orelse &otherx) == x1); const nc: i32 = 1234; const y1: [*c]const i32 = &nc; comptime try expect(!(y1 == null)); comptime try expect(!(null == y1)); comptime try expect(y1 != null); comptime try expect(null != y1); comptime try expect(y1.?.* == 1234); if (y1) |same_y1| { try expect(same_y1.* == 1234); } else { @compileError("fail"); } comptime try expect((y1 orelse &othery) == y1); } test "array initialization types" { const E = enum { A, B, C }; try expect(@TypeOf([_]u8{}) == [0]u8); try expect(@TypeOf([_:0]u8{}) == [0:0]u8); try expect(@TypeOf([_:.A]E{}) == [0:.A]E); try expect(@TypeOf([_:0]u8{ 1, 2, 3 }) == [3:0]u8); } test "null terminated pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var array_with_zero = [_:0]u8{ 'h', 'e', 'l', 'l', 'o' }; var zero_ptr: [*:0]const u8 = @ptrCast([*:0]const u8, &array_with_zero); var no_zero_ptr: [*]const u8 = zero_ptr; var zero_ptr_again = @ptrCast([*:0]const u8, no_zero_ptr); try expect(std.mem.eql(u8, std.mem.sliceTo(zero_ptr_again, 0), "hello")); } }; try S.doTheTest(); comptime try S.doTheTest(); } test "allow any sentinel" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var array = [_:std.math.minInt(i32)]i32{ 1, 2, 3, 4 }; var ptr: [*:std.math.minInt(i32)]i32 = &array; try expect(ptr[4] == std.math.minInt(i32)); } }; try S.doTheTest(); comptime try S.doTheTest(); } test "pointer sentinel with enums" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { const Number = enum { one, two, sentinel, }; fn doTheTest() !void { var ptr: [*:.sentinel]const Number = &[_:.sentinel]Number{ .one, .two, .two, .one }; try expect(ptr[4] == .sentinel); // TODO this should be comptime try expect, see #3731 } }; try S.doTheTest(); comptime try S.doTheTest(); } test "pointer sentinel with optional element" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var ptr: [*:null]const ?i32 = &[_:null]?i32{ 1, 2, 3, 4 }; try expect(ptr[4] == null); // TODO this should be comptime try expect, see #3731 } }; try S.doTheTest(); comptime try S.doTheTest(); } test "pointer sentinel with +inf" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { const inf = std.math.inf_f32; var ptr: [*:inf]const f32 = &[_:inf]f32{ 1.1, 2.2, 3.3, 4.4 }; try expect(ptr[4] == inf); // TODO this should be comptime try expect, see #3731 } }; try S.doTheTest(); comptime try S.doTheTest(); } test "pointer to array at fixed address" { const array = @intToPtr(*volatile [2]u32, 0x10); // Silly check just to reference `array` try expect(@ptrToInt(&array[0]) == 0x10); try expect(@ptrToInt(&array[1]) == 0x14); } test "pointer arithmetic affects the alignment" { { var ptr: [*]align(8) u32 = undefined; var x: usize = 1; try expect(@typeInfo(@TypeOf(ptr)).Pointer.alignment == 8); const ptr1 = ptr + 1; // 1 * 4 = 4 -> lcd(4,8) = 4 try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 4); const ptr2 = ptr + 4; // 4 * 4 = 16 -> lcd(16,8) = 8 try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 8); const ptr3 = ptr + 0; // no-op try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8); const ptr4 = ptr + x; // runtime-known addend try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4); } { var ptr: [*]align(8) [3]u8 = undefined; var x: usize = 1; const ptr1 = ptr + 17; // 3 * 17 = 51 try expect(@typeInfo(@TypeOf(ptr1)).Pointer.alignment == 1); const ptr2 = ptr + x; // runtime-known addend try expect(@typeInfo(@TypeOf(ptr2)).Pointer.alignment == 1); const ptr3 = ptr + 8; // 3 * 8 = 24 -> lcd(8,24) = 8 try expect(@typeInfo(@TypeOf(ptr3)).Pointer.alignment == 8); const ptr4 = ptr + 4; // 3 * 4 = 12 -> lcd(8,12) = 4 try expect(@typeInfo(@TypeOf(ptr4)).Pointer.alignment == 4); } } test "@ptrToInt on null optional at comptime" { { const pointer = @intToPtr(?*u8, 0x000); const x = @ptrToInt(pointer); _ = x; comptime try expect(0 == @ptrToInt(pointer)); } { const pointer = @intToPtr(?*u8, 0xf00); comptime try expect(0xf00 == @ptrToInt(pointer)); } } test "indexing array with sentinel returns correct type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var s: [:0]const u8 = "abc"; try testing.expectEqualSlices(u8, "*const u8", @typeName(@TypeOf(&s[0]))); } test "element pointer to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var cases: [2][2]i32 = [_][2]i32{ [_]i32{ 0, 1 }, [_]i32{ 2, 3 }, }; const items: []i32 = &cases[0]; // *[2]i32 try testing.expect(items.len == 2); try testing.expect(items[1] == 1); try testing.expect(items[0] == 0); } }; try S.doTheTest(); comptime try S.doTheTest(); } test "element pointer arithmetic to slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var cases: [2][2]i32 = [_][2]i32{ [_]i32{ 0, 1 }, [_]i32{ 2, 3 }, }; const elem_ptr = &cases[0]; // *[2]i32 const many = @ptrCast([*][2]i32, elem_ptr); const many_elem = @ptrCast(*[2]i32, &many[1]); const items: []i32 = many_elem; try testing.expect(items.len == 2); try testing.expect(items[1] == 3); try testing.expect(items[0] == 2); } }; try S.doTheTest(); comptime try S.doTheTest(); } test "array slicing to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { var str: [5]i32 = [_]i32{ 1, 2, 3, 4, 5 }; var sub: *[2]i32 = str[1..3]; var slice: []i32 = sub; // used to cause failures try testing.expect(slice.len == 2); try testing.expect(slice[0] == 2); } }; try S.doTheTest(); comptime try S.doTheTest(); } test "pointer to constant decl preserves alignment" { const S = struct { a: u8, b: u8, const aligned align(8) = @This(){ .a = 3, .b = 4 }; }; const alignment = @typeInfo(@TypeOf(&S.aligned)).Pointer.alignment; try std.testing.expect(alignment == 8); } test "ptrCast comptime known slice to C pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const s: [:0]const u8 = "foo"; var p = @ptrCast([*c]const u8, s); try std.testing.expectEqualStrings(s, std.mem.sliceTo(p, 0)); } test "ptrToInt on a generic function" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag != .linux) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag != .linux) return error.SkipZigTest; // TODO const S = struct { fn generic(i: anytype) @TypeOf(i) { return i; } fn doTheTest(a: anytype) !void { try expect(@ptrToInt(a) != 0); } }; try S.doTheTest(&S.generic); }