Commit 692a974c3e

Vexu <git@vexu.eu>
2020-03-08 11:07:26
translate-c reject structs with VLAs
1 parent 5aa993c
Changed files (5)
src/zig_clang.cpp
@@ -1881,6 +1881,26 @@ bool ZigClangType_isRecordType(const ZigClangType *self) {
     return casted->isRecordType();
 }
 
+bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self,
+        const struct ZigClangASTContext *ctx)
+{
+    auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx);
+    auto casted = reinterpret_cast<const clang::QualType *>(self);
+    auto casted_type = reinterpret_cast<const clang::Type *>(self);
+    if (casted_type->isIncompleteArrayType())
+        return true;
+
+    clang::QualType elem_type = *casted;   
+    while (const clang::ConstantArrayType *ArrayT = casted_ctx->getAsConstantArrayType(elem_type)) {
+        if (ArrayT->getSize() == 0)
+            return true;
+
+        elem_type = ArrayT->getElementType();
+    }
+
+    return false;
+}
+
 bool ZigClangType_isConstantArrayType(const ZigClangType *self) {
     auto casted = reinterpret_cast<const clang::Type *>(self);
     return casted->isConstantArrayType();
src/zig_clang.h
@@ -947,6 +947,7 @@ ZIG_EXTERN_C bool ZigClangType_isBooleanType(const struct ZigClangType *self);
 ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self);
 ZIG_EXTERN_C bool ZigClangType_isArrayType(const struct ZigClangType *self);
 ZIG_EXTERN_C bool ZigClangType_isRecordType(const struct ZigClangType *self);
+ZIG_EXTERN_C bool ZigClangType_isIncompleteOrZeroLengthArrayType(const ZigClangQualType *self, const struct ZigClangASTContext *ctx);
 ZIG_EXTERN_C bool ZigClangType_isConstantArrayType(const ZigClangType *self);
 ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self);
 ZIG_EXTERN_C const struct ZigClangArrayType *ZigClangType_getAsArrayTypeUnsafe(const struct ZigClangType *self);
src-self-hosted/clang.zig
@@ -812,6 +812,7 @@ pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) str
 pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool;
 pub extern fn ZigClangType_isConstantArrayType(self: ?*const struct_ZigClangType) bool;
 pub extern fn ZigClangType_isRecordType(self: ?*const struct_ZigClangType) bool;
+pub extern fn ZigClangType_isIncompleteOrZeroLengthArrayType(self: ?*const struct_ZigClangType, *const ZigClangASTContext) bool;
 pub extern fn ZigClangType_isArrayType(self: ?*const struct_ZigClangType) bool;
 pub extern fn ZigClangType_isBooleanType(self: ?*const struct_ZigClangType) bool;
 pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8;
src-self-hosted/translate_c.zig
@@ -793,6 +793,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
         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);
+            const field_qt = ZigClangFieldDecl_getType(field_decl);
 
             if (ZigClangFieldDecl_isBitField(field_decl)) {
                 const opaque = try transCreateNodeOpaqueType(c);
@@ -801,6 +802,13 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
                 break :blk opaque;
             }
 
+            if (ZigClangType_isIncompleteOrZeroLengthArrayType(qualTypeCanon(field_qt), c.clang_context)) {
+                const opaque = try transCreateNodeOpaqueType(c);
+                semicolon = try appendToken(c, .Semicolon, ";");
+                try emitWarning(c, field_loc, "{} demoted to opaque type - has variable length array", .{container_kind_name});
+                break :blk opaque;
+            }
+
             var is_anon = false;
             var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
             if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
@@ -809,7 +817,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
             }
             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) {
+            const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
                 error.UnsupportedType => {
                     const opaque = try transCreateNodeOpaqueType(c);
                     semicolon = try appendToken(c, .Semicolon, ";");
@@ -5600,7 +5608,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
             },
             .Ampersand => {
                 op_token = try appendToken(c, .Ampersand, "&");
-                op_id= .BitAnd;
+                op_id = .BitAnd;
             },
             .Plus => {
                 op_token = try appendToken(c, .Plus, "+");
@@ -5608,7 +5616,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
             },
             .Minus => {
                 op_token = try appendToken(c, .Minus, "-");
-                op_id= .Sub;
+                op_id = .Sub;
             },
             .AmpersandAmpersand => {
                 op_token = try appendToken(c, .Keyword_and, "and");
test/translate_c.zig
@@ -3,6 +3,15 @@ const std = @import("std");
 const CrossTarget = std.zig.CrossTarget;
 
 pub fn addCases(cases: *tests.TranslateCContext) void {
+    cases.add("structs with VLAs are rejected",
+        \\struct foo { int x; int y[]; };
+        \\struct bar { int x; int y[0]; };
+    , &[_][]const u8{
+        \\pub const struct_foo = @OpaqueType();
+    ,
+        \\pub const struct_bar = @OpaqueType();
+    });
+
     cases.add("nested loops without blocks",
         \\void foo() {
         \\    while (0) while (0) {}