diff --git a/bindgen/TypeTranslator.cpp b/bindgen/TypeTranslator.cpp index 553e39a..f60630b 100644 --- a/bindgen/TypeTranslator.cpp +++ b/bindgen/TypeTranslator.cpp @@ -193,17 +193,21 @@ TypeTranslator::addUnionDefinition(clang::RecordDecl *record, std::string name) { std::vector> fields; + int anonIdField = 0; for (const clang::FieldDecl *field : record->fields()) { - std::string fname = field->getNameAsString(); std::shared_ptr ftype = translate(field->getType()); + std::string fname = field->getNameAsString(); + if (fname.empty()) { + fname = "unnamed_" + std::to_string(anonIdField++); + } fields.push_back(std::make_shared(fname, ftype)); } uint64_t sizeInBits = ctx->getTypeSize(record->getTypeForDecl()); assert(sizeInBits % 8 == 0); - return ir.addUnion(name, std::move(fields), sizeInBits / 8, + return ir.addUnion(std::move(name), std::move(fields), sizeInBits / 8, getLocation(record)); } @@ -222,6 +226,7 @@ TypeTranslator::addStructDefinition(clang::RecordDecl *record, ctx->getASTRecordLayout(record); bool isBitFieldStruct = false; + int anonIdField = 0; for (const clang::FieldDecl *field : record->fields()) { if (field->isBitField()) { isBitFieldStruct = true; @@ -229,8 +234,12 @@ TypeTranslator::addStructDefinition(clang::RecordDecl *record, std::shared_ptr ftype = translate(field->getType()); uint64_t recordOffsetInBits = recordLayout.getFieldOffset(field->getFieldIndex()); - fields.push_back(std::make_shared(field->getNameAsString(), - ftype, recordOffsetInBits)); + std::string fname = field->getNameAsString(); + if (fname.empty()) { + fname = "unnamed_" + std::to_string(anonIdField++); + } + fields.push_back( + std::make_shared(fname, ftype, recordOffsetInBits)); } uint64_t sizeInBits = ctx->getTypeSize(record->getTypeForDecl()); diff --git a/tests/samples/Struct.c b/tests/samples/Struct.c index cce03f8..bc6affc 100644 --- a/tests/samples/Struct.c +++ b/tests/samples/Struct.c @@ -34,10 +34,14 @@ char getCharFromAnonymousStruct(struct structWithAnonymousStruct *s) { return s->anonymousStruct.c; } -char getIntFromAnonymousStruct(struct structWithAnonymousStruct *s) { +int getIntFromAnonymousStruct(struct structWithAnonymousStruct *s) { return s->anonymousStruct.i; } +int getFieldOfUnnamedStruct(struct structWithAnonymousStruct *s) { + return s->b; +} + int struct_test_long(struct bigStruct *s, enum struct_op op, long value) { switch (op) { case STRUCT_SET: diff --git a/tests/samples/Struct.h b/tests/samples/Struct.h index 823d935..587360b 100644 --- a/tests/samples/Struct.h +++ b/tests/samples/Struct.h @@ -54,6 +54,10 @@ struct structWithAnonymousStruct { char c; int i; } anonymousStruct; + + struct { + int b; + }; }; struct __attribute__((__packed__)) packedStruct { // no helper methods @@ -75,7 +79,9 @@ struct bitFieldOffsetDivByEight { // no helper methods char getCharFromAnonymousStruct(struct structWithAnonymousStruct *s); -char getIntFromAnonymousStruct(struct structWithAnonymousStruct *s); +int getIntFromAnonymousStruct(struct structWithAnonymousStruct *s); + +int getFieldOfUnnamedStruct(struct structWithAnonymousStruct *s); enum struct_op { STRUCT_SET, STRUCT_TEST }; diff --git a/tests/samples/Struct.scala b/tests/samples/Struct.scala index 75e4683..015b0c2 100644 --- a/tests/samples/Struct.scala +++ b/tests/samples/Struct.scala @@ -26,7 +26,8 @@ object Struct { type point_s = native.Ptr[struct_point] type struct_bigStruct = native.CArray[Byte, native.Nat.Digit[native.Nat._1, native.Nat.Digit[native.Nat._1, native.Nat._2]]] type struct_anonymous_0 = native.CStruct2[native.CChar, native.CInt] - type struct_structWithAnonymousStruct = native.CStruct2[native.CInt, struct_anonymous_0] + type struct_anonymous_1 = native.CStruct1[native.CInt] + type struct_structWithAnonymousStruct = native.CStruct3[native.CInt, struct_anonymous_0, struct_anonymous_1] type struct_packedStruct = native.CStruct1[native.CChar] type struct_bitFieldStruct = native.CArray[Byte, native.Nat._2] type struct_bitFieldOffsetDivByEight = native.CArray[Byte, native.Nat._4] @@ -35,7 +36,8 @@ object Struct { def createPoint(): native.Ptr[struct_point] = native.extern def getBigStructSize(): native.CInt = native.extern def getCharFromAnonymousStruct(s: native.Ptr[struct_structWithAnonymousStruct]): native.CChar = native.extern - def getIntFromAnonymousStruct(s: native.Ptr[struct_structWithAnonymousStruct]): native.CChar = native.extern + def getIntFromAnonymousStruct(s: native.Ptr[struct_structWithAnonymousStruct]): native.CInt = native.extern + def getFieldOfUnnamedStruct(s: native.Ptr[struct_structWithAnonymousStruct]): native.CInt = native.extern def struct_test_long(s: native.Ptr[struct_bigStruct], op: enum_struct_op, value: native.CLong): native.CInt = native.extern def struct_test_double(s: native.Ptr[struct_bigStruct], op: enum_struct_op, value: native.CDouble): native.CInt = native.extern def struct_test_point(s: native.Ptr[struct_bigStruct], op: enum_struct_op, value: native.Ptr[struct_point]): native.CInt = native.extern @@ -111,11 +113,18 @@ object Struct { def i_=(value: native.CInt): Unit = !p._2 = value } + implicit class struct_anonymous_1_ops(val p: native.Ptr[struct_anonymous_1]) extends AnyVal { + def b: native.CInt = !p._1 + def b_=(value: native.CInt): Unit = !p._1 = value + } + implicit class struct_structWithAnonymousStruct_ops(val p: native.Ptr[struct_structWithAnonymousStruct]) extends AnyVal { def a: native.CInt = !p._1 def a_=(value: native.CInt): Unit = !p._1 = value def anonymousStruct: native.Ptr[struct_anonymous_0] = p._2 def anonymousStruct_=(value: native.Ptr[struct_anonymous_0]): Unit = !p._2 = !value + def unnamed_0: native.Ptr[struct_anonymous_1] = p._3 + def unnamed_0_=(value: native.Ptr[struct_anonymous_1]): Unit = !p._3 = !value } } @@ -184,13 +193,24 @@ object Struct { } } + object struct_anonymous_1 { + import implicits._ + def apply()(implicit z: native.Zone): native.Ptr[struct_anonymous_1] = native.alloc[struct_anonymous_1] + def apply(b: native.CInt)(implicit z: native.Zone): native.Ptr[struct_anonymous_1] = { + val ptr = native.alloc[struct_anonymous_1] + ptr.b = b + ptr + } + } + object struct_structWithAnonymousStruct { import implicits._ def apply()(implicit z: native.Zone): native.Ptr[struct_structWithAnonymousStruct] = native.alloc[struct_structWithAnonymousStruct] - def apply(a: native.CInt, anonymousStruct: native.Ptr[struct_anonymous_0])(implicit z: native.Zone): native.Ptr[struct_structWithAnonymousStruct] = { + def apply(a: native.CInt, anonymousStruct: native.Ptr[struct_anonymous_0], unnamed_0: native.Ptr[struct_anonymous_1])(implicit z: native.Zone): native.Ptr[struct_structWithAnonymousStruct] = { val ptr = native.alloc[struct_structWithAnonymousStruct] ptr.a = a ptr.anonymousStruct = anonymousStruct + ptr.unnamed_0 = unnamed_0 ptr } } diff --git a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructSpec.scala b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructSpec.scala index e5d2a4d..46a97f2 100644 --- a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructSpec.scala +++ b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructSpec.scala @@ -72,6 +72,21 @@ class StructSpec extends FunSpec { } } + it("should support unnamed structs") { + type struct_unnamedStruct = CStruct1[CInt] + Zone { implicit zone => + val unnamedStruct: Ptr[struct_unnamedStruct] = + alloc[struct_unnamedStruct] + !unnamedStruct._1 = 42 + + val structWithAnonymousStruct = + Struct.struct_structWithAnonymousStruct() + structWithAnonymousStruct.unnamed_0 = unnamedStruct + + assert(42 == Struct.getFieldOfUnnamedStruct(structWithAnonymousStruct)) + } + } + it("should match size of C memory layout for big structs") { assert(Struct.getBigStructSize() == sizeof[Struct.struct_bigStruct]) }