Commit 11d0dfb882

mlugg <mlugg@mlugg.co.uk>
2023-06-14 19:10:47
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
1 parent ce88c43
Changed files (3)
src/Module.zig
@@ -6817,17 +6817,12 @@ pub fn errorSetFromUnsortedNames(
     return new_ty.toType();
 }
 
-/// Supports optionals in addition to pointers.
+/// Supports only pointers, not pointer-like optionals.
 pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
-    return mod.getCoerced(try mod.intValue_u64(Type.usize, x), ty);
-}
-
-/// Supports only pointers. See `ptrIntValue` for pointer-like optional support.
-pub fn ptrIntValue_ptronly(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
     assert(ty.zigTypeTag(mod) == .Pointer);
     const i = try intern(mod, .{ .ptr = .{
         .ty = ty.toIntern(),
-        .addr = .{ .int = try mod.intValue_u64(Type.usize, x) },
+        .addr = .{ .int = (try mod.intValue_u64(Type.usize, x)).toIntern() },
     } });
     return i.toValue();
 }
src/Sema.zig
@@ -20846,7 +20846,15 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
         if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0)
             return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
 
-        return sema.addConstant(ptr_ty, try mod.ptrIntValue(ptr_ty, addr));
+        const ptr_val = switch (ptr_ty.zigTypeTag(mod)) {
+            .Optional => (try mod.intern(.{ .opt = .{
+                .ty = ptr_ty.toIntern(),
+                .val = if (addr == 0) .none else (try mod.ptrIntValue(ptr_ty.childType(mod), addr)).toIntern(),
+            } })).toValue(),
+            .Pointer => try mod.ptrIntValue(ptr_ty, addr),
+            else => unreachable,
+        };
+        return sema.addConstant(ptr_ty, ptr_val);
     }
 
     try sema.requireRuntimeBlock(block, src, operand_src);
test/behavior/inttoptr.zig
@@ -1,4 +1,6 @@
+const std = @import("std");
 const builtin = @import("builtin");
+const expectEqual = std.testing.expectEqual;
 
 test "casting integer address to function pointer" {
     addressToFunction();
@@ -26,3 +28,21 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
         return;
     }
 }
+
+test "@intToPtr creates null 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
+
+    const ptr = @intToPtr(?*u32, 0);
+    try expectEqual(@as(?*u32, null), ptr);
+}
+
+test "@intToPtr creates allowzero zero 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
+
+    const ptr = @intToPtr(*allowzero u32, 0);
+    try expectEqual(@as(usize, 0), @ptrToInt(ptr));
+}