diff --git a/cgo/libclang.go b/cgo/libclang.go index d495384e..46eff01c 100644 --- a/cgo/libclang.go +++ b/cgo/libclang.go @@ -667,7 +667,13 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD bitfieldNum := passed.bitfieldNum bitfieldList := passed.bitfieldList pos := p.getCursorPosition(c) - if cursorKind := C.tinygo_clang_getCursorKind(c); cursorKind != C.CXCursor_FieldDecl { + switch cursorKind := C.tinygo_clang_getCursorKind(c); cursorKind { + case C.CXCursor_FieldDecl: + // Expected. This is a regular field. + case C.CXCursor_StructDecl, C.CXCursor_UnionDecl: + // Ignore. The next field will be the struct/union itself. + return C.CXChildVisit_Continue + default: cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind)) p.addError(pos, fmt.Sprintf("expected FieldDecl in struct or union, not %s", cursorKindSpelling)) return C.CXChildVisit_Continue diff --git a/cgo/testdata/types.go b/cgo/testdata/types.go index 0c8668cb..2aa0982a 100644 --- a/cgo/testdata/types.go +++ b/cgo/testdata/types.go @@ -44,7 +44,23 @@ typedef union union2d { } union2d_t; typedef union { unsigned char arr[10]; -} unionarrary_t; +} unionarray_t; + +// Nested structs and unions. +typedef struct { + point2d_t begin; + point2d_t end; + int tag; + union { + point2d_t area; + point3d_t solid; + } coord; +} struct_nested_t; +typedef union { + point3d_t point; + unionarray_t array; + union3_t thing; +} union_nested_t; // Enums. These define constant numbers. All these constants must be given the // correct number. @@ -108,7 +124,11 @@ var ( _ C.union1_t _ C.union3_t _ C.union2d_t - _ C.unionarrary_t + _ C.unionarray_t + + // Nested structs and unions. + _ C.struct_nested_t + _ C.union_nested_t // Enums (anonymous and named). _ C.option_t diff --git a/cgo/testdata/types.out.go b/cgo/testdata/types.out.go index d0fcc5a2..8a750080 100644 --- a/cgo/testdata/types.out.go +++ b/cgo/testdata/types.out.go @@ -34,7 +34,7 @@ type C.uint uint32 type C.ulong uint32 type C.ulonglong uint64 type C.ushort uint16 -type C.bitfield_t = C.struct_2 +type C.bitfield_t = C.struct_4 type C.myIntArray = [10]C.int type C.myint = C.int type C.option2_t = C.uint @@ -44,6 +44,13 @@ type C.point2d_t = struct { y C.int } type C.point3d_t = C.struct_point3d +type C.struct_nested_t = struct { + begin C.point2d_t + end C.point2d_t + tag C.int + + coord C.union_2 +} type C.types_t = struct { f float32 d float64 @@ -52,22 +59,23 @@ type C.types_t = struct { type C.union1_t = struct{ i C.int } type C.union2d_t = C.union_union2d type C.union3_t = C.union_1 -type C.unionarrary_t = struct{ arr [10]C.uchar } +type C.union_nested_t = C.union_3 +type C.unionarray_t = struct{ arr [10]C.uchar } -func (s *C.struct_2) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f } -func (s *C.struct_2) set_bitfield_a(value C.uchar) { s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0 } -func (s *C.struct_2) bitfield_b() C.uchar { +func (s *C.struct_4) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f } +func (s *C.struct_4) set_bitfield_a(value C.uchar) { s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0 } +func (s *C.struct_4) bitfield_b() C.uchar { return s.__bitfield_1 >> 5 & 0x1 } -func (s *C.struct_2) set_bitfield_b(value C.uchar) { s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5 } -func (s *C.struct_2) bitfield_c() C.uchar { +func (s *C.struct_4) set_bitfield_b(value C.uchar) { s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5 } +func (s *C.struct_4) bitfield_c() C.uchar { return s.__bitfield_1 >> 6 } -func (s *C.struct_2) set_bitfield_c(value C.uchar, +func (s *C.struct_4) set_bitfield_c(value C.uchar, ) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 } -type C.struct_2 struct { +type C.struct_4 struct { start C.uchar __bitfield_1 C.uchar @@ -92,6 +100,17 @@ func (union *C.union_1) unionfield_s() *C.short { return (*C.short)(unsafe.Point type C.union_1 struct{ $union uint64 } +func (union *C.union_2) unionfield_area() *C.point2d_t { return (*C.point2d_t)(unsafe.Pointer(&union.$union)) } +func (union *C.union_2) unionfield_solid() *C.point3d_t { return (*C.point3d_t)(unsafe.Pointer(&union.$union)) } + +type C.union_2 struct{ $union [3]uint32 } + +func (union *C.union_3) unionfield_point() *C.point3d_t { return (*C.point3d_t)(unsafe.Pointer(&union.$union)) } +func (union *C.union_3) unionfield_array() *C.unionarray_t { return (*C.unionarray_t)(unsafe.Pointer(&union.$union)) } +func (union *C.union_3) unionfield_thing() *C.union3_t { return (*C.union3_t)(unsafe.Pointer(&union.$union)) } + +type C.union_3 struct{ $union [2]uint64 } + func (union *C.union_union2d) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) } func (union *C.union_union2d) unionfield_d() *[2]float64 { return (*[2]float64)(unsafe.Pointer(&union.$union)) } diff --git a/testdata/cgo/main.go b/testdata/cgo/main.go index 9a111243..41bc6892 100644 --- a/testdata/cgo/main.go +++ b/testdata/cgo/main.go @@ -80,6 +80,11 @@ func main() { var _ C.point2d_t = C.point2d_t{x: 3, y: 5} var _ C.point3d_t = C.point3d_t{x: 3, y: 5, z: 7} + // nested structs/unions + var _ C.tagged_union_t + var _ C.nested_struct_t + var _ C.nested_union_t + // recursive types, test using a linked list list := &C.list_t{n: 3, next: &C.struct_list_t{n: 6, next: &C.list_t{n: 7, next: nil}}} for list != nil { diff --git a/testdata/cgo/main.h b/testdata/cgo/main.h index 7f414a84..d38b3322 100644 --- a/testdata/cgo/main.h +++ b/testdata/cgo/main.h @@ -43,6 +43,31 @@ typedef struct { int z; } point3d_t; +typedef struct { + int tag; + union { + int a; + int b; + } u; +} tagged_union_t; + +typedef struct { + int x; + struct { + char red; + char green; + char blue; + } color; +} nested_struct_t; + +typedef union { + int x; + struct { + char a; + char b; + }; +} nested_union_t; + // linked list typedef struct list_t { int n;