Commit 0e7897a9a2

Evan Haas <evan@lagerdata.com>
2021-06-19 02:36:50
translate-c: Remove usage of `extern enum`
Translate enum types as the underlying integer type. Translate enum constants as top-level integer constants of the correct type (which does not necessarily match the enum integer type). If an enum constant's type cannot be translated for some reason, omit it. See discussion https://github.com/ziglang/zig/issues/2115#issuecomment-827968279 Fixes #9153
1 parent d1f99ea
lib/std/zig/c_translation.zig
@@ -11,7 +11,7 @@ const mem = std.mem;
 
 /// Given a type and value, cast the value to the type as c would.
 pub fn cast(comptime DestType: type, target: anytype) DestType {
-    // this function should behave like transCCast in translate-c, except it's for macros and enums
+    // this function should behave like transCCast in translate-c, except it's for macros
     const SourceType = @TypeOf(target);
     switch (@typeInfo(DestType)) {
         .Fn, .Pointer => return castToPtr(DestType, SourceType, target),
@@ -20,12 +20,6 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
                 return castToPtr(DestType, SourceType, target);
             }
         },
-        .Enum => |enum_type| {
-            if (@typeInfo(SourceType) == .Int or @typeInfo(SourceType) == .ComptimeInt) {
-                const intermediate = cast(enum_type.tag_type, target);
-                return @intToEnum(DestType, intermediate);
-            }
-        },
         .Int => {
             switch (@typeInfo(SourceType)) {
                 .Pointer => {
@@ -36,9 +30,6 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
                         return castInt(DestType, @ptrToInt(target));
                     }
                 },
-                .Enum => {
-                    return castInt(DestType, @enumToInt(target));
-                },
                 .Int => {
                     return castInt(DestType, target);
                 },
@@ -106,12 +97,6 @@ fn ptrInfo(comptime PtrType: type) std.builtin.TypeInfo.Pointer {
 }
 
 test "cast" {
-    const E = enum(u2) {
-        Zero,
-        One,
-        Two,
-    };
-
     var i = @as(i64, 10);
 
     try testing.expect(cast(*u8, 16) == @intToPtr(*u8, 16));
@@ -122,12 +107,9 @@ test "cast" {
     try testing.expect(cast(?*i64, @as(*align(1) i64, &i)) == &i);
     try testing.expect(cast(?*i64, @as(?*align(1) i64, &i)) == &i);
 
-    try testing.expect(cast(E, 1) == .One);
-
     try testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(*u32, 4)));
     try testing.expectEqual(@as(u32, 4), cast(u32, @intToPtr(?*u32, 4)));
     try testing.expectEqual(@as(u32, 10), cast(u32, @as(u64, 10)));
-    try testing.expectEqual(@as(u8, 2), cast(u8, E.Two));
 
     try testing.expectEqual(@bitCast(i32, @as(u32, 0x8000_0000)), cast(i32, @as(u32, 0x8000_0000)));
 
@@ -136,17 +118,6 @@ test "cast" {
 
     try testing.expectEqual(@intToPtr(?*c_void, 2), cast(?*c_void, @intToPtr(*u8, 2)));
 
-    const C_ENUM = enum(c_int) {
-        A = 0,
-        B,
-        C,
-        _,
-    };
-    try testing.expectEqual(cast(C_ENUM, @as(i64, -1)), @intToEnum(C_ENUM, -1));
-    try testing.expectEqual(cast(C_ENUM, @as(i8, 1)), .B);
-    try testing.expectEqual(cast(C_ENUM, @as(u64, 1)), .B);
-    try testing.expectEqual(cast(C_ENUM, @as(u64, 42)), @intToEnum(C_ENUM, 42));
-
     var foo: c_int = -1;
     try testing.expect(cast(*c_void, -1) == @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))));
     try testing.expect(cast(*c_void, foo) == @intToPtr(*c_void, @bitCast(usize, @as(isize, -1))));
@@ -162,7 +133,7 @@ test "cast" {
 pub fn sizeof(target: anytype) usize {
     const T: type = if (@TypeOf(target) == type) target else @TypeOf(target);
     switch (@typeInfo(T)) {
-        .Float, .Int, .Struct, .Union, .Enum, .Array, .Bool, .Vector => return @sizeOf(T),
+        .Float, .Int, .Struct, .Union, .Array, .Bool, .Vector => return @sizeOf(T),
         .Fn => {
             // sizeof(main) returns 1, sizeof(&main) returns pointer size.
             // We cannot distinguish those types in Zig, so use pointer size.
@@ -228,7 +199,6 @@ pub fn sizeof(target: anytype) usize {
 }
 
 test "sizeof" {
-    const E = enum(c_int) { One, _ };
     const S = extern struct { a: u32 };
 
     const ptr_size = @sizeOf(*c_void);
@@ -239,9 +209,6 @@ test "sizeof" {
 
     try testing.expect(sizeof(2.0) == @sizeOf(f64));
 
-    try testing.expect(sizeof(E) == @sizeOf(c_int));
-    try testing.expect(sizeof(E.One) == @sizeOf(c_int));
-
     try testing.expect(sizeof(S) == 4);
 
     try testing.expect(sizeof([_]u32{ 4, 5, 6 }) == 12);
src/translate_c/ast.zig
@@ -64,8 +64,6 @@ pub const Node = extern union {
         static_local_var,
         func,
         warning,
-        /// All enums are non-exhaustive
-        @"enum",
         @"struct",
         @"union",
         @"comptime",
@@ -146,10 +144,6 @@ pub const Node = extern union {
         float_to_int,
         /// @intToFloat(lhs, rhs)
         int_to_float,
-        /// @intToEnum(lhs, rhs)
-        int_to_enum,
-        /// @enumToInt(operand)
-        enum_to_int,
         /// @intToPtr(lhs, rhs)
         int_to_ptr,
         /// @ptrToInt(operand)
@@ -215,9 +209,8 @@ pub const Node = extern union {
         var_simple,
         /// pub const name = init;
         pub_var_simple,
-        /// pub const enum_field_name = @enumToInt(enum_name.field_name);
-        pub_enum_redecl,
-        enum_redecl,
+        /// pub? const name (: type)? = value
+        enum_constant,
 
         /// pub inline fn name(params) return_type body
         pub_inline_fn,
@@ -266,7 +259,6 @@ pub const Node = extern union {
                 .unwrap,
                 .deref,
                 .ptr_to_int,
-                .enum_to_int,
                 .empty_array,
                 .while_true,
                 .if_not_break,
@@ -324,7 +316,6 @@ pub const Node = extern union {
                 .float_cast,
                 .float_to_int,
                 .int_to_float,
-                .int_to_enum,
                 .int_to_ptr,
                 .array_cat,
                 .ellipsis3,
@@ -357,7 +348,6 @@ pub const Node = extern union {
                 .call => Payload.Call,
                 .var_decl => Payload.VarDecl,
                 .func => Payload.Func,
-                .@"enum" => Payload.Enum,
                 .@"struct", .@"union" => Payload.Record,
                 .tuple => Payload.TupleInit,
                 .container_init => Payload.ContainerInit,
@@ -369,7 +359,7 @@ pub const Node = extern union {
                 .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl,
                 .log2_int_type => Payload.Log2IntType,
                 .var_simple, .pub_var_simple, .static_local_var => Payload.SimpleVarDecl,
-                .pub_enum_redecl, .enum_redecl => Payload.EnumRedecl,
+                .enum_constant => Payload.EnumConstant,
                 .array_filler => Payload.ArrayFiller,
                 .pub_inline_fn => Payload.PubInlineFn,
                 .field_access => Payload.FieldAccess,
@@ -554,19 +544,6 @@ pub const Payload = struct {
         type: Node,
     };
 
-    pub const Enum = struct {
-        base: Payload,
-        data: struct {
-            int_type: Node,
-            fields: []Field,
-        },
-
-        pub const Field = struct {
-            name: []const u8,
-            value: ?Node,
-        };
-    };
-
     pub const Record = struct {
         base: Payload,
         data: struct {
@@ -658,12 +635,13 @@ pub const Payload = struct {
         },
     };
 
-    pub const EnumRedecl = struct {
+    pub const EnumConstant = struct {
         base: Payload,
         data: struct {
-            enum_val_name: []const u8,
-            field_name: []const u8,
-            enum_name: []const u8,
+            name: []const u8,
+            is_public: bool,
+            type: ?Node,
+            value: Node,
         },
     };
 
@@ -1307,14 +1285,6 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             const payload = node.castTag(.int_to_float).?.data;
             return renderBuiltinCall(c, "@intToFloat", &.{ payload.lhs, payload.rhs });
         },
-        .int_to_enum => {
-            const payload = node.castTag(.int_to_enum).?.data;
-            return renderBuiltinCall(c, "@intToEnum", &.{ payload.lhs, payload.rhs });
-        },
-        .enum_to_int => {
-            const payload = node.castTag(.enum_to_int).?.data;
-            return renderBuiltinCall(c, "@enumToInt", &.{payload});
-        },
         .int_to_ptr => {
             const payload = node.castTag(.int_to_ptr).?.data;
             return renderBuiltinCall(c, "@intToPtr", &.{ payload.lhs, payload.rhs });
@@ -1814,91 +1784,28 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             return renderFieldAccess(c, lhs, payload.field_name);
         },
         .@"struct", .@"union" => return renderRecord(c, node),
-        .@"enum" => {
-            const payload = node.castTag(.@"enum").?.data;
-            _ = try c.addToken(.keyword_extern, "extern");
-            const enum_tok = try c.addToken(.keyword_enum, "enum");
-            _ = try c.addToken(.l_paren, "(");
-            const arg_expr = try renderNode(c, payload.int_type);
-            _ = try c.addToken(.r_paren, ")");
-            _ = try c.addToken(.l_brace, "{");
-            const members = try c.gpa.alloc(NodeIndex, payload.fields.len + 1);
-            defer c.gpa.free(members);
-            members[0] = 0;
-
-            for (payload.fields) |field, i| {
-                const name_tok = try c.addIdentifier(field.name);
-                const value_expr = if (field.value) |some| blk: {
-                    _ = try c.addToken(.equal, "=");
-                    break :blk try renderNode(c, some);
-                } else 0;
-
-                members[i] = try c.addNode(.{
-                    .tag = .container_field_init,
-                    .main_token = name_tok,
-                    .data = .{
-                        .lhs = 0,
-                        .rhs = value_expr,
-                    },
-                });
-                _ = try c.addToken(.comma, ",");
-            }
-            // make non-exhaustive
-            members[payload.fields.len] = try c.addNode(.{
-                .tag = .container_field_init,
-                .main_token = try c.addIdentifier("_"),
-                .data = .{
-                    .lhs = 0,
-                    .rhs = 0,
-                },
-            });
-            _ = try c.addToken(.comma, ",");
-            _ = try c.addToken(.r_brace, "}");
+        .enum_constant => {
+            const payload = node.castTag(.enum_constant).?.data;
 
-            const span = try c.listToSpan(members);
-            return c.addNode(.{
-                .tag = .container_decl_arg_trailing,
-                .main_token = enum_tok,
-                .data = .{
-                    .lhs = arg_expr,
-                    .rhs = try c.addExtra(NodeSubRange{
-                        .start = span.start,
-                        .end = span.end,
-                    }),
-                },
-            });
-        },
-        .pub_enum_redecl, .enum_redecl => {
-            const payload = @fieldParentPtr(Payload.EnumRedecl, "base", node.ptr_otherwise).data;
-            if (node.tag() == .pub_enum_redecl) _ = try c.addToken(.keyword_pub, "pub");
+            if (payload.is_public) _ = try c.addToken(.keyword_pub, "pub");
             const const_tok = try c.addToken(.keyword_const, "const");
-            _ = try c.addIdentifier(payload.enum_val_name);
+            _ = try c.addIdentifier(payload.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");
-            _ = try c.addToken(.l_paren, "(");
-            const enum_name = try c.addNode(.{
-                .tag = .identifier,
-                .main_token = try c.addIdentifier(payload.enum_name),
-                .data = undefined,
-            });
-            const field_access = try renderFieldAccess(c, enum_name, payload.field_name);
-            const init_node = try c.addNode(.{
-                .tag = .builtin_call_two,
-                .main_token = enum_to_int_tok,
-                .data = .{
-                    .lhs = field_access,
-                    .rhs = 0,
-                },
-            });
-            _ = try c.addToken(.r_paren, ")");
+            const init_node = try renderNode(c, payload.value);
             _ = try c.addToken(.semicolon, ";");
 
             return c.addNode(.{
                 .tag = .simple_var_decl,
                 .main_token = const_tok,
                 .data = .{
-                    .lhs = 0,
+                    .lhs = type_node,
                     .rhs = init_node,
                 },
             });
@@ -2210,7 +2117,7 @@ fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIn
 fn addSemicolonIfNeeded(c: *Context, node: Node) !void {
     switch (node.tag()) {
         .warning => unreachable,
-        .var_decl, .var_simple, .arg_redecl, .alias, .enum_redecl, .block, .empty_block, .block_single, .@"switch" => {},
+        .var_decl, .var_simple, .arg_redecl, .alias, .block, .empty_block, .block_single, .@"switch" => {},
         .while_true => {
             const payload = node.castTag(.while_true).?.data;
             return addSemicolonIfNotBlock(c, payload);
@@ -2258,13 +2165,11 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .float_cast,
         .float_to_int,
         .int_to_float,
-        .int_to_enum,
         .int_to_ptr,
         .std_mem_zeroes,
         .std_math_Log2Int,
         .log2_int_type,
         .ptr_to_int,
-        .enum_to_int,
         .sizeof,
         .alignof,
         .typeof,
@@ -2340,7 +2245,6 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .array_cat,
         .array_filler,
         .@"if",
-        .@"enum",
         .@"struct",
         .@"union",
         .array_init,
@@ -2366,8 +2270,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .alias,
         .var_simple,
         .pub_var_simple,
-        .pub_enum_redecl,
-        .enum_redecl,
+        .enum_constant,
         .@"while",
         .@"switch",
         .@"break",
src/clang.zig
@@ -389,9 +389,6 @@ pub const ElaboratedType = opaque {
 };
 
 pub const EnumConstantDecl = opaque {
-    pub const getInitExpr = ZigClangEnumConstantDecl_getInitExpr;
-    extern fn ZigClangEnumConstantDecl_getInitExpr(*const EnumConstantDecl) ?*const Expr;
-
     pub const getInitVal = ZigClangEnumConstantDecl_getInitVal;
     extern fn ZigClangEnumConstantDecl_getInitVal(*const EnumConstantDecl) *const APSInt;
 };
src/translate_c.zig
@@ -1100,27 +1100,37 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
         }
         name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
     }
-    if (!toplevel) _ = try bs.makeMangledName(c, name);
+    if (!toplevel) name = try bs.makeMangledName(c, name);
     try c.decl_table.putNoClobber(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);
 
-    const is_pub = toplevel and !is_unnamed;
-    var redecls = std.ArrayList(Tag.enum_redecl.Data()).init(c.gpa);
-    defer redecls.deinit();
-
-    const init_node = if (enum_decl.getDefinition()) |enum_def| blk: {
-        var pure_enum = true;
+    const enum_type_node = if (enum_decl.getDefinition()) |enum_def| blk: {
         var it = enum_def.enumerator_begin();
-        var end_it = enum_def.enumerator_end();
+        const end_it = enum_def.enumerator_end();
         while (it.neq(end_it)) : (it = it.next()) {
             const enum_const = it.deref();
-            if (enum_const.getInitExpr()) |_| {
-                pure_enum = false;
-                break;
+            var enum_val_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, enum_const).getName_bytes_begin());
+            if (!toplevel) {
+                enum_val_name = try bs.makeMangledName(c, enum_val_name);
             }
-        }
 
-        var fields = std.ArrayList(ast.Payload.Enum.Field).init(c.gpa);
-        defer fields.deinit();
+            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,
+            };
+
+            const enum_const_def = try Tag.enum_constant.create(c.arena, .{
+                .name = enum_val_name,
+                .is_public = toplevel,
+                .type = enum_const_type_node,
+                .value = try transCreateNodeAPInt(c, enum_const.getInitVal()),
+            });
+            if (toplevel)
+                try addTopLevelDecl(c, enum_val_name, enum_const_def)
+            else
+                try scope.appendNode(enum_const_def);
+        }
 
         const int_type = enum_decl.getIntegerType();
         // The underlying type may be null in case of forward-declared enum
@@ -1128,61 +1138,27 @@ 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)
+        break :blk 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", .{});
+                    return failDecl(c, enum_loc, name, "unable to translate enum integer type", .{});
                 },
                 else => |e| return e,
             }
         else
             try Tag.type.create(c.arena, "c_int");
-
-        it = enum_def.enumerator_begin();
-        end_it = enum_def.enumerator_end();
-        while (it.neq(end_it)) : (it = it.next()) {
-            const enum_const = it.deref();
-            const enum_val_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_const).getName_bytes_begin());
-
-            const field_name = if (!is_unnamed and mem.startsWith(u8, enum_val_name, bare_name))
-                enum_val_name[bare_name.len..]
-            else
-                enum_val_name;
-
-            const int_node = if (!pure_enum)
-                try transCreateNodeAPInt(c, enum_const.getInitVal())
-            else
-                null;
-
-            try fields.append(.{
-                .name = field_name,
-                .value = int_node,
-            });
-
-            // 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,
-            });
-        }
-
-        break :blk try Tag.@"enum".create(c.arena, .{
-            .int_type = init_arg_expr,
-            .fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items),
-        });
     } else blk: {
         try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});
         break :blk Tag.opaque_literal.init();
     };
 
+    const is_pub = toplevel and !is_unnamed;
     const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
     payload.* = .{
         .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
         .data = .{
+            .init = enum_type_node,
             .name = name,
-            .init = init_node,
         },
     };
 
@@ -1193,18 +1169,6 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
     } else {
         try scope.appendNode(Node.initPayload(&payload.base));
     }
-
-    for (redecls.items) |redecl| {
-        if (toplevel) {
-            try addTopLevelDecl(c, redecl.field_name, try Tag.pub_enum_redecl.create(c.arena, redecl));
-        } else {
-            try scope.appendNode(try Tag.enum_redecl.create(c.arena, .{
-                .enum_val_name = try bs.makeMangledName(c, redecl.enum_val_name),
-                .field_name = redecl.field_name,
-                .enum_name = redecl.enum_name,
-            }));
-        }
-    }
 }
 
 const ResultUsed = enum {
@@ -2098,8 +2062,7 @@ fn finishBoolExpr(
         },
         .Enum => {
             // node != 0
-            const int_val = try Tag.enum_to_int.create(c.arena, node);
-            return Tag.not_equal.create(c.arena, .{ .lhs = int_val, .rhs = Tag.zero_literal.init() });
+            return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
         },
         .Elaborated => {
             const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);
@@ -2312,21 +2275,22 @@ fn transCCast(
     if (dst_type.eq(src_type)) return expr;
     if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
         return transCPtrCast(c, scope, loc, dst_type, src_type, expr);
+    if (cIsEnum(dst_type)) return transCCast(c, scope, loc, cIntTypeForEnum(dst_type), src_type, expr);
+    if (cIsEnum(src_type)) return transCCast(c, scope, loc, dst_type, cIntTypeForEnum(src_type), expr);
 
     const dst_node = try transQualType(c, scope, dst_type, loc);
-    if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {
+    if (cIsInteger(dst_type) and cIsInteger(src_type)) {
         // 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_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);
+        const src_type_is_signed = cIsSignedInteger(src_type);
+        var src_int_expr = expr;
 
         if (isBoolRes(src_int_expr)) {
             src_int_expr = try Tag.bool_to_int.create(c.arena, src_int_expr);
         }
 
-        switch (cIntTypeCmp(dst_type, src_int_type)) {
+        switch (cIntTypeCmp(dst_type, src_type)) {
             .lt => {
                 // @truncate(SameSignSmallerInt, src_int_expr)
                 const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed);
@@ -2379,14 +2343,6 @@ fn transCCast(
         const bool_to_int = try Tag.bool_to_int.create(c.arena, expr);
         return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int });
     }
-    if (cIsEnum(dst_type)) {
-        // import("std").meta.cast(dest_type, val)
-        return Tag.helpers_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
-    }
-    if (cIsEnum(src_type) and !cIsEnum(dst_type)) {
-        // @enumToInt(val)
-        return Tag.enum_to_int.create(c.arena, expr);
-    }
     // @as(dest_type, val)
     return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
 }
@@ -5975,7 +5931,6 @@ fn getContainer(c: *Context, node: Node) ?Node {
     switch (node.tag()) {
         .@"union",
         .@"struct",
-        .@"enum",
         .address_of,
         .bit_not,
         .not,
src/zig_clang.cpp
@@ -3228,12 +3228,6 @@ bool ZigClangEnumDecl_enumerator_iterator_neq(
     return casted_a != casted_b;
 }
 
-const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *self) {
-    auto casted = reinterpret_cast<const clang::EnumConstantDecl *>(self);
-    const clang::Expr *result = casted->getInitExpr();
-    return reinterpret_cast<const ZigClangExpr *>(result);
-}
-
 const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *self) {
     auto casted = reinterpret_cast<const clang::EnumConstantDecl *>(self);
     const llvm::APSInt *result = &casted->getInitVal();
src/zig_clang.h
@@ -1326,6 +1326,5 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const s
 ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *);
 ZIG_EXTERN_C unsigned ZigClangFieldDecl_getFieldIndex(const struct ZigClangFieldDecl *);
 
-ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *);
 ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *);
 #endif
test/run_translated_c.zig
@@ -1598,4 +1598,53 @@ 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;
+        \\}
+    , "");
+
+    cases.add("Enum constant matches enum name; multiple enumerations with same value",
+        \\#include <stdlib.h>
+        \\enum FOO {
+        \\    FOO = 1,
+        \\    BAR = 2,
+        \\    BAZ = 1,
+        \\};
+        \\int main(void) {
+        \\    enum FOO x = BAZ;
+        \\    if (x != 1) abort();
+        \\    if (x != BAZ) abort();
+        \\    if (x != FOO) abort();
+        \\}
+    , "");
+
+    cases.add("Scoped enums",
+        \\#include <stdlib.h>
+        \\int main(void) {
+        \\   enum Foo { A, B, C };
+        \\   enum Foo a = B;
+        \\   if (a != B) abort();
+        \\   if (a != 1) abort();
+        \\   {
+        \\      enum Foo { A = 5, B = 6, C = 7 };
+        \\      enum Foo a = B;
+        \\      if (a != B) abort();
+        \\      if (a != 6) abort();
+        \\   }
+        \\   if (a != B) abort();
+        \\   if (a != 1) abort();
+        \\}
+    , "");
 }
test/translate_c.zig
@@ -30,15 +30,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    int a, b;
         \\} Bar;
     , &[_][]const u8{
-        \\pub const Foo = extern enum(
-        ++ default_enum_type ++
-            \\) {
-            \\    A,
-            \\    B,
-            \\    _,
-            \\};
-            \\pub const FooA = @enumToInt(Foo.A);
-            \\pub const FooB = @enumToInt(Foo.B);
+        \\pub const FooA: c_int = 0;
+        \\pub const FooB: c_int = 1;
+        \\pub const Foo =
+        ++ " " ++ default_enum_type ++
+            \\;
             \\pub const Bar = extern struct {
             \\    a: c_int,
             \\    b: c_int,
@@ -103,54 +99,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const PTR = ?*c_void;
     });
 
-    cases.add("scoped enum",
-        \\void foo() {
-        \\	enum Foo {
-        \\		A,
-        \\		B,
-        \\		C,
-        \\	};
-        \\	enum Foo a = B;
-        \\	{
-        \\		enum Foo {
-        \\			A,
-        \\			B,
-        \\			C,
-        \\		};
-        \\		enum Foo a = B;
-        \\	}
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo() void {
-        \\    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").zig.c_translation.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").zig.c_translation.cast(enum_Foo, B_3);
-            \\    }
-            \\}
-    });
-
     cases.add("scoped record",
         \\void foo() {
         \\	struct Foo {
@@ -1208,32 +1156,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
             \\    VAL23 = 0xFFFFFFFFFFFFFFFF,
             \\};
         , &[_][]const u8{
-            \\pub const enum_EnumWithInits = extern enum(c_longlong) {
-            \\    VAL01 = 0,
-            \\    VAL02 = 1,
-            \\    VAL03 = 2,
-            \\    VAL04 = 3,
-            \\    VAL05 = -1,
-            \\    VAL06 = -2,
-            \\    VAL07 = -3,
-            \\    VAL08 = -4,
-            \\    VAL09 = -3,
-            \\    VAL10 = -1000012000,
-            \\    VAL11 = -1000161000,
-            \\    VAL12 = -1000174001,
-            \\    VAL13 = -3,
-            \\    VAL14 = -1000012000,
-            \\    VAL15 = -1000161000,
-            \\    VAL16 = -3,
-            \\    VAL17 = 1000011998,
-            \\    VAL18 = 1152921504606846976,
-            \\    VAL19 = 3458764513820540927,
-            \\    VAL20 = 6917529027641081854,
-            \\    VAL21 = 6917529027641081853,
-            \\    VAL22 = 0,
-            \\    VAL23 = -1,
-            \\    _,
-            \\};
+            \\pub const VAL01: c_int = 0;
+            \\pub const VAL02: c_int = 1;
+            \\pub const VAL03: c_int = 2;
+            \\pub const VAL04: c_int = 3;
+            \\pub const VAL05: c_int = -1;
+            \\pub const VAL06: c_int = -2;
+            \\pub const VAL07: c_int = -3;
+            \\pub const VAL08: c_int = -4;
+            \\pub const VAL09: c_int = -3;
+            \\pub const VAL10: c_int = -1000012000;
+            \\pub const VAL11: c_int = -1000161000;
+            \\pub const VAL12: c_int = -1000174001;
+            \\pub const VAL13: c_int = -3;
+            \\pub const VAL14: c_int = -1000012000;
+            \\pub const VAL15: c_int = -1000161000;
+            \\pub const VAL16: c_int = -3;
+            \\pub const VAL17: c_int = 1000011998;
+            \\pub const VAL18: c_longlong = 1152921504606846976;
+            \\pub const VAL19: c_longlong = 3458764513820540927;
+            \\pub const VAL20: c_longlong = 6917529027641081854;
+            \\pub const VAL21: c_longlong = 6917529027641081853;
+            \\pub const VAL22: c_int = 0;
+            \\pub const VAL23: c_longlong = -1;
+            \\pub const enum_EnumWithInits = c_longlong;
         });
     }
 
@@ -1591,11 +1537,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\extern enum enum_ty my_enum;
         \\enum enum_ty { FOO };
     , &[_][]const u8{
-        \\pub const enum_enum_ty = extern enum(c_int) {
-        \\    FOO,
-        \\    _,
-        \\};
-        \\pub const FOO = @enumToInt(enum_enum_ty.FOO);
+        \\pub const FOO: c_int = 0;
+        \\pub const enum_enum_ty = c_int;
         \\pub extern var my_enum: enum_enum_ty;
     });
 
@@ -1716,57 +1659,37 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    p,
         \\};
     , &[_][]const u8{
-        \\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").zig.c_translation.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 a: c_int = 0;
+        \\pub const b: c_int = 1;
+        \\pub const c: c_int = 2;
+        \\pub const d =
+        ++ " " ++ default_enum_type ++
+            \\;
+            \\pub const e: c_int = 0;
+            \\pub const f: c_int = 4;
+            \\pub const g: c_int = 5;
+            \\const enum_unnamed_1 =
+        ++ " " ++ default_enum_type ++
+            \\;
+            \\pub export var h: enum_unnamed_1 = @bitCast(c_uint, e);
+            \\pub const i: c_int = 0;
+            \\pub const j: c_int = 1;
+            \\pub const k: c_int = 2;
+            \\const enum_unnamed_2 =
+        ++ " " ++ default_enum_type ++
+            \\;
             \\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 n: c_int = 0;
+            \\pub const o: c_int = 1;
+            \\pub const p: c_int = 2;
+            \\pub const enum_i =
+        ++ " " ++ default_enum_type ++
+            \\;
         ,
-        \\pub const Baz = struct_Baz;
+        "pub const Baz = struct_Baz;",
     });
 
     cases.add("#define a char literal",
@@ -2257,15 +2180,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    Two,
         \\};
     , &[_][]const u8{
-        \\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);
+        \\pub const One: c_int = 0;
+        \\pub const Two: c_int = 1;
+        \\const enum_unnamed_1 =
+        ++ " " ++ default_enum_type ++
+            \\;
     });
 
     cases.add("c style cast",
@@ -2363,32 +2282,27 @@ 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(
-        ++ 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 FooA: c_int = 0;
+        \\pub const FooB: c_int = 1;
+        \\pub const FooC: c_int = 2;
+        \\pub const enum_Foo =
+        ++ " " ++ default_enum_type ++
+            \\;
             \\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").zig.c_translation.cast(enum_Foo, FooA);
+            \\    var d: enum_Foo = @bitCast(c_uint, 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 k: c_int = @boolToInt((a != 0) or (@bitCast(c_int, d) != 0));
+            \\    var l: c_int = @boolToInt((@bitCast(c_int, d) != 0) and (b != 0));
+            \\    var m: c_int = @boolToInt((c != null) or (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));
@@ -2413,16 +2327,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    x: c_int,
         \\    y: c_int,
         \\};
-        ,
-        \\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 const BarA: c_int = 0;
+        \\pub const BarB: c_int = 1;
+        \\pub const enum_Bar =
+        ++ " " ++ default_enum_type ++
+            \\;
             \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
         ,
         \\pub const Foo = struct_Foo;
@@ -2693,17 +2602,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return 4;
         \\}
     , &[_][]const u8{
-        \\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 const A: c_int = 0;
+        \\pub const B: c_int = 1;
+        \\pub const C: c_int = 2;
+        \\pub const enum_SomeEnum =
+        ++ " " ++ default_enum_type ++
+            \\;
             \\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;
@@ -2712,7 +2616,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
             \\    if (a != 0) return 0;
             \\    if (b != 0) return 1;
             \\    if (c != null) return 2;
-            \\    if (@enumToInt(d) != 0) return 3;
+            \\    if (d != 0) return 3;
             \\    return 4;
             \\}
     });
@@ -3161,17 +3065,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    Foo1,
         \\};
     , &[_][]const u8{
-        \\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 FooA: c_int = 2;
+        \\pub const FooB: c_int = 5;
+        \\pub const Foo1: c_int = 6;
+        \\pub const enum_Foo =
+        ++ " " ++ default_enum_type ++
+            \\;
         ,
         \\pub const Foo = enum_Foo;
     });