Commit ed7328119f

Andrew Kelley <andrew@ziglang.org>
2021-10-25 20:34:23
Sema: implement coercion from pointers to `*c_void`
1 parent 8f3e1ea
Changed files (3)
src/Sema.zig
@@ -9711,10 +9711,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
             @tagName(dest_ty.zigTypeTag()), dest_ty,
         });
     }
-    if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
-        return sema.addConstant(dest_ty, val);
-    }
-    return block.addBitCast(dest_ty, operand);
+    return sema.coerceCompatiblePtrs(block, dest_ty, operand, operand_src);
 }
 
 fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -12096,6 +12093,14 @@ fn coerce(
                     else => {},
                 }
             }
+
+            // cast from *T and [*]T to *c_void
+            // but don't do it if the source type is a double pointer
+            if (dest_info.pointee_type.tag() == .c_void and inst_ty.zigTypeTag() == .Pointer and
+                inst_ty.childType().zigTypeTag() != .Pointer)
+            {
+                return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
+            }
         },
         .Int => {
             // integer widening
@@ -12808,7 +12813,7 @@ fn coerceCompatiblePtrs(
     inst: Air.Inst.Ref,
     inst_src: LazySrcLoc,
 ) !Air.Inst.Ref {
-    if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
+    if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
         // The comptime Value representation is compatible with both types.
         return sema.addConstant(dest_ty, val);
     }
test/behavior/cast.zig
@@ -106,3 +106,17 @@ test "comptime_int @intToFloat" {
         try expect(result == 0x1_0000_0000_0000_0000.0);
     }
 }
+
+test "implicit cast from [*]T to ?*c_void" {
+    var a = [_]u8{ 3, 2, 1 };
+    var runtime_zero: usize = 0;
+    incrementVoidPtrArray(a[runtime_zero..].ptr, 3);
+    try expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 }));
+}
+
+fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
+    var n: usize = 0;
+    while (n < len) : (n += 1) {
+        @ptrCast([*]u8, array.?)[n] += 1;
+    }
+}
test/behavior/cast_stage1.zig
@@ -417,20 +417,6 @@ fn incrementVoidPtrValue(value: ?*c_void) void {
     @ptrCast(*u8, value.?).* += 1;
 }
 
-test "implicit cast from [*]T to ?*c_void" {
-    var a = [_]u8{ 3, 2, 1 };
-    var runtime_zero: usize = 0;
-    incrementVoidPtrArray(a[runtime_zero..].ptr, 3);
-    try expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 }));
-}
-
-fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
-    var n: usize = 0;
-    while (n < len) : (n += 1) {
-        @ptrCast([*]u8, array.?)[n] += 1;
-    }
-}
-
 test "*usize to *void" {
     var i = @as(usize, 0);
     var v = @ptrCast(*void, &i);