diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index d5de3cdb9..e1d6c9a81 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -725,11 +725,15 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No }; const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); + // The underlying type may be null in case of forward-declared enum + // types, while that's not ISO-C compliant many compilers allow this and + // default to the usual integer type used for all the enums. // TODO only emit this tag type if the enum tag type is not the default. // I don't know what the default is, need to figure out how clang is deciding. // it appears to at least be different across gcc/msvc - if (!isCBuiltinType(int_type, .UInt) and + if (int_type.ptr != null and + !isCBuiltinType(int_type, .UInt) and !isCBuiltinType(int_type, .Int)) { _ = try appendToken(c, .LParen, "("); @@ -1555,8 +1559,7 @@ fn transCCast( const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ZigClangQualType_getTypePtr(dst_type)); return transCCast(rp, scope, loc, ZigClangElaboratedType_getNamedType(elaborated_ty), src_type, expr); } - if (ZigClangQualType_getTypeClass(dst_type) == .Enum) - { + if (ZigClangQualType_getTypeClass(dst_type) == .Enum) { const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum"); try builtin_node.params.push(try transQualType(rp, dst_type, loc)); _ = try appendToken(rp.c, .Comma, ","); diff --git a/test/translate_c.zig b/test/translate_c.zig index 304c290be..452898b1b 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -814,6 +814,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void { /////////////// Cases that pass for only stage2 //////////////// + cases.add_2("Forward-declared enum", + \\extern enum enum_ty my_enum; + \\enum enum_ty { FOO }; + , &[_][]const u8{ + \\pub const FOO = 0; + \\pub const enum_enum_ty = extern enum { + \\ FOO, + \\}; + \\pub extern var my_enum: enum_enum_ty; + }); + cases.add_2("Parameterless function pointers", \\typedef void (*fn0)(); \\typedef void (*fn1)(char);