Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Translate anonymous union/struct #4081

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src-self-hosted/clang.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
43 changes: 35 additions & 8 deletions src-self-hosted/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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, ",");
}
Expand Down Expand Up @@ -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, "=");
Expand Down Expand Up @@ -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);
}
Expand Down
9 changes: 9 additions & 0 deletions src/zig_clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,11 @@ const ZigClangTagDecl *ZigClangRecordDecl_getCanonicalDecl(const ZigClangRecordD
return reinterpret_cast<const ZigClangTagDecl *>(tag_decl);
}

const ZigClangFieldDecl *ZigClangFieldDecl_getCanonicalDecl(const ZigClangFieldDecl *field_decl) {
const clang::FieldDecl *canon_decl = reinterpret_cast<const clang::FieldDecl*>(field_decl)->getCanonicalDecl();
return reinterpret_cast<const ZigClangFieldDecl *>(canon_decl);
}

const ZigClangTagDecl *ZigClangEnumDecl_getCanonicalDecl(const ZigClangEnumDecl *enum_decl) {
const clang::TagDecl *tag_decl = reinterpret_cast<const clang::EnumDecl*>(enum_decl)->getCanonicalDecl();
return reinterpret_cast<const ZigClangTagDecl *>(tag_decl);
Expand Down Expand Up @@ -2679,6 +2684,10 @@ bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *self) {
return casted->isBitField();
}

bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *field_decl) {
return reinterpret_cast<const clang::FieldDecl*>(field_decl)->isAnonymousStructOrUnion();
}

ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *self) {
auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
return bitcast(casted->getLocation());
Expand Down
2 changes: 2 additions & 0 deletions src/zig_clang.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 *);

Expand Down
14 changes: 14 additions & 0 deletions test/run_translated_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
\\ return 0;
\\}
, "");

cases.add("anonymous struct & unions",
\\#include <stdlib.h>
\\#include <stdint.h>
\\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;
\\}
, "");
}
60 changes: 45 additions & 15 deletions test/translate_c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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 <arch>-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] = {};
Expand Down