mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-11 06:23:39 +00:00
cgo: implement C unions
Unions are somewhat hard to implement in Go because they are not a native type. But it is actually possible with some compiler magic. This commit inserts a special "C union" field at the start of a struct to indicate that it is a union. As such a field cannot be written directly in Go, this is a useful to distinguish structs and unions.
This commit is contained in:
committed by
Ron Evans
parent
536086988c
commit
d2b3a5486c
+41
-9
@@ -306,18 +306,50 @@ func (info *fileInfo) makeASTType(typ C.CXType) ast.Expr {
|
||||
return info.makeASTType(underlying)
|
||||
case C.CXType_Record:
|
||||
cursor := C.clang_getTypeDeclaration(typ)
|
||||
fieldList := &ast.FieldList{
|
||||
Opening: info.importCPos,
|
||||
Closing: info.importCPos,
|
||||
}
|
||||
ref := refMap.Put(struct {
|
||||
fieldList *ast.FieldList
|
||||
info *fileInfo
|
||||
}{fieldList, info})
|
||||
defer refMap.Remove(ref)
|
||||
C.clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(uintptr(ref)))
|
||||
switch C.clang_getCursorKind(cursor) {
|
||||
case C.CXCursor_StructDecl:
|
||||
fieldList := &ast.FieldList{
|
||||
Opening: info.importCPos,
|
||||
Closing: info.importCPos,
|
||||
return &ast.StructType{
|
||||
Struct: info.importCPos,
|
||||
Fields: fieldList,
|
||||
}
|
||||
case C.CXCursor_UnionDecl:
|
||||
if len(fieldList.List) > 1 {
|
||||
// Insert a special field at the front (of zero width) as a
|
||||
// marker that this is struct is actually a union. This is done
|
||||
// by giving the field a name that cannot be expressed directly
|
||||
// in Go.
|
||||
// Other parts of the compiler look at the first element in a
|
||||
// struct (of size > 2) to know whether this is a union.
|
||||
// Note that we don't have to insert it for single-element
|
||||
// unions as they're basically equivalent to a struct.
|
||||
unionMarker := &ast.Field{
|
||||
Type: &ast.StructType{
|
||||
Struct: info.importCPos,
|
||||
},
|
||||
}
|
||||
unionMarker.Names = []*ast.Ident{
|
||||
&ast.Ident{
|
||||
NamePos: info.importCPos,
|
||||
Name: "C union",
|
||||
Obj: &ast.Object{
|
||||
Kind: ast.Var,
|
||||
Name: "C union",
|
||||
Decl: unionMarker,
|
||||
},
|
||||
},
|
||||
}
|
||||
fieldList.List = append([]*ast.Field{unionMarker}, fieldList.List...)
|
||||
}
|
||||
ref := refMap.Put(struct {
|
||||
fieldList *ast.FieldList
|
||||
info *fileInfo
|
||||
}{fieldList, info})
|
||||
defer refMap.Remove(ref)
|
||||
C.clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(uintptr(ref)))
|
||||
return &ast.StructType{
|
||||
Struct: info.importCPos,
|
||||
Fields: fieldList,
|
||||
|
||||
Reference in New Issue
Block a user