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 {...@@ -476,6 +476,12 @@ pub const FieldDecl = opaque {
476 pub const isBitField = ZigClangFieldDecl_isBitField;476 pub const isBitField = ZigClangFieldDecl_isBitField;
477 extern fn ZigClangFieldDecl_isBitField(*const FieldDecl) bool;477 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
479 pub const getType = ZigClangFieldDecl_getType;485 pub const getType = ZigClangFieldDecl_getType;
480 extern fn ZigClangFieldDecl_getType(*const FieldDecl) QualType;486 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...@@ -1085,17 +1085,15 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1085 const layout = record_def.getASTRecordLayout(c.clang_context);1085 const layout = record_def.getASTRecordLayout(c.clang_context);
1086 const record_alignment = layout.getAlignment();1086 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
1088 while (it.neq(end_it)) : (it = it.next()) {1092 while (it.neq(end_it)) : (it = it.next()) {
1089 const field_decl = it.deref();1093 const field_decl = it.deref();
1090 const field_loc = field_decl.getLocation();1094 const field_loc = field_decl.getLocation();
1091 const field_qt = field_decl.getType();1095 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
1099 var is_anon = false;1097 var is_anon = false;
1100 var field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());1098 var field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
1101 if (field_decl.isAnonymousStructOrUnion() or field_name.len == 0) {1099 if (field_decl.isAnonymousStructOrUnion() or field_name.len == 0) {
...@@ -1125,6 +1123,53 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -1125,6 +1123,53 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1125 else => |e| return e,1123 else => |e| return e,
1126 };1124 };
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
1128 const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0)1173 const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0)
1129 @intCast(c_uint, record_alignment)1174 @intCast(c_uint, record_alignment)
1130 else1175 else
...@@ -1140,6 +1185,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -1140,6 +1185,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1140 .alignment = alignment,1185 .alignment = alignment,
1141 });1186 });
1142 }1187 }
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
1144 const record_payload = try c.arena.create(ast.Payload.Record);1193 const record_payload = try c.arena.create(ast.Payload.Record);
1145 record_payload.* = .{1194 record_payload.* = .{
...@@ -2576,7 +2625,9 @@ fn transInitListExprRecord(...@@ -2576,7 +2625,9 @@ fn transInitListExprRecord(
2576 continue;2625 continue;
2577 }2626 }
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 }
2580 const elem_expr = expr.getInit(init_i);2631 const elem_expr = expr.getInit(init_i);
2581 init_i += 1;2632 init_i += 1;
25822633
src/zig_clang.cpp+12
...@@ -3335,6 +3335,18 @@ bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *self) {...@@ -3335,6 +3335,18 @@ bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *self) {
3335 return casted->isBitField();3335 return casted->isBitField();
3336}3336}
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
3338bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *field_decl) {3350bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *field_decl) {
3339 return reinterpret_cast<const clang::FieldDecl*>(field_decl)->isAnonymousStructOrUnion();3351 return reinterpret_cast<const clang::FieldDecl*>(field_decl)->isAnonymousStructOrUnion();
3340}3352}
src/zig_clang.h+2
...@@ -1407,6 +1407,8 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSour...@@ -1407,6 +1407,8 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSour
1407ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSourceRange_getEnd(const struct ZigClangMacroDefinitionRecord *);1407ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangMacroDefinitionRecord_getSourceRange_getEnd(const struct ZigClangMacroDefinitionRecord *);
14081408
1409ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *);1409ZIG_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 *);
1410ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);1412ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);
1411ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);1413ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);
1412ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);1414ZIG_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 {...@@ -915,21 +915,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
915 \\};915 \\};
916 });916 });
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
933 cases.add("macro with left shift",918 cases.add("macro with left shift",
934 \\#define REDISMODULE_READ (1<<0)919 \\#define REDISMODULE_READ (1<<0)
935 , &[_][]const u8{920 , &[_][]const u8{
...@@ -3577,34 +3562,33 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3577,34 +3562,33 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3577 \\}3562 \\}
3578 });3563 });
35793564
3580 cases.add("Demote function that initializes opaque struct",3565 cases.add("function that dereferences bitfield works",
3581 \\struct my_struct {3566 \\struct my_struct {
3582 \\ unsigned a: 15;3567 \\ unsigned a: 1;
3583 \\ unsigned: 2;3568 \\ unsigned b: 28;
3584 \\ unsigned b: 15;
3585 \\};3569 \\};
3586 \\void initialize(void) {3570 \\void deref(struct my_struct *s) {
3587 \\ struct my_struct S = {.a = 1, .b = 2};3571 \\ *s;
3588 \\}3572 \\}
3589 , &[_][]const u8{3573 , &[_][]const u8{
3590 \\warning: cannot initialize opaque type3574 \\pub const struct_my_struct = extern struct {
3575 \\ bitfield0: c_uint,
3591 ,3576 ,
3592 \\warning: unable to translate function, demoted to extern3577 \\pub export fn deref(arg_s: ?*struct_my_struct) void {
3593 \\pub extern fn initialize() void;3578 \\ var s = arg_s;
3579 \\ _ = s.*;
3580 \\}
3594 });3581 });
35953582
3596 cases.add("Demote function that dereferences opaque type",3583 cases.add("bitfield don't cover requedted space",
3597 \\struct my_struct {3584 \\struct inner {
3598 \\ unsigned a: 1;3585 \\ unsigned a: 1;
3586 \\ char after;
3599 \\};3587 \\};
3600 \\void deref(struct my_struct *s) {
3601 \\ *s;
3602 \\}
3603 , &[_][]const u8{3588 , &[_][]const u8{
3604 \\warning: cannot dereference opaque type3589 \\less bits used than field size.
3605 ,3590 ,
3606 \\warning: unable to translate function, demoted to extern3591 \\pub const struct_inner = opaque {};
3607 \\pub extern fn deref(arg_s: ?*struct_my_struct) void;
3608 });3592 });
36093593
3610 cases.add("Function prototype declared within function",3594 cases.add("Function prototype declared within function",