diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index bdaa8b86dc..3a3b4ac196 100644 --- a/src-self-hosted/clang.zig +++ b/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; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index b2eb96f2ae..be3e43f3d7 100644 --- a/src-self-hosted/translate_c.zig +++ b/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"); diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 8a1baa2d49..c5ea182e87 100644 --- a/src/zig_clang.cpp +++ b/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(ctx); + auto casted = reinterpret_cast(self); + auto casted_type = reinterpret_cast(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(self); return casted->isConstantArrayType(); diff --git a/src/zig_clang.h b/src/zig_clang.h index 2d9485ae9b..579812a84a 100644 --- a/src/zig_clang.h +++ b/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); diff --git a/test/translate_c.zig b/test/translate_c.zig index a791d0ccad..209a301f88 100644 --- a/test/translate_c.zig +++ b/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) {}