authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-08-16 15:47:35+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-08-16 15:47:35+03:00
loged744c4f59b6aafc0c343eb975efae3e51658080
treea62f30a88fde266d7acf2a4b24572aaff9c76320
parent3e228bdf457d8be0fcbb8e44a8fa7a0b09677972
parent49cb1683ff1f87c3a9af0b564de0aa7a5b4daf7d
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16851 from ehaas/translate-c-flexible-array

Translate-c: better flexible array member handling

2 files changed, 39 insertions(+), 8 deletions(-)

src/translate_c.zig+21-8
...@@ -965,6 +965,7 @@ fn buildFlexibleArrayFn(...@@ -965,6 +965,7 @@ fn buildFlexibleArrayFn(
965 field_decl: *const clang.FieldDecl,965 field_decl: *const clang.FieldDecl,
966) TypeError!Node {966) TypeError!Node {
967 const field_qt = field_decl.getType();967 const field_qt = field_decl.getType();
968 const field_qt_canon = qualTypeCanon(field_qt);
968969
969 const u8_type = try Tag.type.create(c.arena, "u8");970 const u8_type = try Tag.type.create(c.arena, "u8");
970 const self_param_name = "self";971 const self_param_name = "self";
...@@ -979,7 +980,7 @@ fn buildFlexibleArrayFn(...@@ -979,7 +980,7 @@ fn buildFlexibleArrayFn(
979 .is_noalias = false,980 .is_noalias = false,
980 };981 };
981982
982 const array_type = @as(*const clang.ArrayType, @ptrCast(field_qt.getTypePtr()));983 const array_type = @as(*const clang.ArrayType, @ptrCast(field_qt_canon));
983 const element_qt = array_type.getElementType();984 const element_qt = array_type.getElementType();
984 const element_type = try transQualType(c, scope, element_qt, field_decl.getLocation());985 const element_type = try transQualType(c, scope, element_qt, field_decl.getLocation());
985986
...@@ -1049,21 +1050,33 @@ fn buildFlexibleArrayFn(...@@ -1049,21 +1050,33 @@ fn buildFlexibleArrayFn(
1049 return Node.initPayload(&payload.base);1050 return Node.initPayload(&payload.base);
1050}1051}
10511052
1053/// Return true if `field_decl` is the flexible array field for its parent record
1052fn isFlexibleArrayFieldDecl(c: *Context, field_decl: *const clang.FieldDecl) bool {1054fn isFlexibleArrayFieldDecl(c: *Context, field_decl: *const clang.FieldDecl) bool {
1053 return qualTypeCanon(field_decl.getType()).isIncompleteOrZeroLengthArrayType(c.clang_context);1055 const record_decl = field_decl.getParent() orelse return false;
1056 const record_flexible_field = flexibleArrayField(c, record_decl) orelse return false;
1057 return field_decl == record_flexible_field;
1054}1058}
10551059
1060/// Find the flexible array field for a record if any. A flexible array field is an
1061/// incomplete or zero-length array that occurs as the last field of a record.
1056/// clang's RecordDecl::hasFlexibleArrayMember is not suitable for determining1062/// clang's RecordDecl::hasFlexibleArrayMember is not suitable for determining
1057/// this because it returns false for a record that ends with a zero-length1063/// this because it returns false for a record that ends with a zero-length
1058/// array, but we consider those to be flexible arrays1064/// array, but we consider those to be flexible arrays
1059fn hasFlexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) bool {1065fn flexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) ?*const clang.FieldDecl {
1060 var it = record_def.field_begin();1066 var it = record_def.field_begin();
1061 const end_it = record_def.field_end();1067 const end_it = record_def.field_end();
1068 var flexible_field: ?*const clang.FieldDecl = null;
1062 while (it.neq(end_it)) : (it = it.next()) {1069 while (it.neq(end_it)) : (it = it.next()) {
1063 const field_decl = it.deref();1070 const field_decl = it.deref();
1064 if (isFlexibleArrayFieldDecl(c, field_decl)) return true;1071 const ty = qualTypeCanon(field_decl.getType());
1072 const incomplete_or_zero_size = ty.isIncompleteOrZeroLengthArrayType(c.clang_context);
1073 if (incomplete_or_zero_size) {
1074 flexible_field = field_decl;
1075 } else {
1076 flexible_field = null;
1077 }
1065 }1078 }
1066 return false;1079 return flexible_field;
1067}1080}
10681081
1069fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void {1082fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void {
...@@ -1117,7 +1130,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -1117,7 +1130,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1117 var functions = std.ArrayList(Node).init(c.gpa);1130 var functions = std.ArrayList(Node).init(c.gpa);
1118 defer functions.deinit();1131 defer functions.deinit();
11191132
1120 const has_flexible_array = hasFlexibleArrayField(c, record_def);1133 const flexible_field = flexibleArrayField(c, record_def);
1121 var unnamed_field_count: u32 = 0;1134 var unnamed_field_count: u32 = 0;
1122 var it = record_def.field_begin();1135 var it = record_def.field_begin();
1123 const end_it = record_def.field_end();1136 const end_it = record_def.field_end();
...@@ -1143,7 +1156,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -1143,7 +1156,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1143 unnamed_field_count += 1;1156 unnamed_field_count += 1;
1144 is_anon = true;1157 is_anon = true;
1145 }1158 }
1146 if (isFlexibleArrayFieldDecl(c, field_decl)) {1159 if (flexible_field == field_decl) {
1147 const flexible_array_fn = buildFlexibleArrayFn(c, scope, layout, field_name, field_decl) catch |err| switch (err) {1160 const flexible_array_fn = buildFlexibleArrayFn(c, scope, layout, field_name, field_decl) catch |err| switch (err) {
1148 error.UnsupportedType => {1161 error.UnsupportedType => {
1149 try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl.getCanonicalDecl()), {});1162 try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl.getCanonicalDecl()), {});
...@@ -1164,7 +1177,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -1164,7 +1177,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
1164 else => |e| return e,1177 else => |e| return e,
1165 };1178 };
11661179
1167 const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0)1180 const alignment = if (flexible_field != null and field_decl.getFieldIndex() == 0)
1168 @as(c_uint, @intCast(record_alignment))1181 @as(c_uint, @intCast(record_alignment))
1169 else1182 else
1170 ClangAlignment.forField(c, field_decl, record_def).zigAlignment();1183 ClangAlignment.forField(c, field_decl, record_def).zigAlignment();
test/run_translated_c.zig+18
...@@ -1554,6 +1554,24 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -1554,6 +1554,24 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1554 \\}1554 \\}
1555 , "");1555 , "");
15561556
1557 cases.add("Flexible array with typedefed flexible item, issue #16838",
1558 \\#include <stdlib.h>
1559 \\#include <assert.h>
1560 \\typedef int MARKER[0];
1561 \\typedef struct { int x; MARKER y; } Flexible;
1562 \\#define SIZE 10
1563 \\int main(void) {
1564 \\ Flexible *flex = malloc(sizeof(Flexible) + SIZE * sizeof(int));
1565 \\ for (int i = 0; i < SIZE; i++) {
1566 \\ flex->y[i] = i;
1567 \\ }
1568 \\ for (int i = 0; i < SIZE; i++) {
1569 \\ assert(flex->y[i] == i);
1570 \\ }
1571 \\ return 0;
1572 \\}
1573 , "");
1574
1557 cases.add("enum with value that fits in c_uint but not c_int, issue #8003",1575 cases.add("enum with value that fits in c_uint but not c_int, issue #8003",
1558 \\#include <stdlib.h>1576 \\#include <stdlib.h>
1559 \\enum my_enum {1577 \\enum my_enum {