Commit 029fe6c9ab

Veikka Tuominen <git@vexu.eu>
2021-06-13 15:53:01
meta.cast: handle casts from negative ints to ptrs
1 parent e5750f8
Changed files (3)
lib/std/meta.zig
@@ -890,38 +890,10 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
     // this function should behave like transCCast in translate-c, except it's for macros and enums
     const SourceType = @TypeOf(target);
     switch (@typeInfo(DestType)) {
-        .Pointer => {
-            switch (@typeInfo(SourceType)) {
-                .Int, .ComptimeInt => {
-                    return @intToPtr(DestType, target);
-                },
-                .Pointer => {
-                    return castPtr(DestType, target);
-                },
-                .Optional => |opt| {
-                    if (@typeInfo(opt.child) == .Pointer) {
-                        return castPtr(DestType, target);
-                    }
-                },
-                else => {},
-            }
-        },
+        .Pointer => return castToPtr(DestType, SourceType, target),
         .Optional => |dest_opt| {
             if (@typeInfo(dest_opt.child) == .Pointer) {
-                switch (@typeInfo(SourceType)) {
-                    .Int, .ComptimeInt => {
-                        return @intToPtr(DestType, target);
-                    },
-                    .Pointer => {
-                        return castPtr(DestType, target);
-                    },
-                    .Optional => |target_opt| {
-                        if (@typeInfo(target_opt.child) == .Pointer) {
-                            return castPtr(DestType, target);
-                        }
-                    },
-                    else => {},
-                }
+                return castToPtr(DestType, SourceType, target);
             }
         },
         .Enum => |enum_type| {
@@ -977,6 +949,30 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {
         return @ptrCast(DestType, @alignCast(dest.alignment, target));
 }
 
+fn castToPtr(comptime DestType: type, comptime SourceType: type, target: anytype) DestType {
+    switch (@typeInfo(SourceType)) {
+        .Int => {
+            return @intToPtr(DestType, castInt(usize, target));
+        },
+        .ComptimeInt => {
+            if (target < 0)
+                return @intToPtr(DestType, @bitCast(usize, @intCast(isize, target)))
+            else
+                return @intToPtr(DestType, @intCast(usize, target));
+        },
+        .Pointer => {
+            return castPtr(DestType, target);
+        },
+        .Optional => |target_opt| {
+            if (@typeInfo(target_opt.child) == .Pointer) {
+                return castPtr(DestType, target);
+            }
+        },
+        else => {},
+    }
+    return @as(DestType, target);
+}
+
 fn ptrInfo(comptime PtrType: type) TypeInfo.Pointer {
     return switch (@typeInfo(PtrType)) {
         .Optional => |opt_info| @typeInfo(opt_info.child).Pointer,
@@ -1026,6 +1022,12 @@ test "std.meta.cast" {
     try testing.expectEqual(cast(C_ENUM, @as(i8, 1)), .B);
     try testing.expectEqual(cast(C_ENUM, @as(u64, 1)), .B);
     try testing.expectEqual(cast(C_ENUM, @as(u64, 42)), @intToEnum(C_ENUM, 42));
+
+    var foo: c_int = -1;
+    try testing.expect(cast(*c_void, -1) == @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))));
+    try testing.expect(cast(*c_void, foo) == @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))));
+    try testing.expect(cast(?*c_void, -1) == @intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))));
+    try testing.expect(cast(?*c_void, foo) == @intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))));
 }
 
 /// Given a value returns its size as C's sizeof operator would.
test/behavior/translate_c_macros.h
@@ -16,3 +16,5 @@ struct Foo {
 };
 
 #define SIZE_OF_FOO sizeof(struct Foo)
+
+#define MAP_FAILED	((void *) -1)
test/behavior/translate_c_macros.zig
@@ -20,3 +20,7 @@ test "sizeof in macros" {
 test "reference to a struct type" {
     try expectEqual(@sizeOf(h.struct_Foo), h.SIZE_OF_FOO);
 }
+
+test "cast negative integer to pointer" {
+    try expectEqual(@intToPtr(?*c_void, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED);
+}