diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index f58e8c2352d4..77c57e506606 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -760,6 +760,7 @@ pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTU pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl; pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl; pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl; +pub extern fn ZigClangFieldDecl_getCanonicalDecl(field_decl: ?*const struct_ZigClangFieldDecl) ?*const struct_ZigClangFieldDecl; pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl; pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl; pub extern fn ZigClangFunctionDecl_getCanonicalDecl(self: ?*const struct_ZigClangFunctionDecl) ?*const struct_ZigClangFunctionDecl; @@ -1055,6 +1056,7 @@ pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangSt pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr; +pub extern fn ZigClangFieldDecl_isAnonymousStructOrUnion(*const struct_ZigClangFieldDecl) bool; pub extern fn ZigClangFieldDecl_isBitField(*const struct_ZigClangFieldDecl) bool; pub extern fn ZigClangFieldDecl_getType(*const struct_ZigClangFieldDecl) struct_ZigClangQualType; pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) struct_ZigClangSourceLocation; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 730c93e037e1..74c45a3243db 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -759,8 +759,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); break :blk opaque; } - const raw_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))); - if (raw_name.len < 1) continue; // fix weird windows bug? + + var is_anon = false; + var raw_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))); + if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl) or raw_name.len == 0) { + raw_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); + is_anon = true; + } const field_name = try appendIdentifier(c, raw_name); _ = try appendToken(c, .Colon, ":"); const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) { @@ -781,6 +786,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* .align_expr = null, }; + if (is_anon) { + _ = try c.decl_table.put( + @ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl)), + raw_name, + ); + } + try container_node.fields_and_decls.push(&field_node.base); _ = try appendToken(c, .Comma, ","); } @@ -1829,8 +1841,11 @@ fn transInitListExprRecord( // .field_name = expr const period_tok = try appendToken(rp.c, .Period, "."); - const raw_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))); - if (raw_name.len < 1) continue; + var raw_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))); + if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) { + const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?; + raw_name = try mem.dupe(rp.c.a(), u8, name.value); + } const field_name_tok = try appendIdentifier(rp.c, raw_name); _ = try appendToken(rp.c, .Equal, "="); @@ -2417,10 +2432,22 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE container_node = try transCreateNodePtrDeref(rp.c, container_node); } - const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, ZigClangMemberExpr_getMemberDecl(stmt)))); - if (name.len == 0) { - return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)), "TODO access of anonymous field", .{}); - } + const member_decl = ZigClangMemberExpr_getMemberDecl(stmt); + const name = blk: { + const decl_kind = ZigClangDecl_getKind(@ptrCast(*const ZigClangDecl, member_decl)); + // If we're referring to a anonymous struct/enum find the bogus name + // we've assigned to it during the RecordDecl translation + if (decl_kind == .Field) { + const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl); + if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) { + const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?; + break :blk try mem.dupe(rp.c.a(), u8, name.value); + } + } + const decl = @ptrCast(*const ZigClangDecl, member_decl); + break :blk try rp.c.str(ZigClangDecl_getName_bytes_begin(decl)); + }; + const node = try transCreateNodeFieldAccess(rp.c, container_node, name); return maybeSuppressResult(rp, scope, result_used, node); } diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 0b75ea64e3b5..9d88f071c066 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -1562,6 +1562,11 @@ const ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const ZigClangRecordD return reinterpret_cast(tag_decl); } +const ZigClangFieldDecl *ZigClangFieldDecl_getCanonicalDecl(const ZigClangFieldDecl *field_decl) { + const clang::FieldDecl *canon_decl = reinterpret_cast(field_decl)->getCanonicalDecl(); + return reinterpret_cast(canon_decl); +} + const ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const ZigClangEnumDecl *enum_decl) { const clang::TagDecl *tag_decl = reinterpret_cast(enum_decl)->getCanonicalDecl(); return reinterpret_cast(tag_decl); @@ -2679,6 +2684,10 @@ bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *self) { return casted->isBitField(); } +bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *field_decl) { + return reinterpret_cast(field_decl)->isAnonymousStructOrUnion(); +} + ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *self) { auto casted = reinterpret_cast(self); return bitcast(casted->getLocation()); diff --git a/src/zig_clang.h b/src/zig_clang.h index 0edd8fb128b5..1d94989faf7b 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -855,6 +855,7 @@ ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumType_getDecl(const struc ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl); ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *); +ZIG_EXTERN_C const struct ZigClangFieldDecl *ZigClangFieldDecl_getCanonicalDecl(const ZigClangFieldDecl *); ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const struct ZigClangTypedefNameDecl *); ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self); ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self); @@ -1118,6 +1119,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSour ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSourceRange_getEnd(const struct ZigClangMacroDefinitionRecord *); ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *); +ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *); ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *); ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *); diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 42dd97873c05..dc6966c08d74 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -23,4 +23,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("anonymous struct & unions", + \\#include + \\#include + \\static struct { struct { uint16_t x, y; }; } x = { 1 }; + \\static struct { union { uint32_t x; uint8_t y; }; } y = { 0x55AA55AA }; + \\int main(int argc, char **argv) { + \\ if (x.x != 1) abort(); + \\ if (x.y != 0) abort(); + \\ if (y.x != 0x55AA55AA) abort(); + \\ if (y.y != 0xAA) abort(); + \\ return 0; + \\} + , ""); } diff --git a/test/translate_c.zig b/test/translate_c.zig index 7049173d80c6..dcef74918618 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -8,6 +8,32 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const VAL = 0xF00D; }); + cases.add("anonymous struct & unions", + \\typedef struct { + \\ union { + \\ char x; + \\ struct { int y; }; + \\ }; + \\} outer; + \\void foo(outer *x) { x->y = x->x; } + , &[_][]const u8{ + \\const struct_unnamed_5 = extern struct { + \\ y: c_int, + \\}; + \\const union_unnamed_3 = extern union { + \\ x: u8, + \\ unnamed_4: struct_unnamed_5, + \\}; + \\const struct_unnamed_1 = extern struct { + \\ unnamed_2: union_unnamed_3, + \\}; + \\pub const outer = struct_unnamed_1; + \\pub export fn foo(arg_x: [*c]outer) void { + \\ var x = arg_x; + \\ x.*.unnamed_2.unnamed_4.y = @bitCast(c_int, @as(c_uint, x.*.unnamed_2.x)); + \\} + }); + cases.add("union initializer", \\union { int x; char c[4]; } \\ ua = {1}, @@ -1411,21 +1437,25 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("type referenced struct", - \\struct Foo { - \\ struct Bar{ - \\ int b; - \\ }; - \\ struct Bar c; - \\}; - , &[_][]const u8{ - \\pub const struct_Bar = extern struct { - \\ b: c_int, - \\}; - \\pub const struct_Foo = extern struct { - \\ c: struct_Bar, - \\}; - }); + if (builtin.os != .windows) { + // When clang uses the -windows-none triple it behaves as MSVC and + // interprets the inner `struct Bar` as an anonymous structure + cases.add("type referenced struct", + \\struct Foo { + \\ struct Bar{ + \\ int b; + \\ }; + \\ struct Bar c; + \\}; + , &[_][]const u8{ + \\pub const struct_Bar = extern struct { + \\ b: c_int, + \\}; + \\pub const struct_Foo = extern struct { + \\ c: struct_Bar, + \\}; + }); + } cases.add("undefined array global", \\int array[100] = {};