diff options
| author | Veikka Tuominen <git@vexu.eu> | 2021-06-13 16:53:01 +0300 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2021-06-13 16:53:01 +0300 |
| commit | 029fe6c9abca1373ef0e379fa8e24fbf3a987800 (patch) | |
| tree | 2b98942516624eefbe28112cb9ac470089427b54 /lib/std/meta.zig | |
| parent | e5750f8c7f65455589e2d4b45847a351ab7023d6 (diff) | |
| download | zig-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.zig | 62 |
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. |
