Commit b5c117d051

xackus <14938807+xackus@users.noreply.github.com>
2021-03-30 18:28:50
translate-c: fix enums that require c_uint type
1 parent 986a712
src/translate_c.zig
@@ -1117,9 +1117,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
         // default to the usual integer type used for all the enums.
 
         // default to c_int since msvc and gcc default to different types
-        const init_arg_expr = if (int_type.ptr != null and
-            !isCBuiltinType(int_type, .UInt) and
-            !isCBuiltinType(int_type, .Int))
+        const init_arg_expr = if (int_type.ptr != null)
             transQualType(c, scope, int_type, enum_loc) catch |err| switch (err) {
                 error.UnsupportedType => {
                     return failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
@@ -2285,8 +2283,8 @@ fn transCCast(
         // 1. If src_type is an enum, determine the underlying signed int type
         // 2. Extend or truncate without changing signed-ness.
         // 3. Bit-cast to correct signed-ness
-        const src_type_is_signed = cIsSignedInteger(src_type) or cIsEnum(src_type);
         const src_int_type = if (cIsInteger(src_type)) src_type else cIntTypeForEnum(src_type);
+        const src_type_is_signed = cIsSignedInteger(src_int_type);
         var src_int_expr = if (cIsInteger(src_type)) expr else try Tag.enum_to_int.create(c.arena, expr);
 
         if (isBoolRes(src_int_expr)) {
test/run_translated_c.zig
@@ -1540,4 +1540,14 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
         \\    return 0;
         \\}
     , "");
+
+    cases.add("enum with value that fits in c_uint but not c_int, issue #8003",
+        \\#include <stdlib.h>
+        \\enum my_enum {
+        \\    FORCE_UINT = 0xffffffff
+        \\};
+        \\int main(void) {
+        \\    if(FORCE_UINT != 0xffffffff) abort();
+        \\}
+    , "");
 }
test/translate_c.zig
@@ -3,6 +3,8 @@ const std = @import("std");
 const CrossTarget = std.zig.CrossTarget;
 
 pub fn addCases(cases: *tests.TranslateCContext) void {
+    const default_enum_type = if (std.Target.current.abi == .msvc) "c_int" else "c_uint";
+
     cases.add("field access is grouped if necessary",
         \\unsigned long foo(unsigned long x) {
         \\    return ((union{unsigned long _x}){x})._x;
@@ -28,17 +30,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    int a, b;
         \\} Bar;
     , &[_][]const u8{
-        \\pub const Foo = extern enum(c_int) {
-        \\    A,
-        \\    B,
-        \\    _,
-        \\};
-        \\pub const FooA = @enumToInt(Foo.A);
-        \\pub const FooB = @enumToInt(Foo.B);
-        \\pub const Bar = extern struct {
-        \\    a: c_int,
-        \\    b: c_int,
-        \\};
+        \\pub const Foo = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    A,
+            \\    B,
+            \\    _,
+            \\};
+            \\pub const FooA = @enumToInt(Foo.A);
+            \\pub const FooB = @enumToInt(Foo.B);
+            \\pub const Bar = extern struct {
+            \\    a: c_int,
+            \\    b: c_int,
+            \\};
     });
 
     cases.add("if as while stmt has semicolon",
@@ -118,29 +122,33 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     , &[_][]const u8{
         \\pub export fn foo() void {
-        \\    const enum_Foo = extern enum(c_int) {
-        \\        A,
-        \\        B,
-        \\        C,
-        \\        _,
-        \\    };
-        \\    const A = @enumToInt(enum_Foo.A);
-        \\    const B = @enumToInt(enum_Foo.B);
-        \\    const C = @enumToInt(enum_Foo.C);
-        \\    var a: enum_Foo = @import("std").meta.cast(enum_Foo, B);
-        \\    {
-        \\        const enum_Foo = extern enum(c_int) {
-        \\            A,
-        \\            B,
-        \\            C,
-        \\            _,
-        \\        };
-        \\        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 = @import("std").meta.cast(enum_Foo, B_3);
-        \\    }
-        \\}
+        \\    const enum_Foo = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\        A,
+            \\        B,
+            \\        C,
+            \\        _,
+            \\    };
+            \\    const A = @enumToInt(enum_Foo.A);
+            \\    const B = @enumToInt(enum_Foo.B);
+            \\    const C = @enumToInt(enum_Foo.C);
+            \\    var a: enum_Foo = @import("std").meta.cast(enum_Foo, B);
+            \\    {
+            \\        const enum_Foo = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\            A,
+            \\            B,
+            \\            C,
+            \\            _,
+            \\        };
+            \\        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 = @import("std").meta.cast(enum_Foo, B_3);
+            \\    }
+            \\}
     });
 
     cases.add("scoped record",
@@ -1702,47 +1710,55 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    p,
         \\};
     , &[_][]const u8{
-        \\pub const d = extern enum(c_int) {
-        \\    a,
-        \\    b,
-        \\    c,
-        \\    _,
-        \\};
-        \\pub const a = @enumToInt(d.a);
-        \\pub const b = @enumToInt(d.b);
-        \\pub const c = @enumToInt(d.c);
-        \\const enum_unnamed_1 = extern enum(c_int) {
-        \\    e = 0,
-        \\    f = 4,
-        \\    g = 5,
-        \\    _,
-        \\};
-        \\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 = @import("std").meta.cast(enum_unnamed_1, e);
-        \\const enum_unnamed_2 = extern enum(c_int) {
-        \\    i,
-        \\    j,
-        \\    k,
-        \\    _,
-        \\};
-        \\pub const i = @enumToInt(enum_unnamed_2.i);
-        \\pub const j = @enumToInt(enum_unnamed_2.j);
-        \\pub const k = @enumToInt(enum_unnamed_2.k);
-        \\pub const struct_Baz = extern struct {
-        \\    l: enum_unnamed_2,
-        \\    m: d,
-        \\};
-        \\pub const enum_i = extern enum(c_int) {
-        \\    n,
-        \\    o,
-        \\    p,
-        \\    _,
-        \\};
-        \\pub const n = @enumToInt(enum_i.n);
-        \\pub const o = @enumToInt(enum_i.o);
-        \\pub const p = @enumToInt(enum_i.p);
+        \\pub const d = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    a,
+            \\    b,
+            \\    c,
+            \\    _,
+            \\};
+            \\pub const a = @enumToInt(d.a);
+            \\pub const b = @enumToInt(d.b);
+            \\pub const c = @enumToInt(d.c);
+            \\const enum_unnamed_1 = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    e = 0,
+            \\    f = 4,
+            \\    g = 5,
+            \\    _,
+            \\};
+            \\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 = @import("std").meta.cast(enum_unnamed_1, e);
+            \\const enum_unnamed_2 = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    i,
+            \\    j,
+            \\    k,
+            \\    _,
+            \\};
+            \\pub const i = @enumToInt(enum_unnamed_2.i);
+            \\pub const j = @enumToInt(enum_unnamed_2.j);
+            \\pub const k = @enumToInt(enum_unnamed_2.k);
+            \\pub const struct_Baz = extern struct {
+            \\    l: enum_unnamed_2,
+            \\    m: d,
+            \\};
+            \\pub const enum_i = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    n,
+            \\    o,
+            \\    p,
+            \\    _,
+            \\};
+            \\pub const n = @enumToInt(enum_i.n);
+            \\pub const o = @enumToInt(enum_i.o);
+            \\pub const p = @enumToInt(enum_i.p);
         ,
         \\pub const Baz = struct_Baz;
     });
@@ -2234,13 +2250,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    Two,
         \\};
     , &[_][]const u8{
-        \\const enum_unnamed_1 = extern enum(c_int) {
-        \\    One,
-        \\    Two,
-        \\    _,
-        \\};
-        \\pub const One = @enumToInt(enum_unnamed_1.One);
-        \\pub const Two = @enumToInt(enum_unnamed_1.Two);
+        \\const enum_unnamed_1 = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    One,
+            \\    Two,
+            \\    _,
+            \\};
+            \\pub const One = @enumToInt(enum_unnamed_1.One);
+            \\pub const Two = @enumToInt(enum_unnamed_1.Two);
     });
 
     cases.add("c style cast",
@@ -2338,35 +2356,37 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
         \\}
     , &[_][]const u8{
-        \\pub const enum_Foo = extern enum(c_int) {
-        \\    A,
-        \\    B,
-        \\    C,
-        \\    _,
-        \\};
-        \\pub const FooA = @enumToInt(enum_Foo.A);
-        \\pub const FooB = @enumToInt(enum_Foo.B);
-        \\pub const FooC = @enumToInt(enum_Foo.C);
-        \\pub const SomeTypedef = c_int;
-        \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {
-        \\    var a = arg_a;
-        \\    var b = arg_b;
-        \\    var c = arg_c;
-        \\    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));
-        \\    var h: c_int = @boolToInt((a != 0) or (b != 0));
-        \\    var i: c_int = @boolToInt((b != 0) or (c != null));
-        \\    var j: c_int = @boolToInt((a != 0) or (c != null));
-        \\    var k: c_int = @boolToInt((a != 0) or (@bitCast(c_int, @enumToInt(d)) != 0));
-        \\    var l: c_int = @boolToInt((@bitCast(c_int, @enumToInt(d)) != 0) and (b != 0));
-        \\    var m: c_int = @boolToInt((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0));
-        \\    var td: SomeTypedef = 44;
-        \\    var o: c_int = @boolToInt((td != 0) or (b != 0));
-        \\    var p: c_int = @boolToInt((c != null) and (td != 0));
-        \\    return (((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p;
-        \\}
+        \\pub const enum_Foo = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    A,
+            \\    B,
+            \\    C,
+            \\    _,
+            \\};
+            \\pub const FooA = @enumToInt(enum_Foo.A);
+            \\pub const FooB = @enumToInt(enum_Foo.B);
+            \\pub const FooC = @enumToInt(enum_Foo.C);
+            \\pub const SomeTypedef = c_int;
+            \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {
+            \\    var a = arg_a;
+            \\    var b = arg_b;
+            \\    var c = arg_c;
+            \\    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));
+            \\    var h: c_int = @boolToInt((a != 0) or (b != 0));
+            \\    var i: c_int = @boolToInt((b != 0) or (c != null));
+            \\    var j: c_int = @boolToInt((a != 0) or (c != null));
+            \\    var k: c_int = @boolToInt((a != 0) or (@bitCast(c_int, @enumToInt(d)) != 0));
+            \\    var l: c_int = @boolToInt((@bitCast(c_int, @enumToInt(d)) != 0) and (b != 0));
+            \\    var m: c_int = @boolToInt((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0));
+            \\    var td: SomeTypedef = 44;
+            \\    var o: c_int = @boolToInt((td != 0) or (b != 0));
+            \\    var p: c_int = @boolToInt((c != null) and (td != 0));
+            \\    return (((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p;
+            \\}
         ,
         \\pub const Foo = enum_Foo;
     });
@@ -2387,14 +2407,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    y: c_int,
         \\};
         ,
-        \\pub const enum_Bar = extern enum(c_int) {
-        \\    A,
-        \\    B,
-        \\    _,
-        \\};
-        \\pub const BarA = @enumToInt(enum_Bar.A);
-        \\pub const BarB = @enumToInt(enum_Bar.B);
-        \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
+        \\pub const enum_Bar = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    A,
+            \\    B,
+            \\    _,
+            \\};
+            \\pub const BarA = @enumToInt(enum_Bar.A);
+            \\pub const BarB = @enumToInt(enum_Bar.B);
+            \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
         ,
         \\pub const Foo = struct_Foo;
         \\pub const Bar = enum_Bar;
@@ -2664,26 +2686,28 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return 4;
         \\}
     , &[_][]const u8{
-        \\pub const enum_SomeEnum = extern enum(c_int) {
-        \\    A,
-        \\    B,
-        \\    C,
-        \\    _,
-        \\};
-        \\pub const A = @enumToInt(enum_SomeEnum.A);
-        \\pub const B = @enumToInt(enum_SomeEnum.B);
-        \\pub const C = @enumToInt(enum_SomeEnum.C);
-        \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {
-        \\    var a = arg_a;
-        \\    var b = arg_b;
-        \\    var c = arg_c;
-        \\    var d = arg_d;
-        \\    if (a != 0) return 0;
-        \\    if (b != 0) return 1;
-        \\    if (c != null) return 2;
-        \\    if (@enumToInt(d) != 0) return 3;
-        \\    return 4;
-        \\}
+        \\pub const enum_SomeEnum = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    A,
+            \\    B,
+            \\    C,
+            \\    _,
+            \\};
+            \\pub const A = @enumToInt(enum_SomeEnum.A);
+            \\pub const B = @enumToInt(enum_SomeEnum.B);
+            \\pub const C = @enumToInt(enum_SomeEnum.C);
+            \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {
+            \\    var a = arg_a;
+            \\    var b = arg_b;
+            \\    var c = arg_c;
+            \\    var d = arg_d;
+            \\    if (a != 0) return 0;
+            \\    if (b != 0) return 1;
+            \\    if (c != null) return 2;
+            \\    if (@enumToInt(d) != 0) return 3;
+            \\    return 4;
+            \\}
     });
 
     cases.add("simple data types",
@@ -3130,15 +3154,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    Foo1,
         \\};
     , &[_][]const u8{
-        \\pub const enum_Foo = extern enum(c_int) {
-        \\    A = 2,
-        \\    B = 5,
-        \\    @"1" = 6,
-        \\    _,
-        \\};
-        \\pub const FooA = @enumToInt(enum_Foo.A);
-        \\pub const FooB = @enumToInt(enum_Foo.B);
-        \\pub const Foo1 = @enumToInt(enum_Foo.@"1");
+        \\pub const enum_Foo = extern enum(
+        ++ default_enum_type ++
+            \\) {
+            \\    A = 2,
+            \\    B = 5,
+            \\    @"1" = 6,
+            \\    _,
+            \\};
+            \\pub const FooA = @enumToInt(enum_Foo.A);
+            \\pub const FooB = @enumToInt(enum_Foo.B);
+            \\pub const Foo1 = @enumToInt(enum_Foo.@"1");
         ,
         \\pub const Foo = enum_Foo;
     });