aboutsummaryrefslogtreecommitdiff
path: root/lib/std/meta.zig
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2021-06-13 16:53:01 +0300
committerVeikka Tuominen <git@vexu.eu>2021-06-13 16:53:01 +0300
commit029fe6c9abca1373ef0e379fa8e24fbf3a987800 (patch)
tree2b98942516624eefbe28112cb9ac470089427b54 /lib/std/meta.zig
parente5750f8c7f65455589e2d4b45847a351ab7023d6 (diff)
downloadzig-029fe6c9abca1373ef0e379fa8e24fbf3a987800.tar.gz
zig-029fe6c9abca1373ef0e379fa8e24fbf3a987800.zip
meta.cast: handle casts from negative ints to ptrs
Diffstat (limited to 'lib/std/meta.zig')
-rw-r--r--lib/std/meta.zig62
1 files changed, 32 insertions, 30 deletions
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index 56b231eedb..e738ad6efb 100644
--- a/lib/std/meta.zig
+++ b/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.