diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 37f1eebe2742..b7df7cb9f15a 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -7,6 +7,7 @@ pub const struct_ZigClangAPInt = @OpaqueType(); pub const struct_ZigClangAPSInt = @OpaqueType(); pub const struct_ZigClangAPFloat = @OpaqueType(); pub const struct_ZigClangASTContext = @OpaqueType(); +pub const struct_ZigClangASTRecordLayout = @OpaqueType(); pub const struct_ZigClangASTUnit = @OpaqueType(); pub const struct_ZigClangArraySubscriptExpr = @OpaqueType(); pub const struct_ZigClangArrayType = @OpaqueType(); @@ -757,6 +758,9 @@ pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_Z pub extern fn ZigClangSourceManager_getSpellingColumnNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigClangSourceManager, SL: struct_ZigClangSourceLocation) [*:0]const u8; pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType; +pub extern fn ZigClangASTContext_getASTRecordLayout(self: ?*const struct_ZigClangASTContext, D: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangASTRecordLayout; +pub extern fn ZigClangASTRecordLayout_getFieldCount(self: ?*const struct_ZigClangASTRecordLayout) c_uint; +pub extern fn ZigClangASTRecordLayout_getFieldOffset(self: ?*const struct_ZigClangASTRecordLayout, field_no: c_uint) u64; pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext; pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager; pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool; @@ -1072,6 +1076,9 @@ pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigC pub extern fn ZigClangFieldDecl_isAnonymousStructOrUnion(*const struct_ZigClangFieldDecl) bool; pub extern fn ZigClangFieldDecl_isBitField(*const struct_ZigClangFieldDecl) bool; +pub extern fn ZigClangFieldDecl_isUnnamedBitfield(*const struct_ZigClangFieldDecl) bool; +pub extern fn ZigClangFieldDecl_getFieldIndex(*const struct_ZigClangFieldDecl) c_uint; +pub extern fn ZigClangFieldDecl_getBitWidthValue(*const struct_ZigClangFieldDecl, *const struct_ZigClangASTContext) c_uint; 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 baba9666012a..a33c741084b6 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -751,7 +751,8 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* break :blk opaque; }; - const layout_tok = try if (ZigClangRecordDecl_getPackedAttribute(record_decl)) + const is_packed = ZigClangRecordDecl_getPackedAttribute(record_decl); + const layout_tok = try if (is_packed) appendToken(c, .Keyword_packed, "packed") else appendToken(c, .Keyword_extern, "extern"); @@ -768,33 +769,39 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* .rbrace_token = undefined, }; + const layout = ZigClangASTContext_getASTRecordLayout(c.clang_context, record_def); var it = ZigClangRecordDecl_field_begin(record_def); const end_it = ZigClangRecordDecl_field_end(record_def); while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { const field_decl = ZigClangRecordDecl_field_iterator_deref(it); const field_loc = ZigClangFieldDecl_getLocation(field_decl); - if (ZigClangFieldDecl_isBitField(field_decl)) { - const opaque = try transCreateNodeOpaqueType(c); - semicolon = try appendToken(c, .Semicolon, ";"); - try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); - break :blk opaque; - } + const is_bitfield = ZigClangFieldDecl_isBitField(field_decl); + const offset = ZigClangASTRecordLayout_getFieldOffset(layout, ZigClangFieldDecl_getFieldIndex(field_decl)); var is_anon = false; var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl))); - if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) { + if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl) or (is_bitfield and ZigClangFieldDecl_isUnnamedBitfield(field_decl))) { 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) { - error.UnsupportedType => { - try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name}); - return null; - }, - else => |e| return e, + + const field_type = if (is_bitfield) ty: { + const field_qt = ZigClangFieldDecl_getType(field_decl); + const sign = if (cIsSignedInteger(field_qt)) "i" else "u"; + const bit_width = ZigClangFieldDecl_getBitWidthValue(field_decl, c.clang_context); + const type_name = try std.fmt.allocPrint(c.a(), "{}{}", .{ sign, bit_width }); + break :ty try transCreateNodeIdentifier(c, type_name); + } else ty: { + break :ty transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) { + error.UnsupportedType => { + try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name}); + return null; + }, + else => |e| return e, + }; }; const field_node = try c.a().create(ast.Node.ContainerField); @@ -3459,15 +3466,6 @@ fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocatio const record_decl = ZigClangRecordType_getDecl(record_ty); const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse return true; - var it = ZigClangRecordDecl_field_begin(record_def); - const end_it = ZigClangRecordDecl_field_end(record_def); - while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { - const field_decl = ZigClangRecordDecl_field_iterator_deref(it); - - if (ZigClangFieldDecl_isBitField(field_decl)) { - return true; - } - } return false; }, .Elaborated => { diff --git a/src/analyze.cpp b/src/analyze.cpp index 2958dd8917a0..fb437de7d3ad 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1682,18 +1682,12 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { *result = true; return ErrorNone; case ZigTypeIdInt: - switch (type_entry->data.integral.bit_count) { - case 8: - case 16: - case 32: - case 64: - case 128: - *result = true; - return ErrorNone; - default: - *result = false; - return ErrorNone; + if (type_entry->data.integral.bit_count <= 128) { + *result = true; + } else { + *result = false; } + return ErrorNone; case ZigTypeIdVector: return type_allowed_in_extern(g, type_entry->data.vector.elem_type, result); case ZigTypeIdFloat: diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index ed738e042ef9..cf96197801c0 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #if __GNUC__ >= 8 #pragma GCC diagnostic pop @@ -1504,6 +1505,20 @@ ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* sel return bitcast(reinterpret_cast(self)->getPointerType(bitcast(T))); } +const ZigClangASTRecordLayout *ZigClangASTContext_getASTRecordLayout(const ZigClangASTContext* self, const ZigClangRecordDecl *D) { + const clang::RecordDecl *record_decl = reinterpret_cast(D); + const clang::ASTRecordLayout *result = &reinterpret_cast(self)->getASTRecordLayout(record_decl); + return reinterpret_cast(result); +} + +unsigned ZigClangASTRecordLayout_getFieldCount(const struct ZigClangASTRecordLayout *self) { + return reinterpret_cast(self)->getFieldCount(); +} + +uint64_t ZigClangASTRecordLayout_getFieldOffset(const ZigClangASTRecordLayout *self, unsigned field_no) { + return reinterpret_cast(self)->getFieldOffset(field_no); +} + unsigned ZigClangASTContext_getTypeAlign(const ZigClangASTContext* self, ZigClangQualType T) { return reinterpret_cast(self)->getTypeAlign(bitcast(T)); } @@ -2748,6 +2763,22 @@ bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *field_d return reinterpret_cast(field_decl)->isAnonymousStructOrUnion(); } +bool ZigClangFieldDecl_isUnnamedBitfield(const struct ZigClangFieldDecl *self) { + auto casted = reinterpret_cast(self); + return casted->isUnnamedBitfield(); +} + +unsigned ZigClangFieldDecl_getFieldIndex(const struct ZigClangFieldDecl *self) { + auto casted = reinterpret_cast(self); + return casted->getFieldIndex(); +} + +unsigned ZigClangFieldDecl_getBitWidthValue(const struct ZigClangFieldDecl *self, const struct ZigClangASTContext *ctx) { + auto casted = reinterpret_cast(self); + auto casted_ctx = reinterpret_cast(ctx); + return casted->getBitWidthValue(*casted_ctx); +} + 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 f9ced941cbf2..b8d63330508f 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -69,6 +69,7 @@ struct ZigClangAPInt; struct ZigClangAPSInt; struct ZigClangAPValue; struct ZigClangASTContext; +struct ZigClangASTRecordLayout; struct ZigClangASTUnit; struct ZigClangArraySubscriptExpr; struct ZigClangArrayType; @@ -831,7 +832,10 @@ ZIG_EXTERN_C const char* ZigClangSourceManager_getCharacterData(const struct Zig struct ZigClangSourceLocation SL); ZIG_EXTERN_C struct ZigClangQualType ZigClangASTContext_getPointerType(const struct ZigClangASTContext*, struct ZigClangQualType T); +ZIG_EXTERN_C const ZigClangASTRecordLayout *ZigClangASTContext_getASTRecordLayout(const struct ZigClangASTContext* self, const ZigClangRecordDecl *D); +ZIG_EXTERN_C unsigned ZigClangASTRecordLayout_getFieldCount(const ZigClangASTRecordLayout *self); +ZIG_EXTERN_C uint64_t ZigClangASTRecordLayout_getFieldOffset(const ZigClangASTRecordLayout *self, unsigned field_no); // Can return null. ZIG_EXTERN_C struct ZigClangASTUnit *ZigClangLoadFromCommandLine(const char **args_begin, const char **args_end, @@ -1130,8 +1134,11 @@ ZIG_EXTERN_C const char *ZigClangMacroDefinitionRecord_getName_getNameStart(cons ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSourceRange_getBegin(const struct ZigClangMacroDefinitionRecord *); ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSourceRange_getEnd(const struct ZigClangMacroDefinitionRecord *); +ZIG_EXTERN_C unsigned ZigClangFieldDecl_getFieldIndex(const struct ZigClangFieldDecl *self); +ZIG_EXTERN_C unsigned ZigClangFieldDecl_getBitWidthValue(const struct ZigClangFieldDecl *self, const struct ZigClangASTContext *ctx); ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *); ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *); +ZIG_EXTERN_C bool ZigClangFieldDecl_isUnnamedBitfield(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/stage1/c_abi/main.zig b/test/stage1/c_abi/main.zig index 3c2b73152422..11d73c4f6262 100644 --- a/test/stage1/c_abi/main.zig +++ b/test/stage1/c_abi/main.zig @@ -261,3 +261,18 @@ export fn zig_big_struct_both(x: BigStruct) BigStruct { }; return s; } + +test "C struct with bit fields" { + const C_struct = extern struct { + a: u4, + b: u6, + c: i2, + d: u0, // 0-width field aligns to next byte boundary + e: u1, + }; + std.testing.expectEqual(0, @bitOffsetOf(C_struct, "a")); + std.testing.expectEqual(4, @bitOffsetOf(C_struct, "b")); + std.testing.expectEqual(10, @bitOffsetOf(C_struct, "c")); + std.testing.expectEqual(16, @bitOffsetOf(C_struct, "d")); + std.testing.expectEqual(16, @bitOffsetOf(C_struct, "e")); +} diff --git a/test/translate_c.zig b/test/translate_c.zig index 16caa6e32346..3e2b0dcdbe53 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -347,18 +347,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add("pointer to struct demoted to opaque due to bit fields", - \\struct Foo { - \\ unsigned int: 1; - \\}; - \\struct Bar { - \\ struct Foo *foo; + cases.add("bit fields", + \\struct bitfield { + \\ unsigned int a : 3; + \\ signed int b : 6; + \\ unsigned int c : 6; + \\ unsigned int d : 6; + \\ unsigned int : 0; + \\ unsigned long long e : 22; + \\ unsigned int a2 : 3; + \\ unsigned int b2 : 6; + \\ unsigned int c2 : 6; + \\ unsigned int d2 : 6; + \\ unsigned int : 0; + \\ unsigned long long e2 : 22; \\}; , &[_][]const u8{ - \\pub const struct_Foo = @OpaqueType(); - , - \\pub const struct_Bar = extern struct { - \\ foo: ?*struct_Foo, + \\pub const struct_bitfield = extern struct { + \\ a: u3, + \\ b: i6, + \\ c: u6, + \\ d: u6, + \\ unnamed_1: u0, + \\ e: u22, + \\ a2: u3, + \\ b2: u6, + \\ c2: u6, + \\ d2: u6, + \\ unnamed_2: u0, + \\ e2: u22, \\}; });