Skip to content

Commit bf678a1

Browse files
committed
Merge branch 'LemonBoy-c-anon-stuff'
closes #4081
2 parents f83b02a + 62413da commit bf678a1

File tree

6 files changed

+107
-23
lines changed

6 files changed

+107
-23
lines changed

src-self-hosted/clang.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,7 @@ pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTU
760760
pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl;
761761
pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl;
762762
pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl;
763+
pub extern fn ZigClangFieldDecl_getCanonicalDecl(field_decl: ?*const struct_ZigClangFieldDecl) ?*const struct_ZigClangFieldDecl;
763764
pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl;
764765
pub extern fn ZigClangTypedefNameDecl_getCanonicalDecl(self: ?*const struct_ZigClangTypedefNameDecl) ?*const struct_ZigClangTypedefNameDecl;
765766
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
10551056

10561057
pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr;
10571058

1059+
pub extern fn ZigClangFieldDecl_isAnonymousStructOrUnion(*const struct_ZigClangFieldDecl) bool;
10581060
pub extern fn ZigClangFieldDecl_isBitField(*const struct_ZigClangFieldDecl) bool;
10591061
pub extern fn ZigClangFieldDecl_getType(*const struct_ZigClangFieldDecl) struct_ZigClangQualType;
10601062
pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) struct_ZigClangSourceLocation;

src-self-hosted/translate_c.zig

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -759,8 +759,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
759759
try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});
760760
break :blk opaque;
761761
}
762-
const raw_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)));
763-
if (raw_name.len < 1) continue; // fix weird windows bug?
762+
763+
var is_anon = false;
764+
var raw_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)));
765+
if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl) or raw_name.len == 0) {
766+
raw_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()});
767+
is_anon = true;
768+
}
764769
const field_name = try appendIdentifier(c, raw_name);
765770
_ = try appendToken(c, .Colon, ":");
766771
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!?*
781786
.align_expr = null,
782787
};
783788

789+
if (is_anon) {
790+
_ = try c.decl_table.put(
791+
@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl)),
792+
raw_name,
793+
);
794+
}
795+
784796
try container_node.fields_and_decls.push(&field_node.base);
785797
_ = try appendToken(c, .Comma, ",");
786798
}
@@ -1829,8 +1841,11 @@ fn transInitListExprRecord(
18291841
// .field_name = expr
18301842
const period_tok = try appendToken(rp.c, .Period, ".");
18311843

1832-
const raw_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)));
1833-
if (raw_name.len < 1) continue;
1844+
var raw_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)));
1845+
if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
1846+
const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;
1847+
raw_name = try mem.dupe(rp.c.a(), u8, name.value);
1848+
}
18341849
const field_name_tok = try appendIdentifier(rp.c, raw_name);
18351850

18361851
_ = try appendToken(rp.c, .Equal, "=");
@@ -2417,10 +2432,22 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE
24172432
container_node = try transCreateNodePtrDeref(rp.c, container_node);
24182433
}
24192434

2420-
const name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, ZigClangMemberExpr_getMemberDecl(stmt))));
2421-
if (name.len == 0) {
2422-
return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)), "TODO access of anonymous field", .{});
2423-
}
2435+
const member_decl = ZigClangMemberExpr_getMemberDecl(stmt);
2436+
const name = blk: {
2437+
const decl_kind = ZigClangDecl_getKind(@ptrCast(*const ZigClangDecl, member_decl));
2438+
// If we're referring to a anonymous struct/enum find the bogus name
2439+
// we've assigned to it during the RecordDecl translation
2440+
if (decl_kind == .Field) {
2441+
const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl);
2442+
if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
2443+
const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;
2444+
break :blk try mem.dupe(rp.c.a(), u8, name.value);
2445+
}
2446+
}
2447+
const decl = @ptrCast(*const ZigClangDecl, member_decl);
2448+
break :blk try rp.c.str(ZigClangDecl_getName_bytes_begin(decl));
2449+
};
2450+
24242451
const node = try transCreateNodeFieldAccess(rp.c, container_node, name);
24252452
return maybeSuppressResult(rp, scope, result_used, node);
24262453
}

src/zig_clang.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,11 @@ const ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const ZigClangRecordD
15621562
return reinterpret_cast<const ZigClangTagDecl *>(tag_decl);
15631563
}
15641564

1565+
const ZigClangFieldDecl *ZigClangFieldDecl_getCanonicalDecl(const ZigClangFieldDecl *field_decl) {
1566+
const clang::FieldDecl *canon_decl = reinterpret_cast<const clang::FieldDecl*>(field_decl)->getCanonicalDecl();
1567+
return reinterpret_cast<const ZigClangFieldDecl *>(canon_decl);
1568+
}
1569+
15651570
const ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const ZigClangEnumDecl *enum_decl) {
15661571
const clang::TagDecl *tag_decl = reinterpret_cast<const clang::EnumDecl*>(enum_decl)->getCanonicalDecl();
15671572
return reinterpret_cast<const ZigClangTagDecl *>(tag_decl);
@@ -2679,6 +2684,10 @@ bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *self) {
26792684
return casted->isBitField();
26802685
}
26812686

2687+
bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *field_decl) {
2688+
return reinterpret_cast<const clang::FieldDecl*>(field_decl)->isAnonymousStructOrUnion();
2689+
}
2690+
26822691
ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *self) {
26832692
auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
26842693
return bitcast(casted->getLocation());

src/zig_clang.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,7 @@ ZIG_EXTERN_C const struct ZigClangEnumDecl *ZigClangEnumType_getDecl(const struc
855855

856856
ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const struct ZigClangRecordDecl *record_decl);
857857
ZIG_EXTERN_C const struct ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const struct ZigClangEnumDecl *);
858+
ZIG_EXTERN_C const struct ZigClangFieldDecl *ZigClangFieldDecl_getCanonicalDecl(const ZigClangFieldDecl *);
858859
ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefNameDecl_getCanonicalDecl(const struct ZigClangTypedefNameDecl *);
859860
ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangFunctionDecl_getCanonicalDecl(const ZigClangFunctionDecl *self);
860861
ZIG_EXTERN_C const struct ZigClangVarDecl *ZigClangVarDecl_getCanonicalDecl(const ZigClangVarDecl *self);
@@ -1118,6 +1119,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSour
11181119
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSourceRange_getEnd(const struct ZigClangMacroDefinitionRecord *);
11191120

11201121
ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *);
1122+
ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);
11211123
ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);
11221124
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);
11231125

test/run_translated_c.zig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
3939
\\ return 0;
4040
\\}
4141
, "");
42+
43+
cases.add("anonymous struct & unions",
44+
\\#include <stdlib.h>
45+
\\#include <stdint.h>
46+
\\static struct { struct { uint16_t x, y; }; } x = { 1 };
47+
\\static struct { union { uint32_t x; uint8_t y; }; } y = { 0x55AA55AA };
48+
\\int main(int argc, char **argv) {
49+
\\ if (x.x != 1) abort();
50+
\\ if (x.y != 0) abort();
51+
\\ if (y.x != 0x55AA55AA) abort();
52+
\\ if (y.y != 0xAA) abort();
53+
\\ return 0;
54+
\\}
55+
, "");
4256
}

test/translate_c.zig

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,32 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
88
\\pub const VAL = 0xF00D;
99
});
1010

11+
cases.add("anonymous struct & unions",
12+
\\typedef struct {
13+
\\ union {
14+
\\ char x;
15+
\\ struct { int y; };
16+
\\ };
17+
\\} outer;
18+
\\void foo(outer *x) { x->y = x->x; }
19+
, &[_][]const u8{
20+
\\const struct_unnamed_5 = extern struct {
21+
\\ y: c_int,
22+
\\};
23+
\\const union_unnamed_3 = extern union {
24+
\\ x: u8,
25+
\\ unnamed_4: struct_unnamed_5,
26+
\\};
27+
\\const struct_unnamed_1 = extern struct {
28+
\\ unnamed_2: union_unnamed_3,
29+
\\};
30+
\\pub const outer = struct_unnamed_1;
31+
\\pub export fn foo(arg_x: [*c]outer) void {
32+
\\ var x = arg_x;
33+
\\ x.*.unnamed_2.unnamed_4.y = @bitCast(c_int, @as(c_uint, x.*.unnamed_2.x));
34+
\\}
35+
});
36+
1137
cases.add("union initializer",
1238
\\union { int x; char c[4]; }
1339
\\ ua = {1},
@@ -1445,21 +1471,25 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14451471
\\}
14461472
});
14471473

1448-
cases.add("type referenced struct",
1449-
\\struct Foo {
1450-
\\ struct Bar{
1451-
\\ int b;
1452-
\\ };
1453-
\\ struct Bar c;
1454-
\\};
1455-
, &[_][]const u8{
1456-
\\pub const struct_Bar = extern struct {
1457-
\\ b: c_int,
1458-
\\};
1459-
\\pub const struct_Foo = extern struct {
1460-
\\ c: struct_Bar,
1461-
\\};
1462-
});
1474+
if (builtin.os != .windows) {
1475+
// When clang uses the <arch>-windows-none triple it behaves as MSVC and
1476+
// interprets the inner `struct Bar` as an anonymous structure
1477+
cases.add("type referenced struct",
1478+
\\struct Foo {
1479+
\\ struct Bar{
1480+
\\ int b;
1481+
\\ };
1482+
\\ struct Bar c;
1483+
\\};
1484+
, &[_][]const u8{
1485+
\\pub const struct_Bar = extern struct {
1486+
\\ b: c_int,
1487+
\\};
1488+
\\pub const struct_Foo = extern struct {
1489+
\\ c: struct_Bar,
1490+
\\};
1491+
});
1492+
}
14631493

14641494
cases.add("undefined array global",
14651495
\\int array[100] = {};

0 commit comments

Comments
 (0)