translate-c: fix enums that require c_uint type

This commit is contained in:
xackus 2021-03-30 18:28:50 +02:00 committed by Veikka Tuominen
parent 986a71234b
commit b5c117d051
3 changed files with 186 additions and 152 deletions

View file

@ -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 the usual integer type used for all the enums.
// default to c_int since msvc and gcc default to different types // default to c_int since msvc and gcc default to different types
const init_arg_expr = if (int_type.ptr != null and const init_arg_expr = if (int_type.ptr != null)
!isCBuiltinType(int_type, .UInt) and
!isCBuiltinType(int_type, .Int))
transQualType(c, scope, int_type, enum_loc) catch |err| switch (err) { transQualType(c, scope, int_type, enum_loc) catch |err| switch (err) {
error.UnsupportedType => { error.UnsupportedType => {
return failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); 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 // 1. If src_type is an enum, determine the underlying signed int type
// 2. Extend or truncate without changing signed-ness. // 2. Extend or truncate without changing signed-ness.
// 3. Bit-cast to correct 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_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); var src_int_expr = if (cIsInteger(src_type)) expr else try Tag.enum_to_int.create(c.arena, expr);
if (isBoolRes(src_int_expr)) { if (isBoolRes(src_int_expr)) {

View file

@ -1540,4 +1540,14 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0; \\ 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();
\\}
, "");
} }

View file

@ -3,6 +3,8 @@ const std = @import("std");
const CrossTarget = std.zig.CrossTarget; const CrossTarget = std.zig.CrossTarget;
pub fn addCases(cases: *tests.TranslateCContext) void { 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", cases.add("field access is grouped if necessary",
\\unsigned long foo(unsigned long x) { \\unsigned long foo(unsigned long x) {
\\ return ((union{unsigned long _x}){x})._x; \\ return ((union{unsigned long _x}){x})._x;
@ -28,17 +30,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ int a, b; \\ int a, b;
\\} Bar; \\} Bar;
, &[_][]const u8{ , &[_][]const u8{
\\pub const Foo = extern enum(c_int) { \\pub const Foo = extern enum(
\\ A, ++ default_enum_type ++
\\ B, \\) {
\\ _, \\ A,
\\}; \\ B,
\\pub const FooA = @enumToInt(Foo.A); \\ _,
\\pub const FooB = @enumToInt(Foo.B); \\};
\\pub const Bar = extern struct { \\pub const FooA = @enumToInt(Foo.A);
\\ a: c_int, \\pub const FooB = @enumToInt(Foo.B);
\\ b: c_int, \\pub const Bar = extern struct {
\\}; \\ a: c_int,
\\ b: c_int,
\\};
}); });
cases.add("if as while stmt has semicolon", cases.add("if as while stmt has semicolon",
@ -118,29 +122,33 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
\\pub export fn foo() void { \\pub export fn foo() void {
\\ const enum_Foo = extern enum(c_int) { \\ const enum_Foo = extern enum(
\\ A, ++ default_enum_type ++
\\ B, \\) {
\\ C, \\ A,
\\ _, \\ B,
\\ }; \\ C,
\\ const A = @enumToInt(enum_Foo.A); \\ _,
\\ const B = @enumToInt(enum_Foo.B); \\ };
\\ const C = @enumToInt(enum_Foo.C); \\ const A = @enumToInt(enum_Foo.A);
\\ var a: enum_Foo = @import("std").meta.cast(enum_Foo, B); \\ const B = @enumToInt(enum_Foo.B);
\\ { \\ const C = @enumToInt(enum_Foo.C);
\\ const enum_Foo = extern enum(c_int) { \\ var a: enum_Foo = @import("std").meta.cast(enum_Foo, B);
\\ A, \\ {
\\ B, \\ const enum_Foo = extern enum(
\\ C, ++ default_enum_type ++
\\ _, \\) {
\\ }; \\ A,
\\ const A_2 = @enumToInt(enum_Foo.A); \\ B,
\\ const B_3 = @enumToInt(enum_Foo.B); \\ C,
\\ const C_4 = @enumToInt(enum_Foo.C); \\ _,
\\ var a_5: enum_Foo = @import("std").meta.cast(enum_Foo, B_3); \\ };
\\ } \\ 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", cases.add("scoped record",
@ -1702,47 +1710,55 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ p, \\ p,
\\}; \\};
, &[_][]const u8{ , &[_][]const u8{
\\pub const d = extern enum(c_int) { \\pub const d = extern enum(
\\ a, ++ default_enum_type ++
\\ b, \\) {
\\ c, \\ a,
\\ _, \\ b,
\\}; \\ c,
\\pub const a = @enumToInt(d.a); \\ _,
\\pub const b = @enumToInt(d.b); \\};
\\pub const c = @enumToInt(d.c); \\pub const a = @enumToInt(d.a);
\\const enum_unnamed_1 = extern enum(c_int) { \\pub const b = @enumToInt(d.b);
\\ e = 0, \\pub const c = @enumToInt(d.c);
\\ f = 4, \\const enum_unnamed_1 = extern enum(
\\ g = 5, ++ default_enum_type ++
\\ _, \\) {
\\}; \\ e = 0,
\\pub const e = @enumToInt(enum_unnamed_1.e); \\ f = 4,
\\pub const f = @enumToInt(enum_unnamed_1.f); \\ g = 5,
\\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) { \\pub const e = @enumToInt(enum_unnamed_1.e);
\\ i, \\pub const f = @enumToInt(enum_unnamed_1.f);
\\ j, \\pub const g = @enumToInt(enum_unnamed_1.g);
\\ k, \\pub export var h: enum_unnamed_1 = @import("std").meta.cast(enum_unnamed_1, e);
\\ _, \\const enum_unnamed_2 = extern enum(
\\}; ++ default_enum_type ++
\\pub const i = @enumToInt(enum_unnamed_2.i); \\) {
\\pub const j = @enumToInt(enum_unnamed_2.j); \\ i,
\\pub const k = @enumToInt(enum_unnamed_2.k); \\ j,
\\pub const struct_Baz = extern struct { \\ k,
\\ l: enum_unnamed_2, \\ _,
\\ m: d, \\};
\\}; \\pub const i = @enumToInt(enum_unnamed_2.i);
\\pub const enum_i = extern enum(c_int) { \\pub const j = @enumToInt(enum_unnamed_2.j);
\\ n, \\pub const k = @enumToInt(enum_unnamed_2.k);
\\ o, \\pub const struct_Baz = extern struct {
\\ p, \\ l: enum_unnamed_2,
\\ _, \\ m: d,
\\}; \\};
\\pub const n = @enumToInt(enum_i.n); \\pub const enum_i = extern enum(
\\pub const o = @enumToInt(enum_i.o); ++ default_enum_type ++
\\pub const p = @enumToInt(enum_i.p); \\) {
\\ 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; \\pub const Baz = struct_Baz;
}); });
@ -2234,13 +2250,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ Two, \\ Two,
\\}; \\};
, &[_][]const u8{ , &[_][]const u8{
\\const enum_unnamed_1 = extern enum(c_int) { \\const enum_unnamed_1 = extern enum(
\\ One, ++ default_enum_type ++
\\ Two, \\) {
\\ _, \\ One,
\\}; \\ Two,
\\pub const One = @enumToInt(enum_unnamed_1.One); \\ _,
\\pub const Two = @enumToInt(enum_unnamed_1.Two); \\};
\\pub const One = @enumToInt(enum_unnamed_1.One);
\\pub const Two = @enumToInt(enum_unnamed_1.Two);
}); });
cases.add("c style cast", 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); \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
\\pub const enum_Foo = extern enum(c_int) { \\pub const enum_Foo = extern enum(
\\ A, ++ default_enum_type ++
\\ B, \\) {
\\ C, \\ 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 FooA = @enumToInt(enum_Foo.A);
\\pub const SomeTypedef = c_int; \\pub const FooB = @enumToInt(enum_Foo.B);
\\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int { \\pub const FooC = @enumToInt(enum_Foo.C);
\\ var a = arg_a; \\pub const SomeTypedef = c_int;
\\ var b = arg_b; \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {
\\ var c = arg_c; \\ var a = arg_a;
\\ var d: enum_Foo = @import("std").meta.cast(enum_Foo, FooA); \\ var b = arg_b;
\\ var e: c_int = @boolToInt((a != 0) and (b != 0)); \\ var c = arg_c;
\\ var f: c_int = @boolToInt((b != 0) and (c != null)); \\ var d: enum_Foo = @import("std").meta.cast(enum_Foo, FooA);
\\ var g: c_int = @boolToInt((a != 0) and (c != null)); \\ var e: c_int = @boolToInt((a != 0) and (b != 0));
\\ var h: c_int = @boolToInt((a != 0) or (b != 0)); \\ var f: c_int = @boolToInt((b != 0) and (c != null));
\\ var i: c_int = @boolToInt((b != 0) or (c != null)); \\ var g: c_int = @boolToInt((a != 0) and (c != null));
\\ var j: c_int = @boolToInt((a != 0) or (c != null)); \\ var h: c_int = @boolToInt((a != 0) or (b != 0));
\\ var k: c_int = @boolToInt((a != 0) or (@bitCast(c_int, @enumToInt(d)) != 0)); \\ var i: c_int = @boolToInt((b != 0) or (c != null));
\\ var l: c_int = @boolToInt((@bitCast(c_int, @enumToInt(d)) != 0) and (b != 0)); \\ var j: c_int = @boolToInt((a != 0) or (c != null));
\\ var m: c_int = @boolToInt((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0)); \\ var k: c_int = @boolToInt((a != 0) or (@bitCast(c_int, @enumToInt(d)) != 0));
\\ var td: SomeTypedef = 44; \\ var l: c_int = @boolToInt((@bitCast(c_int, @enumToInt(d)) != 0) and (b != 0));
\\ var o: c_int = @boolToInt((td != 0) or (b != 0)); \\ var m: c_int = @boolToInt((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0));
\\ var p: c_int = @boolToInt((c != null) and (td != 0)); \\ var td: SomeTypedef = 44;
\\ return (((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p; \\ 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; \\pub const Foo = enum_Foo;
}); });
@ -2387,14 +2407,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ y: c_int, \\ y: c_int,
\\}; \\};
, ,
\\pub const enum_Bar = extern enum(c_int) { \\pub const enum_Bar = extern enum(
\\ A, ++ default_enum_type ++
\\ B, \\) {
\\ _, \\ 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 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 Foo = struct_Foo;
\\pub const Bar = enum_Bar; \\pub const Bar = enum_Bar;
@ -2664,26 +2686,28 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return 4; \\ return 4;
\\} \\}
, &[_][]const u8{ , &[_][]const u8{
\\pub const enum_SomeEnum = extern enum(c_int) { \\pub const enum_SomeEnum = extern enum(
\\ A, ++ default_enum_type ++
\\ B, \\) {
\\ C, \\ 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 const A = @enumToInt(enum_SomeEnum.A);
\\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int { \\pub const B = @enumToInt(enum_SomeEnum.B);
\\ var a = arg_a; \\pub const C = @enumToInt(enum_SomeEnum.C);
\\ var b = arg_b; \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {
\\ var c = arg_c; \\ var a = arg_a;
\\ var d = arg_d; \\ var b = arg_b;
\\ if (a != 0) return 0; \\ var c = arg_c;
\\ if (b != 0) return 1; \\ var d = arg_d;
\\ if (c != null) return 2; \\ if (a != 0) return 0;
\\ if (@enumToInt(d) != 0) return 3; \\ if (b != 0) return 1;
\\ return 4; \\ if (c != null) return 2;
\\} \\ if (@enumToInt(d) != 0) return 3;
\\ return 4;
\\}
}); });
cases.add("simple data types", cases.add("simple data types",
@ -3130,15 +3154,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ Foo1, \\ Foo1,
\\}; \\};
, &[_][]const u8{ , &[_][]const u8{
\\pub const enum_Foo = extern enum(c_int) { \\pub const enum_Foo = extern enum(
\\ A = 2, ++ default_enum_type ++
\\ B = 5, \\) {
\\ @"1" = 6, \\ 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 FooA = @enumToInt(enum_Foo.A);
\\pub const FooB = @enumToInt(enum_Foo.B);
\\pub const Foo1 = @enumToInt(enum_Foo.@"1");
, ,
\\pub const Foo = enum_Foo; \\pub const Foo = enum_Foo;
}); });