diff --git a/lib/std/zig/c_translation.zig b/lib/std/zig/c_translation.zig index 6e0f721b4f96..7851525bb7be 100644 --- a/lib/std/zig/c_translation.zig +++ b/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); diff --git a/src/clang.zig b/src/clang.zig index bd305bc76f05..023d1aba4b3e 100644 --- a/src/clang.zig +++ b/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; }; diff --git a/src/translate_c.zig b/src/translate_c.zig index 4b0761839190..a68c434b8795 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1099,27 +1099,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 @@ -1127,61 +1137,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, }, }; @@ -1192,18 +1168,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 { @@ -2096,8 +2060,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); @@ -2309,21 +2272,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); @@ -2376,14 +2340,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 }); } @@ -5969,7 +5925,6 @@ fn getContainer(c: *Context, node: Node) ?Node { switch (node.tag()) { .@"union", .@"struct", - .@"enum", .address_of, .bit_not, .not, diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 59e84c6ba05f..70c8c6559f04 100644 --- a/src/translate_c/ast.zig +++ b/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", diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 8a60a1210edb..7c923021d827 100644 --- a/src/zig_clang.cpp +++ b/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(self); - const clang::Expr *result = casted->getInitExpr(); - return reinterpret_cast(result); -} - const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *self) { auto casted = reinterpret_cast(self); const llvm::APSInt *result = &casted->getInitVal(); diff --git a/src/zig_clang.h b/src/zig_clang.h index 5ffba627df6b..634534dfb401 100644 --- a/src/zig_clang.h +++ b/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 diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 4440802c3354..03f06ed8cac3 100644 --- a/test/run_translated_c.zig +++ b/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 + \\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 + \\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(); + \\} + , ""); } diff --git a/test/translate_c.zig b/test/translate_c.zig index 21350a8600bd..a6a652681c9b 100644 --- a/test/translate_c.zig +++ b/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; });