From 029fe6c9abca1373ef0e379fa8e24fbf3a987800 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sun, 13 Jun 2021 16:53:01 +0300 Subject: [PATCH] meta.cast: handle casts from negative ints to ptrs --- lib/std/meta.zig | 62 ++++++++++++++-------------- test/behavior/translate_c_macros.h | 2 + test/behavior/translate_c_macros.zig | 4 ++ 3 files changed, 38 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. diff --git a/test/behavior/translate_c_macros.h b/test/behavior/translate_c_macros.h index d3a6ac1ea5..6f458684c7 100644 --- a/test/behavior/translate_c_macros.h +++ b/test/behavior/translate_c_macros.h @@ -16,3 +16,5 @@ struct Foo { }; #define SIZE_OF_FOO sizeof(struct Foo) + +#define MAP_FAILED ((void *) -1) diff --git a/test/behavior/translate_c_macros.zig b/test/behavior/translate_c_macros.zig index 5be8eac5a7..8de06ae8ea 100644 --- a/test/behavior/translate_c_macros.zig +++ b/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); +}