authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-06-14 18:10:47+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-15 02:43:06-07:00
log11d0dfb8829f7a247b21b417157bafeebd6a2a90
treef78e3fe50d8d691196cfdddc11a7f8988c5cc3c0
parentce88c43a4ee94d82a64e7580885dc6693cc6120c

Sema: fix @intToPtr of zero value to optional pointer

Calling into coercion logic here is a little opaque, and more to the point wholly unnecessary. Instead, the (very short) logic is now implemented directly in Sema. Resolves: #16033

3 files changed, 31 insertions(+), 8 deletions(-)

src/Module.zig+2-7
......@@ -6817,17 +6817,12 @@ pub fn errorSetFromUnsortedNames(
68176817 return new_ty.toType();
68186818}
68196819
6820/// Supports optionals in addition to pointers.
6820/// Supports only pointers, not pointer-like optionals.
68216821pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
6822 return mod.getCoerced(try mod.intValue_u64(Type.usize, x), ty);
6823}
6824
6825/// Supports only pointers. See `ptrIntValue` for pointer-like optional support.
6826pub fn ptrIntValue_ptronly(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
68276822 assert(ty.zigTypeTag(mod) == .Pointer);
68286823 const i = try intern(mod, .{ .ptr = .{
68296824 .ty = ty.toIntern(),
6830 .addr = .{ .int = try mod.intValue_u64(Type.usize, x) },
6825 .addr = .{ .int = (try mod.intValue_u64(Type.usize, x)).toIntern() },
68316826 } });
68326827 return i.toValue();
68336828}
src/Sema.zig+9-1
......@@ -20846,7 +20846,15 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
2084620846 if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0)
2084720847 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
2084820848
20849 return sema.addConstant(ptr_ty, try mod.ptrIntValue(ptr_ty, addr));
20849 const ptr_val = switch (ptr_ty.zigTypeTag(mod)) {
20850 .Optional => (try mod.intern(.{ .opt = .{
20851 .ty = ptr_ty.toIntern(),
20852 .val = if (addr == 0) .none else (try mod.ptrIntValue(ptr_ty.childType(mod), addr)).toIntern(),
20853 } })).toValue(),
20854 .Pointer => try mod.ptrIntValue(ptr_ty, addr),
20855 else => unreachable,
20856 };
20857 return sema.addConstant(ptr_ty, ptr_val);
2085020858 }
2085120859
2085220860 try sema.requireRuntimeBlock(block, src, operand_src);
test/behavior/inttoptr.zig+20
......@@ -1,4 +1,6 @@
1const std = @import("std");
12const builtin = @import("builtin");
3const expectEqual = std.testing.expectEqual;
24
35test "casting integer address to function pointer" {
46 addressToFunction();
......@@ -26,3 +28,21 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
2628 return;
2729 }
2830}
31
32test "@intToPtr creates null pointer" {
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
36
37 const ptr = @intToPtr(?*u32, 0);
38 try expectEqual(@as(?*u32, null), ptr);
39}
40
41test "@intToPtr creates allowzero zero pointer" {
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
44 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
45
46 const ptr = @intToPtr(*allowzero u32, 0);
47 try expectEqual(@as(usize, 0), @ptrToInt(ptr));
48}