Commit d4d21dd46d
Changed files (4)
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.
src/translate_c.zig
@@ -2161,8 +2161,8 @@ fn transCCast(
return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int });
}
if (cIsEnum(dst_type)) {
- // @intToEnum(dest_type, val)
- return Tag.int_to_enum.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
+ // import("std").meta.cast(dest_type, val)
+ return Tag.std_meta_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
}
if (cIsEnum(src_type) and !cIsEnum(dst_type)) {
// @enumToInt(val)
test/run_translated_c.zig
@@ -1453,4 +1453,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");
+
+ cases.add("Cast to enum from larger integral type. Issue #6011",
+ \\#include <stdint.h>
+ \\#include <stdlib.h>
+ \\enum Foo { A, B, C };
+ \\static inline enum Foo do_stuff(void) {
+ \\ int64_t i = 1;
+ \\ return (enum Foo)i;
+ \\}
+ \\int main(void) {
+ \\ if (do_stuff() != B) abort();
+ \\ return 0;
+ \\}
+ , "");
}
test/translate_c.zig
@@ -111,7 +111,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ const A = @enumToInt(enum_Foo.A);
\\ const B = @enumToInt(enum_Foo.B);
\\ const C = @enumToInt(enum_Foo.C);
- \\ var a: enum_Foo = @intToEnum(enum_Foo, B);
+ \\ var a: enum_Foo = @import("std").meta.cast(enum_Foo, B);
\\ {
\\ const enum_Foo = extern enum(c_int) {
\\ A,
@@ -122,7 +122,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ const A_2 = @enumToInt(enum_Foo.A);
\\ const B_3 = @enumToInt(enum_Foo.B);
\\ const C_4 = @enumToInt(enum_Foo.C);
- \\ var a_5: enum_Foo = @intToEnum(enum_Foo, B_3);
+ \\ var a_5: enum_Foo = @import("std").meta.cast(enum_Foo, B_3);
\\ }
\\}
});
@@ -1676,7 +1676,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const e = @enumToInt(enum_unnamed_1.e);
\\pub const f = @enumToInt(enum_unnamed_1.f);
\\pub const g = @enumToInt(enum_unnamed_1.g);
- \\pub export var h: enum_unnamed_1 = @intToEnum(enum_unnamed_1, e);
+ \\pub export var h: enum_unnamed_1 = @import("std").meta.cast(enum_unnamed_1, e);
\\const enum_unnamed_2 = extern enum(c_int) {
\\ i,
\\ j,
@@ -2308,7 +2308,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ var a = arg_a;
\\ var b = arg_b;
\\ var c = arg_c;
- \\ var d: enum_Foo = @intToEnum(enum_Foo, FooA);
+ \\ var d: enum_Foo = @import("std").meta.cast(enum_Foo, FooA);
\\ var e: c_int = @boolToInt((a != 0) and (b != 0));
\\ var f: c_int = @boolToInt((b != 0) and (c != null));
\\ var g: c_int = @boolToInt((a != 0) and (c != null));