authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2023-08-15 21:37:57-07:00
committergravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2023-08-15 23:59:07-07:00
logbdf5739c0a982d24a722b625a660a15bef617ce9
tree8cb6588bc472c2351f9de2fa9f5c6a07c4db7136
parent340a45683ca8e0b23e95f5fb86bd9c827970e6e8

translate-c: Flexible array members must be the last field in a struct

Previously any zero-length or incomplete array within a struct was treated as a flexible array member.

1 files changed, 19 insertions(+), 7 deletions(-)

src/translate_c.zig+19-7
...@@ -1049,21 +1049,33 @@ fn buildFlexibleArrayFn(...@@ -1049,21 +1049,33 @@ fn buildFlexibleArrayFn(
1049 return Node.initPayload(&payload.base);1049 return Node.initPayload(&payload.base);
1050}1050}
10511051
1052/// Return true if `field_decl` is the flexible array field for its parent record
1052fn isFlexibleArrayFieldDecl(c: *Context, field_decl: *const clang.FieldDecl) bool {1053fn isFlexibleArrayFieldDecl(c: *Context, field_decl: *const clang.FieldDecl) bool {
1053 return qualTypeCanon(field_decl.getType()).isIncompleteOrZeroLengthArrayType(c.clang_context);1054 const record_decl = field_decl.getParent() orelse return false;
1055 const record_flexible_field = flexibleArrayField(c, record_decl) orelse return false;
1056 return field_decl == record_flexible_field;
1054}1057}
10551058
1059/// Find the flexible array field for a record if any. A flexible array field is an
1060/// incomplete or zero-length array that occurs as the last field of a record.
1056/// clang's RecordDecl::hasFlexibleArrayMember is not suitable for determining1061/// clang's RecordDecl::hasFlexibleArrayMember is not suitable for determining
1057/// this because it returns false for a record that ends with a zero-length1062/// this because it returns false for a record that ends with a zero-length
1058/// array, but we consider those to be flexible arrays1063/// array, but we consider those to be flexible arrays
1059fn hasFlexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) bool {1064fn flexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) ?*const clang.FieldDecl {
1060 var it = record_def.field_begin();1065 var it = record_def.field_begin();
1061 const end_it = record_def.field_end();1066 const end_it = record_def.field_end();
1067 var flexible_field: ?*const clang.FieldDecl = null;
1062 while (it.neq(end_it)) : (it = it.next()) {1068 while (it.neq(end_it)) : (it = it.next()) {
1063 const field_decl = it.deref();1069 const field_decl = it.deref();
1064 if (isFlexibleArrayFieldDecl(c, field_decl)) return true;1070 const ty = qualTypeCanon(field_decl.getType());
1071 const incomplete_or_zero_size = ty.isIncompleteOrZeroLengthArrayType(c.clang_context);
1072 if (incomplete_or_zero_size) {
1073 flexible_field = field_decl;
1074 } else {
1075 flexible_field = null;
1076 }
1065 }1077 }
1066 return false;1078 return flexible_field;
1067}1079}
10681080
1069fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void {1081fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void {
...@@ -1117,7 +1129,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -1117,7 +1129,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1117 var functions = std.ArrayList(Node).init(c.gpa);1129 var functions = std.ArrayList(Node).init(c.gpa);
1118 defer functions.deinit();1130 defer functions.deinit();
11191131
1120 const has_flexible_array = hasFlexibleArrayField(c, record_def);1132 const flexible_field = flexibleArrayField(c, record_def);
1121 var unnamed_field_count: u32 = 0;1133 var unnamed_field_count: u32 = 0;
1122 var it = record_def.field_begin();1134 var it = record_def.field_begin();
1123 const end_it = record_def.field_end();1135 const end_it = record_def.field_end();
...@@ -1143,7 +1155,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -1143,7 +1155,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1143 unnamed_field_count += 1;1155 unnamed_field_count += 1;
1144 is_anon = true;1156 is_anon = true;
1145 }1157 }
1146 if (isFlexibleArrayFieldDecl(c, field_decl)) {1158 if (flexible_field == field_decl) {
1147 const flexible_array_fn = buildFlexibleArrayFn(c, scope, layout, field_name, field_decl) catch |err| switch (err) {1159 const flexible_array_fn = buildFlexibleArrayFn(c, scope, layout, field_name, field_decl) catch |err| switch (err) {
1148 error.UnsupportedType => {1160 error.UnsupportedType => {
1149 try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl.getCanonicalDecl()), {});1161 try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl.getCanonicalDecl()), {});
...@@ -1164,7 +1176,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -1164,7 +1176,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1164 else => |e| return e,1176 else => |e| return e,
1165 };1177 };
11661178
1167 const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0)1179 const alignment = if (flexible_field != null and field_decl.getFieldIndex() == 0)
1168 @as(c_uint, @intCast(record_alignment))1180 @as(c_uint, @intCast(record_alignment))
1169 else1181 else
1170 ClangAlignment.forField(c, field_decl, record_def).zigAlignment();1182 ClangAlignment.forField(c, field_decl, record_def).zigAlignment();