authorgravatar for 5883156+TwoClocks@users.noreply.github.comTwoClocks <5883156+TwoClocks@users.noreply.github.com> 2022-01-15 10:30:18-08:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-05-28 17:31:26+03:00
log22cb6938891c73d64b749a2516c8eaf79aa25b03
tree9eed8d3d35ad8e4d16084003f44384c60ade9010
parent0e6285c8fc31ff866df96847fe34e660da38b4a9

reserve correct space for bitfields


5 files changed, 94 insertions(+), 39 deletions(-)

src/clang.zig+6
......@@ -476,6 +476,12 @@ pub const FieldDecl = opaque {
476476 pub const isBitField = ZigClangFieldDecl_isBitField;
477477 extern fn ZigClangFieldDecl_isBitField(*const FieldDecl) bool;
478478
479 pub const getBitWidthValue = ZigClangFieldDecl_getBitWidthValue;
480 extern fn ZigClangFieldDecl_getBitWidthValue(*const FieldDecl, *const ASTContext) c_uint;
481
482 pub const isZeroLengthBitField = ZigClangFieldDecl_isZeroLengthBitField;
483 extern fn ZigClangFieldDecl_isZeroLengthBitField(*const FieldDecl, *const ASTContext) bool;
484
479485 pub const getType = ZigClangFieldDecl_getType;
480486 extern fn ZigClangFieldDecl_getType(*const FieldDecl) QualType;
481487
src/translate_c.zig+58-7
......@@ -1085,17 +1085,15 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
10851085 const layout = record_def.getASTRecordLayout(c.clang_context);
10861086 const record_alignment = layout.getAlignment();
10871087
1088 var record_bitfield_count: u32 = 0;
1089 var bits_unused: i32 = 0;
1090 var bits_type: clang.BuiltinTypeKind = clang.BuiltinTypeKind.Void;
1091
10881092 while (it.neq(end_it)) : (it = it.next()) {
10891093 const field_decl = it.deref();
10901094 const field_loc = field_decl.getLocation();
10911095 const field_qt = field_decl.getType();
10921096
1093 if (field_decl.isBitField()) {
1094 try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1095 try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
1096 break :blk Tag.opaque_literal.init();
1097 }
1098
10991097 var is_anon = false;
11001098 var field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
11011099 if (field_decl.isAnonymousStructOrUnion() or field_name.len == 0) {
......@@ -1125,6 +1123,53 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
11251123 else => |e| return e,
11261124 };
11271125
1126 if (field_decl.isBitField()) {
1127 var this_field_width = @intCast(i32, field_decl.getBitWidthValue(c.clang_context));
1128
1129 // are we starting new bitfield?
1130 if (bits_unused <= 0) {
1131 const size_map = std.ComptimeStringMap(u16, .{ .{ "u8", 8 }, .{ "c_ushort", 16 }, .{ "u16", 16 }, .{ "u32", 32 }, .{ "c_uint", 32 }, .{ "c_ulong", 32 }, .{ "c_ulonglong", 64 }, .{ "u64", 64 } });
1132
1133 bits_type = @ptrCast(*const clang.BuiltinType, field_qt.getTypePtr()).getKind();
1134
1135 var field_width = field_type.castTag(.type).?.*.data; // we just set it 10 lines back. this should not fail.
1136
1137 if (size_map.get(field_width)) |sz| {
1138 bits_unused = @intCast(i32, sz) - this_field_width;
1139 field_name = try std.fmt.allocPrint(c.arena, "bitfield{d}", .{record_bitfield_count});
1140 record_bitfield_count += 1;
1141 } else {
1142 try warn(c, scope, field_loc, "{s} demoted to opaque type - bitfield type not unsigned or unknown. type:{s} ", .{ container_kind_name, field_width });
1143 break :blk Tag.opaque_literal.init();
1144 }
1145 } else {
1146 var this_type = @ptrCast(*const clang.BuiltinType, field_qt.getTypePtr()).getKind();
1147 if (field_decl.isZeroLengthBitField(c.clang_context)) {
1148 try warn(c, scope, field_loc, "{s} demoted to opaque type - bitfield with zero size not supported", .{container_kind_name});
1149 break :blk Tag.opaque_literal.init();
1150 } else if (bits_type != this_type) {
1151 try warn(c, scope, field_loc, "{s} demoted to opaque type - bitfield type changed in the middle of bitfield was;{s} is:{s}", .{ container_kind_name, @tagName(bits_type), @tagName(this_type) });
1152 break :blk Tag.opaque_literal.init();
1153 } else {
1154 // next
1155 bits_unused -= this_field_width;
1156 if (bits_unused < 0) {
1157 try warn(c, scope, field_loc, "{s} demoted to opaque type - bitfield overrun type size not supported", .{container_kind_name});
1158 break :blk Tag.opaque_literal.init();
1159 }
1160 }
1161 continue; // free the field_type? tag is alloc'd
1162 }
1163 } else {
1164 if (bits_unused >= 8) {
1165 // if they didn't add a "reserved:n" at the end, and the # of bits used is more than 1 byte of their requested size,
1166 // the layout is to compiler specific.
1167 try warn(c, scope, field_loc, "{s} demoted to opaque type - less bits used than field size. unused bit count:{d}", .{ container_kind_name, bits_unused });
1168 break :blk Tag.opaque_literal.init();
1169 }
1170 bits_unused = 0;
1171 }
1172
11281173 const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0)
11291174 @intCast(c_uint, record_alignment)
11301175 else
......@@ -1140,6 +1185,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
11401185 .alignment = alignment,
11411186 });
11421187 }
1188 if (bits_unused >= 8) { // one last check if the last field was a bitfield
1189 try warn(c, scope, record_loc, "{s} demoted to opaque type - less bits used than field size. unused bit count:{d}", .{ container_kind_name, bits_unused });
1190 break :blk Tag.opaque_literal.init();
1191 }
11431192
11441193 const record_payload = try c.arena.create(ast.Payload.Record);
11451194 record_payload.* = .{
......@@ -2576,7 +2625,9 @@ fn transInitListExprRecord(
25762625 continue;
25772626 }
25782627
2579 assert(init_i < init_count);
2628 if (init_i >= init_count) {
2629 return fail(c, error.UnsupportedTranslation, loc, "init list longer fields in record. Record has bitfield?", .{});
2630 }
25802631 const elem_expr = expr.getInit(init_i);
25812632 init_i += 1;
25822633
src/zig_clang.cpp+12
......@@ -3335,6 +3335,18 @@ bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *self) {
33353335 return casted->isBitField();
33363336}
33373337
3338unsigned ZigClangFieldDecl_getBitWidthValue( const struct ZigClangFieldDecl *self, const ZigClangASTContext *ctx) {
3339 auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
3340 auto casted_ctx = const_cast<clang::ASTContext *>(reinterpret_cast<const clang::ASTContext *>(ctx));
3341 return casted->getBitWidthValue(*casted_ctx);
3342}
3343
3344bool ZigClangFieldDecl_isZeroLengthBitField( ZigClangFieldDecl *self, const ZigClangASTContext *ctx) {
3345 auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
3346 auto casted_ctx = const_cast<clang::ASTContext *>(reinterpret_cast<const clang::ASTContext *>(ctx));
3347 return casted->isZeroLengthBitField(*casted_ctx);
3348}
3349
33383350bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *field_decl) {
33393351 return reinterpret_cast<const clang::FieldDecl*>(field_decl)->isAnonymousStructOrUnion();
33403352}
src/zig_clang.h+2
......@@ -1407,6 +1407,8 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSour
14071407ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSourceRange_getEnd(const struct ZigClangMacroDefinitionRecord *);
14081408
14091409ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *);
1410ZIG_EXTERN_C unsigned ZigClangFieldDecl_getBitWidthValue( const struct ZigClangFieldDecl *, const ZigClangASTContext *);
1411ZIG_EXTERN_C bool ZigClangFieldDecl_isZeroLengthBitField( ZigClangFieldDecl *, const ZigClangASTContext *);
14101412ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);
14111413ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);
14121414ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);
test/translate_c.zig+16-32
......@@ -915,21 +915,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
915915 \\};
916916 });
917917
918 cases.add("pointer to struct demoted to opaque due to bit fields",
919 \\struct Foo {
920 \\ unsigned int: 1;
921 \\};
922 \\struct Bar {
923 \\ struct Foo *foo;
924 \\};
925 , &[_][]const u8{
926 \\pub const struct_Foo = opaque {};
927 ,
928 \\pub const struct_Bar = extern struct {
929 \\ foo: ?*struct_Foo,
930 \\};
931 });
932
933918 cases.add("macro with left shift",
934919 \\#define REDISMODULE_READ (1<<0)
935920 , &[_][]const u8{
......@@ -3577,34 +3562,33 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
35773562 \\}
35783563 });
35793564
3580 cases.add("Demote function that initializes opaque struct",
3565 cases.add("function that dereferences bitfield works",
35813566 \\struct my_struct {
3582 \\ unsigned a: 15;
3583 \\ unsigned: 2;
3584 \\ unsigned b: 15;
3567 \\ unsigned a: 1;
3568 \\ unsigned b: 28;
35853569 \\};
3586 \\void initialize(void) {
3587 \\ struct my_struct S = {.a = 1, .b = 2};
3570 \\void deref(struct my_struct *s) {
3571 \\ *s;
35883572 \\}
35893573 , &[_][]const u8{
3590 \\warning: cannot initialize opaque type
3574 \\pub const struct_my_struct = extern struct {
3575 \\ bitfield0: c_uint,
35913576 ,
3592 \\warning: unable to translate function, demoted to extern
3593 \\pub extern fn initialize() void;
3577 \\pub export fn deref(arg_s: ?*struct_my_struct) void {
3578 \\ var s = arg_s;
3579 \\ _ = s.*;
3580 \\}
35943581 });
35953582
3596 cases.add("Demote function that dereferences opaque type",
3597 \\struct my_struct {
3583 cases.add("bitfield don't cover requedted space",
3584 \\struct inner {
35983585 \\ unsigned a: 1;
3586 \\ char after;
35993587 \\};
3600 \\void deref(struct my_struct *s) {
3601 \\ *s;
3602 \\}
36033588 , &[_][]const u8{
3604 \\warning: cannot dereference opaque type
3589 \\less bits used than field size.
36053590 ,
3606 \\warning: unable to translate function, demoted to extern
3607 \\pub extern fn deref(arg_s: ?*struct_my_struct) void;
3591 \\pub const struct_inner = opaque {};
36083592 });
36093593
36103594 cases.add("Function prototype declared within function",