Skip to content

Commit

Permalink
translate-c: Declare type of enum constants
Browse files Browse the repository at this point in the history
If the enum type cannot be translated for some reason, omit it. In that
case the previous behavior will occur - the enum constant's type will be
the enum's tag type.

Fixes #9153
  • Loading branch information
ehaas committed Jun 19, 2021
1 parent e006281 commit 832a6ee
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 35 deletions.
9 changes: 9 additions & 0 deletions src/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1158,12 +1158,20 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
.value = int_node,
});

const enum_const_qt = @ptrCast(*const clang.ValueDecl, enum_const).getType();
const enum_const_loc = @ptrCast(*const clang.Decl, enum_const).getLocation();
const enum_const_type_node: ?Node = transQualType(c, scope, enum_const_qt, enum_const_loc) catch |err| switch (err) {
error.UnsupportedType => null,
else => |e| return e,
};

// In C each enum value is in the global namespace. So we put them there too.
// At this point we can rely on the enum emitting successfully.
try redecls.append(.{
.enum_val_name = enum_val_name,
.field_name = field_name,
.enum_name = name,
.type = enum_const_type_node,
});
}

Expand Down Expand Up @@ -1201,6 +1209,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
.enum_val_name = try bs.makeMangledName(c, redecl.enum_val_name),
.field_name = redecl.field_name,
.enum_name = redecl.enum_name,
.type = redecl.type,
}));
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/translate_c/ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@ pub const Payload = struct {
enum_val_name: []const u8,
field_name: []const u8,
enum_name: []const u8,
type: ?Node,
},
};

Expand Down Expand Up @@ -1873,6 +1874,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
if (node.tag() == .pub_enum_redecl) _ = try c.addToken(.keyword_pub, "pub");
const const_tok = try c.addToken(.keyword_const, "const");
_ = try c.addIdentifier(payload.enum_val_name);
const type_node = if (payload.type) |enum_const_type| blk: {
_ = try c.addToken(.colon, ":");
break :blk try renderNode(c, enum_const_type);
} else 0;

_ = try c.addToken(.equal, "=");

const enum_to_int_tok = try c.addToken(.builtin, "@enumToInt");
Expand All @@ -1898,7 +1904,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
.tag = .simple_var_decl,
.main_token = const_tok,
.data = .{
.lhs = 0,
.lhs = type_node,
.rhs = init_node,
},
});
Expand Down
16 changes: 16 additions & 0 deletions test/run_translated_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1598,4 +1598,20 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");

cases.add("Enum constants are assigned correct type. Issue #9153",
\\enum A { A0, A1=0xFFFFFFFF };
\\enum B { B0=-1, B1=0xFFFFFFFF };
\\enum C { C0=-1, C1=0 };
\\enum D { D0, D1=0xFFFFFFFFFFL };
\\enum E { E0=-1, E1=0xFFFFFFFFFFL };
\\int main(void) {
\\ signed char a0 = A0, a1 = A1;
\\ signed char b0 = B0, b1 = B1;
\\ signed char c0 = C0, c1 = C1;
\\ signed char d0 = D0, d1 = D1;
\\ signed char e0 = E0, e1 = E1;
\\ return 0;
\\}
, "");
}
68 changes: 34 additions & 34 deletions test/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ B,
\\ _,
\\};
\\pub const FooA = @enumToInt(Foo.A);
\\pub const FooB = @enumToInt(Foo.B);
\\pub const FooA: c_int = @enumToInt(Foo.A);
\\pub const FooB: c_int = @enumToInt(Foo.B);
\\pub const Bar = extern struct {
\\ a: c_int,
\\ b: c_int,
Expand Down Expand Up @@ -130,9 +130,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ C,
\\ _,
\\ };
\\ const A = @enumToInt(enum_Foo.A);
\\ const B = @enumToInt(enum_Foo.B);
\\ const C = @enumToInt(enum_Foo.C);
\\ const A: c_int = @enumToInt(enum_Foo.A);
\\ const B: c_int = @enumToInt(enum_Foo.B);
\\ const C: c_int = @enumToInt(enum_Foo.C);
\\ var a: enum_Foo = @import("std").zig.c_translation.cast(enum_Foo, B);
\\ {
\\ const enum_Foo = extern enum(
Expand All @@ -143,9 +143,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ C,
\\ _,
\\ };
\\ const A_2 = @enumToInt(enum_Foo.A);
\\ const B_3 = @enumToInt(enum_Foo.B);
\\ const C_4 = @enumToInt(enum_Foo.C);
\\ const A_2: c_int = @enumToInt(enum_Foo.A);
\\ const B_3: c_int = @enumToInt(enum_Foo.B);
\\ const C_4: c_int = @enumToInt(enum_Foo.C);
\\ var a_5: enum_Foo = @import("std").zig.c_translation.cast(enum_Foo, B_3);
\\ }
\\}
Expand Down Expand Up @@ -1595,7 +1595,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ FOO,
\\ _,
\\};
\\pub const FOO = @enumToInt(enum_enum_ty.FOO);
\\pub const FOO: c_int = @enumToInt(enum_enum_ty.FOO);
\\pub extern var my_enum: enum_enum_ty;
});

Expand Down Expand Up @@ -1724,9 +1724,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ c,
\\ _,
\\};
\\pub const a = @enumToInt(d.a);
\\pub const b = @enumToInt(d.b);
\\pub const c = @enumToInt(d.c);
\\pub const a: c_int = @enumToInt(d.a);
\\pub const b: c_int = @enumToInt(d.b);
\\pub const c: c_int = @enumToInt(d.c);
\\const enum_unnamed_1 = extern enum(
++ default_enum_type ++
\\) {
Expand All @@ -1735,9 +1735,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ 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 const e: c_int = @enumToInt(enum_unnamed_1.e);
\\pub const f: c_int = @enumToInt(enum_unnamed_1.f);
\\pub const g: c_int = @enumToInt(enum_unnamed_1.g);
\\pub export var h: enum_unnamed_1 = @import("std").zig.c_translation.cast(enum_unnamed_1, e);
\\const enum_unnamed_2 = extern enum(
++ default_enum_type ++
Expand All @@ -1747,9 +1747,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ 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 i: c_int = @enumToInt(enum_unnamed_2.i);
\\pub const j: c_int = @enumToInt(enum_unnamed_2.j);
\\pub const k: c_int = @enumToInt(enum_unnamed_2.k);
\\pub const struct_Baz = extern struct {
\\ l: enum_unnamed_2,
\\ m: d,
Expand All @@ -1762,9 +1762,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ p,
\\ _,
\\};
\\pub const n = @enumToInt(enum_i.n);
\\pub const o = @enumToInt(enum_i.o);
\\pub const p = @enumToInt(enum_i.p);
\\pub const n: c_int = @enumToInt(enum_i.n);
\\pub const o: c_int = @enumToInt(enum_i.o);
\\pub const p: c_int = @enumToInt(enum_i.p);
,
\\pub const Baz = struct_Baz;
});
Expand Down Expand Up @@ -2264,8 +2264,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ Two,
\\ _,
\\};
\\pub const One = @enumToInt(enum_unnamed_1.One);
\\pub const Two = @enumToInt(enum_unnamed_1.Two);
\\pub const One: c_int = @enumToInt(enum_unnamed_1.One);
\\pub const Two: c_int = @enumToInt(enum_unnamed_1.Two);
});

cases.add("c style cast",
Expand Down Expand Up @@ -2371,9 +2371,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ 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: c_int = @enumToInt(enum_Foo.A);
\\pub const FooB: c_int = @enumToInt(enum_Foo.B);
\\pub const FooC: c_int = @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;
Expand Down Expand Up @@ -2421,8 +2421,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ B,
\\ _,
\\};
\\pub const BarA = @enumToInt(enum_Bar.A);
\\pub const BarB = @enumToInt(enum_Bar.B);
\\pub const BarA: c_int = @enumToInt(enum_Bar.A);
\\pub const BarB: c_int = @enumToInt(enum_Bar.B);
\\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
,
\\pub const Foo = struct_Foo;
Expand Down Expand Up @@ -2701,9 +2701,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ 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: c_int = @enumToInt(enum_SomeEnum.A);
\\pub const B: c_int = @enumToInt(enum_SomeEnum.B);
\\pub const C: c_int = @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;
Expand Down Expand Up @@ -3169,9 +3169,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ @"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: c_int = @enumToInt(enum_Foo.A);
\\pub const FooB: c_int = @enumToInt(enum_Foo.B);
\\pub const Foo1: c_int = @enumToInt(enum_Foo.@"1");
,
\\pub const Foo = enum_Foo;
});
Expand Down

0 comments on commit 832a6ee

Please sign in to comment.