Skip to content

Commit

Permalink
meta.cast: handle casts from negative ints to ptrs
Browse files Browse the repository at this point in the history
  • Loading branch information
Vexu committed Jun 13, 2021
1 parent e5750f8 commit 029fe6c
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 30 deletions.
62 changes: 32 additions & 30 deletions lib/std/meta.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions test/behavior/translate_c_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ struct Foo {
};

#define SIZE_OF_FOO sizeof(struct Foo)

#define MAP_FAILED ((void *) -1)
4 changes: 4 additions & 0 deletions test/behavior/translate_c_macros.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 029fe6c

Please sign in to comment.