aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorEvan Haas <evan@lagerdata.com>2021-04-13 20:57:50 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-15 22:46:22 -0400
commitd4d21dd46d69961300cc796abdebe352dfe6eae8 (patch)
treeaa0e3483f5536d0d8b74894c78e373b045ca3f1b /lib
parentccdf55310bee2dcf86b718d26a56933dc1a03443 (diff)
downloadzig-d4d21dd46d69961300cc796abdebe352dfe6eae8.tar.gz
zig-d4d21dd46d69961300cc796abdebe352dfe6eae8.zip
translate-c: better handling of int -> enum casts
In std.meta.cast when casting to an enum type from an integer type, first do a C-style cast from the source value to the tag type of the enum. This ensures that we don't get an error due to the source value not being representable by the enum. In transCCast() use std.meta.cast instead of directly emitting the cast operation since the enum's underlying type may not be known at translation time due to an MSVC bug, see https://github.com/ziglang/zig/issues/8003 Fixes #6011
Diffstat (limited to 'lib')
-rw-r--r--lib/std/meta.zig18
1 files changed, 15 insertions, 3 deletions
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index 860b6874c0..c6f800ca2c 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -888,7 +888,7 @@ pub fn Vector(comptime len: u32, comptime child: type) type {
/// Given a type and value, cast the value to the type as c would.
/// This is for translate-c and is not intended for general use.
pub fn cast(comptime DestType: type, target: anytype) DestType {
- // this function should behave like transCCast in translate-c, except it's for macros
+ // this function should behave like transCCast in translate-c, except it's for macros and enums
const SourceType = @TypeOf(target);
switch (@typeInfo(DestType)) {
.Pointer => {
@@ -925,9 +925,10 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
}
}
},
- .Enum => {
+ .Enum => |enum_type| {
if (@typeInfo(SourceType) == .Int or @typeInfo(SourceType) == .ComptimeInt) {
- return @intToEnum(DestType, target);
+ const intermediate = cast(enum_type.tag_type, target);
+ return @intToEnum(DestType, intermediate);
}
},
.Int => {
@@ -1015,6 +1016,17 @@ test "std.meta.cast" {
testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*volatile u8, 2)));
testing.expectEqual(@intToPtr(?*c_void, 2), cast(?*c_void, @intToPtr(*u8, 2)));
+
+ const C_ENUM = extern enum(c_int) {
+ A = 0,
+ B,
+ C,
+ _,
+ };
+ testing.expectEqual(cast(C_ENUM, @as(i64, -1)), @intToEnum(C_ENUM, -1));
+ testing.expectEqual(cast(C_ENUM, @as(i8, 1)), .B);
+ testing.expectEqual(cast(C_ENUM, @as(u64, 1)), .B);
+ testing.expectEqual(cast(C_ENUM, @as(u64, 42)), @intToEnum(C_ENUM, 42));
}
/// Given a value returns its size as C's sizeof operator would.