This is a large refactor of the cgo package. It should fix a number of
smaller problems and be a bit more strict (like upstream CGo): it for
example requires every Go file in a package to include the header files
it needs instead of piggybacking on imports in earlier files.

The main benefit is that it should be a bit more maintainable and easier
to add new features in the future (like static functions).

This breaks the tinygo.org/x/bluetooth package, which should be updated
before this change lands.
Этот коммит содержится в:
Ayke van Laethem 2022-02-20 19:54:52 +01:00 коммит произвёл Ron Evans
родитель 1d2c39c3b9
коммит 5afb63df60
9 изменённых файлов: 925 добавлений и 945 удалений

Различия файлов не показаны, т.к. их слишком много Показать различия

Просмотреть файл

@ -72,7 +72,11 @@ var diagnosticSeverity = [...]string{
C.CXDiagnostic_Fatal: "fatal", C.CXDiagnostic_Fatal: "fatal",
} }
func (p *cgoPackage) parseFragment(fragment string, cflags []string, filename string) { // Alias so that cgo.go (which doesn't import Clang related stuff and is in
// theory decoupled from Clang) can also use this type.
type clangCursor = C.GoCXCursor
func (f *cgoFile) readNames(fragment string, cflags []string, filename string, callback func(map[string]clangCursor)) {
index := C.clang_createIndex(0, 0) index := C.clang_createIndex(0, 0)
defer C.clang_disposeIndex(index) defer C.clang_disposeIndex(index)
@ -119,8 +123,8 @@ func (p *cgoPackage) parseFragment(fragment string, cflags []string, filename st
spelling := getString(C.clang_getDiagnosticSpelling(diagnostic)) spelling := getString(C.clang_getDiagnosticSpelling(diagnostic))
severity := diagnosticSeverity[C.clang_getDiagnosticSeverity(diagnostic)] severity := diagnosticSeverity[C.clang_getDiagnosticSeverity(diagnostic)]
location := C.clang_getDiagnosticLocation(diagnostic) location := C.clang_getDiagnosticLocation(diagnostic)
pos := p.getClangLocationPosition(location, unit) pos := f.getClangLocationPosition(location, unit)
p.addError(pos, severity+": "+spelling) f.addError(pos, severity+": "+spelling)
} }
for i := 0; i < numDiagnostics; i++ { for i := 0; i < numDiagnostics; i++ {
diagnostic := C.clang_getDiagnostic(unit, C.uint(i)) diagnostic := C.clang_getDiagnostic(unit, C.uint(i))
@ -135,7 +139,7 @@ func (p *cgoPackage) parseFragment(fragment string, cflags []string, filename st
} }
// Extract information required by CGo. // Extract information required by CGo.
ref := storedRefs.Put(p) ref := storedRefs.Put(f)
defer storedRefs.Remove(ref) defer storedRefs.Remove(ref)
cursor := C.tinygo_clang_getTranslationUnitCursor(unit) cursor := C.tinygo_clang_getTranslationUnitCursor(unit)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_globals_visitor), C.CXClientData(ref)) C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_globals_visitor), C.CXClientData(ref))
@ -155,35 +159,64 @@ func (p *cgoPackage) parseFragment(fragment string, cflags []string, filename st
data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size] data := (*[1 << 24]byte)(unsafe.Pointer(rawData))[:size]
// Hash the contents if it isn't hashed yet. // Hash the contents if it isn't hashed yet.
if _, ok := p.visitedFiles[path]; !ok { if _, ok := f.visitedFiles[path]; !ok {
// already stored // already stored
sum := sha512.Sum512_224(data) sum := sha512.Sum512_224(data)
p.visitedFiles[path] = sum[:] f.visitedFiles[path] = sum[:]
} }
} }
inclusionCallbackRef := storedRefs.Put(inclusionCallback) inclusionCallbackRef := storedRefs.Put(inclusionCallback)
defer storedRefs.Remove(inclusionCallbackRef) defer storedRefs.Remove(inclusionCallbackRef)
C.clang_getInclusions(unit, C.CXInclusionVisitor(C.tinygo_clang_inclusion_visitor), C.CXClientData(inclusionCallbackRef)) C.clang_getInclusions(unit, C.CXInclusionVisitor(C.tinygo_clang_inclusion_visitor), C.CXClientData(inclusionCallbackRef))
// Do all the C AST operations inside a callback. This makes sure that
// libclang related memory is only freed after it is not necessary anymore.
callback(f.names)
} }
//export tinygo_clang_globals_visitor // Convert the AST node under the given Clang cursor to a Go AST node and return
func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int { // it.
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage) func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaboratedTypeInfo) {
kind := C.tinygo_clang_getCursorKind(c) kind := C.tinygo_clang_getCursorKind(c)
pos := p.getCursorPosition(c) pos := f.getCursorPosition(c)
switch kind { switch kind {
case C.CXCursor_FunctionDecl: case C.CXCursor_FunctionDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if _, required := p.missingSymbols[name]; !required {
return C.CXChildVisit_Continue
}
cursorType := C.tinygo_clang_getCursorType(c) cursorType := C.tinygo_clang_getCursorType(c)
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c)) numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
fn := &functionInfo{ obj := &ast.Object{
pos: pos, Kind: ast.Fun,
variadic: C.clang_isFunctionTypeVariadic(cursorType) != 0, Name: "C." + name,
}
args := make([]*ast.Field, numArgs)
decl := &ast.FuncDecl{
Doc: &ast.CommentGroup{
List: []*ast.Comment{
{
Slash: pos - 1,
Text: "//export " + name,
},
},
},
Name: &ast.Ident{
NamePos: pos,
Name: "C." + name,
Obj: obj,
},
Type: &ast.FuncType{
Func: pos,
Params: &ast.FieldList{
Opening: pos,
List: args,
Closing: pos,
},
},
}
if C.clang_isFunctionTypeVariadic(cursorType) != 0 {
decl.Doc.List = append(decl.Doc.List, &ast.Comment{
Slash: pos - 1,
Text: "//go:variadic",
})
} }
p.functions[name] = fn
for i := 0; i < numArgs; i++ { for i := 0; i < numArgs; i++ {
arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i)) arg := C.tinygo_clang_Cursor_getArgument(c, C.uint(i))
argName := getString(C.tinygo_clang_getCursorSpelling(arg)) argName := getString(C.tinygo_clang_getCursorSpelling(arg))
@ -191,50 +224,108 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
if argName == "" { if argName == "" {
argName = "$" + strconv.Itoa(i) argName = "$" + strconv.Itoa(i)
} }
fn.args = append(fn.args, paramInfo{ args[i] = &ast.Field{
name: argName, Names: []*ast.Ident{
typeExpr: p.makeDecayingASTType(argType, pos), {
}) NamePos: pos,
Name: argName,
Obj: &ast.Object{
Kind: ast.Var,
Name: argName,
Decl: decl,
},
},
},
Type: f.makeDecayingASTType(argType, pos),
}
} }
resultType := C.tinygo_clang_getCursorResultType(c) resultType := C.tinygo_clang_getCursorResultType(c)
if resultType.kind != C.CXType_Void { if resultType.kind != C.CXType_Void {
fn.results = &ast.FieldList{ decl.Type.Results = &ast.FieldList{
List: []*ast.Field{ List: []*ast.Field{
{ {
Type: p.makeASTType(resultType, pos), Type: f.makeASTType(resultType, pos),
}, },
}, },
} }
} }
case C.CXCursor_StructDecl: obj.Decl = decl
typ := C.tinygo_clang_getCursorType(c) return decl, nil
name := getString(C.tinygo_clang_getCursorSpelling(c)) case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
if _, required := p.missingSymbols["struct_"+name]; !required { typ := f.makeASTRecordType(c, pos)
return C.CXChildVisit_Continue typeName := "C." + name
typeExpr := typ.typeExpr
if typ.unionSize != 0 {
// Convert to a single-field struct type.
typeExpr = f.makeUnionField(typ)
} }
p.makeASTType(typ, pos) obj := &ast.Object{
Kind: ast.Typ,
Name: typeName,
}
typeSpec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: typ.pos,
Name: typeName,
Obj: obj,
},
Type: typeExpr,
}
obj.Decl = typeSpec
return typeSpec, typ
case C.CXCursor_TypedefDecl: case C.CXCursor_TypedefDecl:
typedefType := C.tinygo_clang_getCursorType(c) typeName := "C." + name
name := getString(C.clang_getTypedefName(typedefType)) underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
if _, required := p.missingSymbols[name]; !required { obj := &ast.Object{
return C.CXChildVisit_Continue Kind: ast.Typ,
Name: typeName,
} }
p.makeASTType(typedefType, pos) typeSpec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: pos,
Name: typeName,
Obj: obj,
},
Type: f.makeASTType(underlyingType, pos),
}
if underlyingType.kind != C.CXType_Enum {
typeSpec.Assign = pos
}
obj.Decl = typeSpec
return typeSpec, nil
case C.CXCursor_VarDecl: case C.CXCursor_VarDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if _, required := p.missingSymbols[name]; !required {
return C.CXChildVisit_Continue
}
cursorType := C.tinygo_clang_getCursorType(c) cursorType := C.tinygo_clang_getCursorType(c)
p.globals[name] = globalInfo{ typeExpr := f.makeASTType(cursorType, pos)
typeExpr: p.makeASTType(cursorType, pos), gen := &ast.GenDecl{
pos: pos, TokPos: pos,
Tok: token.VAR,
Lparen: token.NoPos,
Rparen: token.NoPos,
Doc: &ast.CommentGroup{
List: []*ast.Comment{
{
Slash: pos - 1,
Text: "//go:extern " + name,
},
},
},
} }
obj := &ast.Object{
Kind: ast.Var,
Name: "C." + name,
}
valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{
NamePos: pos,
Name: "C." + name,
Obj: obj,
}},
Type: typeExpr,
}
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec)
return gen, nil
case C.CXCursor_MacroDefinition: case C.CXCursor_MacroDefinition:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if _, required := p.missingSymbols[name]; !required {
return C.CXChildVisit_Continue
}
sourceRange := C.tinygo_clang_getCursorExtent(c) sourceRange := C.tinygo_clang_getCursorExtent(c)
start := C.clang_getRangeStart(sourceRange) start := C.clang_getRangeStart(sourceRange)
end := C.clang_getRangeEnd(sourceRange) end := C.clang_getRangeEnd(sourceRange)
@ -242,17 +333,17 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
var startOffset, endOffset C.unsigned var startOffset, endOffset C.unsigned
C.clang_getExpansionLocation(start, &file, nil, nil, &startOffset) C.clang_getExpansionLocation(start, &file, nil, nil, &startOffset)
if file == nil { if file == nil {
p.addError(pos, "internal error: could not find file where macro is defined") f.addError(pos, "internal error: could not find file where macro is defined")
break return nil, nil
} }
C.clang_getExpansionLocation(end, &endFile, nil, nil, &endOffset) C.clang_getExpansionLocation(end, &endFile, nil, nil, &endOffset)
if file != endFile { if file != endFile {
p.addError(pos, "internal error: expected start and end location of a macro to be in the same file") f.addError(pos, "internal error: expected start and end location of a macro to be in the same file")
break return nil, nil
} }
if startOffset > endOffset { if startOffset > endOffset {
p.addError(pos, "internal error: start offset of macro is after end offset") f.addError(pos, "internal error: start offset of macro is after end offset")
break return nil, nil
} }
// read file contents and extract the relevant byte range // read file contents and extract the relevant byte range
@ -260,31 +351,94 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
var size C.size_t var size C.size_t
sourcePtr := C.clang_getFileContents(tu, file, &size) sourcePtr := C.clang_getFileContents(tu, file, &size)
if endOffset >= C.uint(size) { if endOffset >= C.uint(size) {
p.addError(pos, "internal error: end offset of macro lies after end of file") f.addError(pos, "internal error: end offset of macro lies after end of file")
break return nil, nil
} }
source := string(((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[startOffset:endOffset:endOffset]) source := string(((*[1 << 28]byte)(unsafe.Pointer(sourcePtr)))[startOffset:endOffset:endOffset])
if !strings.HasPrefix(source, name) { if !strings.HasPrefix(source, name) {
p.addError(pos, fmt.Sprintf("internal error: expected macro value to start with %#v, got %#v", name, source)) f.addError(pos, fmt.Sprintf("internal error: expected macro value to start with %#v, got %#v", name, source))
break return nil, nil
} }
value := source[len(name):] value := source[len(name):]
// Try to convert this #define into a Go constant expression. // Try to convert this #define into a Go constant expression.
expr, scannerError := parseConst(pos+token.Pos(len(name)), p.fset, value) expr, scannerError := parseConst(pos+token.Pos(len(name)), f.fset, value)
if scannerError != nil { if scannerError != nil {
p.errors = append(p.errors, *scannerError) f.errors = append(f.errors, *scannerError)
return nil, nil
} }
if expr != nil {
// Parsing was successful. gen := &ast.GenDecl{
p.constants[name] = constantInfo{expr, pos} TokPos: token.NoPos,
Tok: token.CONST,
Lparen: token.NoPos,
Rparen: token.NoPos,
} }
obj := &ast.Object{
Kind: ast.Con,
Name: "C." + name,
}
valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{
NamePos: pos,
Name: "C." + name,
Obj: obj,
}},
Values: []ast.Expr{expr},
}
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec)
return gen, nil
case C.CXCursor_EnumDecl: case C.CXCursor_EnumDecl:
// Visit all enums, because the fields may be used even when the enum obj := &ast.Object{
// type itself is not. Kind: ast.Typ,
typ := C.tinygo_clang_getCursorType(c) Name: "C." + name,
p.makeASTType(typ, pos) }
underlying := C.tinygo_clang_getEnumDeclIntegerType(c)
// TODO: gc's CGo implementation uses types such as `uint32` for enums
// instead of types such as C.int, which are used here.
typeSpec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: pos,
Name: "C." + name,
Obj: obj,
},
Assign: pos,
Type: f.makeASTType(underlying, pos),
}
obj.Decl = typeSpec
return typeSpec, nil
case C.CXCursor_EnumConstantDecl:
value := C.tinygo_clang_getEnumConstantDeclValue(c)
expr := &ast.BasicLit{
ValuePos: pos,
Kind: token.INT,
Value: strconv.FormatInt(int64(value), 10),
}
gen := &ast.GenDecl{
TokPos: token.NoPos,
Tok: token.CONST,
Lparen: token.NoPos,
Rparen: token.NoPos,
}
obj := &ast.Object{
Kind: ast.Con,
Name: "C." + name,
}
valueSpec := &ast.ValueSpec{
Names: []*ast.Ident{{
NamePos: pos,
Name: "C." + name,
Obj: obj,
}},
Values: []ast.Expr{expr},
}
obj.Decl = valueSpec
gen.Specs = append(gen.Specs, valueSpec)
return gen, nil
default:
f.addError(pos, fmt.Sprintf("internal error: unknown cursor type: %d", kind))
return nil, nil
} }
return C.CXChildVisit_Continue
} }
func getString(clangString C.CXString) (s string) { func getString(clangString C.CXString) (s string) {
@ -294,6 +448,49 @@ func getString(clangString C.CXString) (s string) {
return return
} }
//export tinygo_clang_globals_visitor
func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
f := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoFile)
switch C.tinygo_clang_getCursorKind(c) {
case C.CXCursor_FunctionDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
f.names[name] = c
case C.CXCursor_StructDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if name != "" {
f.names["struct_"+name] = c
}
case C.CXCursor_UnionDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if name != "" {
f.names["union_"+name] = c
}
case C.CXCursor_TypedefDecl:
typedefType := C.tinygo_clang_getCursorType(c)
name := getString(C.clang_getTypedefName(typedefType))
f.names[name] = c
case C.CXCursor_VarDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
f.names[name] = c
case C.CXCursor_MacroDefinition:
name := getString(C.tinygo_clang_getCursorSpelling(c))
f.names[name] = c
case C.CXCursor_EnumDecl:
name := getString(C.tinygo_clang_getCursorSpelling(c))
if name != "" {
// Named enum, which can be referenced from Go using C.enum_foo.
f.names["enum_"+name] = c
}
// The enum fields are in global scope, so recurse to visit them.
return C.CXChildVisit_Recurse
case C.CXCursor_EnumConstantDecl:
// We arrive here because of the "Recurse" above.
name := getString(C.tinygo_clang_getCursorSpelling(c))
f.names[name] = c
}
return C.CXChildVisit_Continue
}
// getCursorPosition returns a usable token.Pos from a libclang cursor. // getCursorPosition returns a usable token.Pos from a libclang cursor.
func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos { func (p *cgoPackage) getCursorPosition(cursor C.GoCXCursor) token.Pos {
return p.getClangLocationPosition(C.tinygo_clang_getCursorLocation(cursor), C.tinygo_clang_Cursor_getTranslationUnit(cursor)) return p.getClangLocationPosition(C.tinygo_clang_getCursorLocation(cursor), C.tinygo_clang_Cursor_getTranslationUnit(cursor))
@ -391,7 +588,7 @@ func (p *cgoPackage) addErrorAt(position token.Position, msg string) {
// makeDecayingASTType does the same as makeASTType but takes care of decaying // makeDecayingASTType does the same as makeASTType but takes care of decaying
// types (arrays in function parameters, etc). It is otherwise identical to // types (arrays in function parameters, etc). It is otherwise identical to
// makeASTType. // makeASTType.
func (p *cgoPackage) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr { func (f *cgoFile) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
// Strip typedefs, if any. // Strip typedefs, if any.
underlyingType := typ underlyingType := typ
if underlyingType.kind == C.CXType_Typedef { if underlyingType.kind == C.CXType_Typedef {
@ -417,15 +614,15 @@ func (p *cgoPackage) makeDecayingASTType(typ C.CXType, pos token.Pos) ast.Expr {
pointeeType := C.clang_getElementType(underlyingType) pointeeType := C.clang_getElementType(underlyingType)
return &ast.StarExpr{ return &ast.StarExpr{
Star: pos, Star: pos,
X: p.makeASTType(pointeeType, pos), X: f.makeASTType(pointeeType, pos),
} }
} }
return p.makeASTType(typ, pos) return f.makeASTType(typ, pos)
} }
// makeASTType return the ast.Expr for the given libclang type. In other words, // makeASTType return the ast.Expr for the given libclang type. In other words,
// it converts a libclang type to a type in the Go AST. // it converts a libclang type to a type in the Go AST.
func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr { func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
var typeName string var typeName string
switch typ.kind { switch typ.kind {
case C.CXType_Char_S, C.CXType_Char_U: case C.CXType_Char_S, C.CXType_Char_U:
@ -486,7 +683,7 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
} }
return &ast.StarExpr{ return &ast.StarExpr{
Star: pos, Star: pos,
X: p.makeASTType(pointeeType, pos), X: f.makeASTType(pointeeType, pos),
} }
case C.CXType_ConstantArray: case C.CXType_ConstantArray:
return &ast.ArrayType{ return &ast.ArrayType{
@ -496,7 +693,7 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
Kind: token.INT, Kind: token.INT,
Value: strconv.FormatInt(int64(C.clang_getArraySize(typ)), 10), Value: strconv.FormatInt(int64(C.clang_getArraySize(typ)), 10),
}, },
Elt: p.makeASTType(C.clang_getElementType(typ), pos), Elt: f.makeASTType(C.clang_getElementType(typ), pos),
} }
case C.CXType_FunctionProto: case C.CXType_FunctionProto:
// Be compatible with gc, which uses the *[0]byte type for function // Be compatible with gc, which uses the *[0]byte type for function
@ -517,71 +714,21 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
} }
case C.CXType_Typedef: case C.CXType_Typedef:
name := getString(C.clang_getTypedefName(typ)) name := getString(C.clang_getTypedefName(typ))
if _, ok := p.typedefs[name]; !ok { c := C.tinygo_clang_getTypeDeclaration(typ)
p.typedefs[name] = nil // don't recurse
c := C.tinygo_clang_getTypeDeclaration(typ)
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
expr := p.makeASTType(underlyingType, pos)
if strings.HasPrefix(name, "_Cgo_") {
expr := expr.(*ast.Ident)
typeSize := C.clang_Type_getSizeOf(underlyingType)
switch expr.Name {
case "C.char":
if typeSize != 1 {
// This happens for some very special purpose architectures
// (DSPs etc.) that are not currently targeted.
// https://www.embecosm.com/2017/04/18/non-8-bit-char-support-in-clang-and-llvm/
p.addError(pos, fmt.Sprintf("unknown char width: %d", typeSize))
}
switch underlyingType.kind {
case C.CXType_Char_S:
expr.Name = "int8"
case C.CXType_Char_U:
expr.Name = "uint8"
}
case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
switch typeSize {
case 1:
expr.Name = "int8"
case 2:
expr.Name = "int16"
case 4:
expr.Name = "int32"
case 8:
expr.Name = "int64"
}
case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
switch typeSize {
case 1:
expr.Name = "uint8"
case 2:
expr.Name = "uint16"
case 4:
expr.Name = "uint32"
case 8:
expr.Name = "uint64"
}
}
}
p.typedefs[name] = &typedefInfo{
typeExpr: expr,
pos: pos,
}
}
return &ast.Ident{ return &ast.Ident{
NamePos: pos, NamePos: pos,
Name: "C." + name, Name: f.getASTDeclName(name, c, false),
} }
case C.CXType_Elaborated: case C.CXType_Elaborated:
underlying := C.clang_Type_getNamedType(typ) underlying := C.clang_Type_getNamedType(typ)
switch underlying.kind { switch underlying.kind {
case C.CXType_Record: case C.CXType_Record:
return p.makeASTType(underlying, pos) return f.makeASTType(underlying, pos)
case C.CXType_Enum: case C.CXType_Enum:
return p.makeASTType(underlying, pos) return f.makeASTType(underlying, pos)
default: default:
typeKindSpelling := getString(C.clang_getTypeKindSpelling(underlying.kind)) typeKindSpelling := getString(C.clang_getTypeKindSpelling(underlying.kind))
p.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling)) f.addError(pos, fmt.Sprintf("unknown elaborated type (libclang type kind %s)", typeKindSpelling))
typeName = "<unknown>" typeName = "<unknown>"
} }
case C.CXType_Record: case C.CXType_Record:
@ -599,63 +746,46 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
} }
if name == "" { if name == "" {
// Anonymous record, probably inside a typedef. // Anonymous record, probably inside a typedef.
typeInfo := p.makeASTRecordType(cursor, pos) clangLocation := C.tinygo_clang_getCursorLocation(cursor)
if typeInfo.bitfields != nil || typeInfo.unionSize != 0 { var file C.CXFile
// This record is a union or is a struct with bitfields, so we var line C.unsigned
// have to declare it as a named type (for getters/setters to var column C.unsigned
// work). C.clang_getFileLocation(clangLocation, &file, &line, &column, nil)
p.anonStructNum++ location := token.Position{
cgoName := cgoRecordPrefix + strconv.Itoa(p.anonStructNum) Filename: getString(C.clang_getFileName(file)),
p.elaboratedTypes[cgoName] = typeInfo Line: int(line),
return &ast.Ident{ Column: int(column),
NamePos: pos,
Name: "C." + cgoName,
}
} }
return typeInfo.typeExpr if location.Filename == "" || location.Line == 0 {
// Not sure when this would happen, but protect from it anyway.
f.addError(pos, "could not find file/line information")
}
name = f.getUnnamedDeclName("_Ctype_"+cgoRecordPrefix+"__", location)
} else { } else {
cgoName := cgoRecordPrefix + name name = cgoRecordPrefix + name
if _, ok := p.elaboratedTypes[cgoName]; !ok { }
p.elaboratedTypes[cgoName] = nil // predeclare (to avoid endless recursion) return &ast.Ident{
p.elaboratedTypes[cgoName] = p.makeASTRecordType(cursor, pos) NamePos: pos,
} Name: f.getASTDeclName(name, cursor, false),
return &ast.Ident{
NamePos: pos,
Name: "C." + cgoName,
}
} }
case C.CXType_Enum: case C.CXType_Enum:
cursor := C.tinygo_clang_getTypeDeclaration(typ) cursor := C.tinygo_clang_getTypeDeclaration(typ)
name := getString(C.tinygo_clang_getCursorSpelling(cursor)) name := getString(C.tinygo_clang_getCursorSpelling(cursor))
underlying := C.tinygo_clang_getEnumDeclIntegerType(cursor)
if name == "" { if name == "" {
// anonymous enum name = f.getUnnamedDeclName("_Ctype_enum___", cursor)
ref := storedRefs.Put(p)
defer storedRefs.Remove(ref)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
return p.makeASTType(underlying, pos)
} else { } else {
// named enum name = "enum_" + name
if _, ok := p.enums[name]; !ok { }
ref := storedRefs.Put(p) return &ast.Ident{
defer storedRefs.Remove(ref) NamePos: pos,
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref)) Name: f.getASTDeclName(name, cursor, false),
p.enums[name] = enumInfo{
typeExpr: p.makeASTType(underlying, pos),
pos: pos,
}
}
return &ast.Ident{
NamePos: pos,
Name: "C.enum_" + name,
}
} }
} }
if typeName == "" { if typeName == "" {
// Report this as an error. // Report this as an error.
typeSpelling := getString(C.clang_getTypeSpelling(typ)) typeSpelling := getString(C.clang_getTypeSpelling(typ))
typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind)) typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind))
p.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling)) f.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling))
typeName = "C.<unknown>" typeName = "C.<unknown>"
} }
return &ast.Ident{ return &ast.Ident{
@ -664,9 +794,80 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
} }
} }
// getIntegerType returns an AST node that defines types such as C.int.
func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSpec {
pos := p.getCursorPosition(cursor)
// Find a Go type that matches the size and signedness of the given C type.
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(cursor)
var goName string
typeSize := C.clang_Type_getSizeOf(underlyingType)
switch name {
case "C.char":
if typeSize != 1 {
// This happens for some very special purpose architectures
// (DSPs etc.) that are not currently targeted.
// https://www.embecosm.com/2017/04/18/non-8-bit-char-support-in-clang-and-llvm/
p.addError(pos, fmt.Sprintf("unknown char width: %d", typeSize))
}
switch underlyingType.kind {
case C.CXType_Char_S:
goName = "int8"
case C.CXType_Char_U:
goName = "uint8"
}
case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
switch typeSize {
case 1:
goName = "int8"
case 2:
goName = "int16"
case 4:
goName = "int32"
case 8:
goName = "int64"
}
case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
switch typeSize {
case 1:
goName = "uint8"
case 2:
goName = "uint16"
case 4:
goName = "uint32"
case 8:
goName = "uint64"
}
}
if goName == "" { // should not happen
p.addError(pos, "internal error: did not find Go type for C type "+name)
goName = "int"
}
// Construct an *ast.TypeSpec for this type.
obj := &ast.Object{
Kind: ast.Typ,
Name: name,
}
spec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: pos,
Name: name,
Obj: obj,
},
Type: &ast.Ident{
NamePos: pos,
Name: goName,
},
}
obj.Decl = spec
return spec
}
// makeASTRecordType parses a C record (struct or union) and translates it into // makeASTRecordType parses a C record (struct or union) and translates it into
// a Go struct type. // a Go struct type.
func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elaboratedTypeInfo { func (f *cgoFile) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elaboratedTypeInfo {
fieldList := &ast.FieldList{ fieldList := &ast.FieldList{
Opening: pos, Opening: pos,
Closing: pos, Closing: pos,
@ -676,11 +877,11 @@ func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elab
bitfieldNum := 0 bitfieldNum := 0
ref := storedRefs.Put(struct { ref := storedRefs.Put(struct {
fieldList *ast.FieldList fieldList *ast.FieldList
pkg *cgoPackage file *cgoFile
inBitfield *bool inBitfield *bool
bitfieldNum *int bitfieldNum *int
bitfieldList *[]bitfieldInfo bitfieldList *[]bitfieldInfo
}{fieldList, p, &inBitfield, &bitfieldNum, &bitfieldList}) }{fieldList, f, &inBitfield, &bitfieldNum, &bitfieldList})
defer storedRefs.Remove(ref) defer storedRefs.Remove(ref)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(ref)) C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_struct_visitor), C.CXClientData(ref))
renameFieldKeywords(fieldList) renameFieldKeywords(fieldList)
@ -709,13 +910,13 @@ func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elab
} }
if bitfieldList != nil { if bitfieldList != nil {
// This is valid C... but please don't do this. // This is valid C... but please don't do this.
p.addError(pos, "bitfield in a union is not supported") f.addError(pos, "bitfield in a union is not supported")
} }
typ := C.tinygo_clang_getCursorType(cursor) typ := C.tinygo_clang_getCursorType(cursor)
alignInBytes := int64(C.clang_Type_getAlignOf(typ)) alignInBytes := int64(C.clang_Type_getAlignOf(typ))
sizeInBytes := int64(C.clang_Type_getSizeOf(typ)) sizeInBytes := int64(C.clang_Type_getSizeOf(typ))
if sizeInBytes == 0 { if sizeInBytes == 0 {
p.addError(pos, "zero-length union is not supported") f.addError(pos, "zero-length union is not supported")
} }
typeInfo.unionSize = sizeInBytes typeInfo.unionSize = sizeInBytes
typeInfo.unionAlign = alignInBytes typeInfo.unionAlign = alignInBytes
@ -723,7 +924,7 @@ func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elab
default: default:
cursorKind := C.tinygo_clang_getCursorKind(cursor) cursorKind := C.tinygo_clang_getCursorKind(cursor)
cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind)) cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
p.addError(pos, fmt.Sprintf("expected StructDecl or UnionDecl, not %s", cursorKindSpelling)) f.addError(pos, fmt.Sprintf("expected StructDecl or UnionDecl, not %s", cursorKindSpelling))
return &elaboratedTypeInfo{ return &elaboratedTypeInfo{
typeExpr: &ast.StructType{ typeExpr: &ast.StructType{
Struct: pos, Struct: pos,
@ -737,17 +938,17 @@ func (p *cgoPackage) makeASTRecordType(cursor C.GoCXCursor, pos token.Pos) *elab
func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int { func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
passed := storedRefs.Get(unsafe.Pointer(client_data)).(struct { passed := storedRefs.Get(unsafe.Pointer(client_data)).(struct {
fieldList *ast.FieldList fieldList *ast.FieldList
pkg *cgoPackage file *cgoFile
inBitfield *bool inBitfield *bool
bitfieldNum *int bitfieldNum *int
bitfieldList *[]bitfieldInfo bitfieldList *[]bitfieldInfo
}) })
fieldList := passed.fieldList fieldList := passed.fieldList
p := passed.pkg f := passed.file
inBitfield := passed.inBitfield inBitfield := passed.inBitfield
bitfieldNum := passed.bitfieldNum bitfieldNum := passed.bitfieldNum
bitfieldList := passed.bitfieldList bitfieldList := passed.bitfieldList
pos := p.getCursorPosition(c) pos := f.getCursorPosition(c)
switch cursorKind := C.tinygo_clang_getCursorKind(c); cursorKind { switch cursorKind := C.tinygo_clang_getCursorKind(c); cursorKind {
case C.CXCursor_FieldDecl: case C.CXCursor_FieldDecl:
// Expected. This is a regular field. // Expected. This is a regular field.
@ -756,7 +957,7 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
return C.CXChildVisit_Continue return C.CXChildVisit_Continue
default: default:
cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind)) cursorKindSpelling := getString(C.clang_getCursorKindSpelling(cursorKind))
p.addError(pos, fmt.Sprintf("expected FieldDecl in struct or union, not %s", cursorKindSpelling)) f.addError(pos, fmt.Sprintf("expected FieldDecl in struct or union, not %s", cursorKindSpelling))
return C.CXChildVisit_Continue return C.CXChildVisit_Continue
} }
name := getString(C.tinygo_clang_getCursorSpelling(c)) name := getString(C.tinygo_clang_getCursorSpelling(c))
@ -767,14 +968,14 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
} }
typ := C.tinygo_clang_getCursorType(c) typ := C.tinygo_clang_getCursorType(c)
field := &ast.Field{ field := &ast.Field{
Type: p.makeASTType(typ, p.getCursorPosition(c)), Type: f.makeASTType(typ, f.getCursorPosition(c)),
} }
offsetof := int64(C.clang_Type_getOffsetOf(C.tinygo_clang_getCursorType(parent), C.CString(name))) offsetof := int64(C.clang_Type_getOffsetOf(C.tinygo_clang_getCursorType(parent), C.CString(name)))
alignOf := int64(C.clang_Type_getAlignOf(typ) * 8) alignOf := int64(C.clang_Type_getAlignOf(typ) * 8)
bitfieldOffset := offsetof % alignOf bitfieldOffset := offsetof % alignOf
if bitfieldOffset != 0 { if bitfieldOffset != 0 {
if C.tinygo_clang_Cursor_isBitField(c) != 1 { if C.tinygo_clang_Cursor_isBitField(c) != 1 {
p.addError(pos, "expected a bitfield") f.addError(pos, "expected a bitfield")
return C.CXChildVisit_Continue return C.CXChildVisit_Continue
} }
if !*inBitfield { if !*inBitfield {
@ -821,23 +1022,6 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
return C.CXChildVisit_Continue return C.CXChildVisit_Continue
} }
//export tinygo_clang_enum_visitor
func tinygo_clang_enum_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage)
name := getString(C.tinygo_clang_getCursorSpelling(c))
pos := p.getCursorPosition(c)
value := C.tinygo_clang_getEnumConstantDeclValue(c)
p.constants[name] = constantInfo{
expr: &ast.BasicLit{
ValuePos: pos,
Kind: token.INT,
Value: strconv.FormatInt(int64(value), 10),
},
pos: pos,
}
return C.CXChildVisit_Continue
}
//export tinygo_clang_inclusion_visitor //export tinygo_clang_inclusion_visitor
func tinygo_clang_inclusion_visitor(includedFile C.CXFile, inclusionStack *C.CXSourceLocation, includeLen C.unsigned, clientData C.CXClientData) { func tinygo_clang_inclusion_visitor(includedFile C.CXFile, inclusionStack *C.CXSourceLocation, includeLen C.unsigned, clientData C.CXClientData) {
callback := storedRefs.Get(unsafe.Pointer(clientData)).(func(C.CXFile)) callback := storedRefs.Get(unsafe.Pointer(clientData)).(func(C.CXFile))

33
cgo/testdata/basic.out.go предоставленный
Просмотреть файл

@ -24,23 +24,16 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
type C.int16_t = int16 type (
type C.int32_t = int32 C.char uint8
type C.int64_t = int64 C.schar int8
type C.int8_t = int8 C.uchar uint8
type C.uint16_t = uint16 C.short int16
type C.uint32_t = uint32 C.ushort uint16
type C.uint64_t = uint64 C.int int32
type C.uint8_t = uint8 C.uint uint32
type C.uintptr_t = uintptr C.long int32
type C.char uint8 C.ulong uint32
type C.int int32 C.longlong int64
type C.long int32 C.ulonglong uint64
type C.longlong int64 )
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16

37
cgo/testdata/const.out.go предоставленный
Просмотреть файл

@ -24,26 +24,19 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
const C.bar = C.foo type (
const C.foo = 3 C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
type C.int16_t = int16 const C.foo = 3
type C.int32_t = int32 const C.bar = C.foo
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16

2
cgo/testdata/errors.go предоставленный
Просмотреть файл

@ -27,7 +27,7 @@ import "C"
//line errors.go:100 //line errors.go:100
var ( var (
// constant too large // constant too large
_ C.uint8_t = 2 << 10 _ C.char = 2 << 10
// z member does not exist // z member does not exist
_ C.point_t = C.point_t{z: 3} _ C.point_t = C.point_t{z: 3}

42
cgo/testdata/errors.out.go предоставленный
Просмотреть файл

@ -6,7 +6,7 @@
// testdata/errors.go:19:26: unexpected token ), expected end of expression // testdata/errors.go:19:26: unexpected token ), expected end of expression
// Type checking errors after CGo processing: // Type checking errors after CGo processing:
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as uint8 value in variable declaration (overflows) // testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as C.char value in variable declaration (overflows)
// testdata/errors.go:105: unknown field z in struct literal // testdata/errors.go:105: unknown field z in struct literal
// testdata/errors.go:108: undeclared name: C.SOME_CONST_1 // testdata/errors.go:108: undeclared name: C.SOME_CONST_1
// testdata/errors.go:110: cannot use C.SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows) // testdata/errors.go:110: cannot use C.SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows)
@ -38,29 +38,23 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
const C.SOME_CONST_3 = 1234 type (
C.char uint8
type C.int16_t = int16 C.schar int8
type C.int32_t = int32 C.uchar uint8
type C.int64_t = int64 C.short int16
type C.int8_t = int8 C.ushort uint16
type C.uint16_t = uint16 C.int int32
type C.uint32_t = uint32 C.uint uint32
type C.uint64_t = uint64 C.long int32
type C.uint8_t = uint8 C.ulong uint32
type C.uintptr_t = uintptr C.longlong int64
type C.char uint8 C.ulonglong uint64
type C.int int32 )
type C.long int32 type C._Ctype_struct___0 struct {
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16
type C.point_t = struct {
x C.int x C.int
y C.int y C.int
} }
type C.point_t = C._Ctype_struct___0
const C.SOME_CONST_3 = 1234

35
cgo/testdata/flags.out.go предоставленный
Просмотреть файл

@ -29,26 +29,19 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
type (
C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
const C.BAR = 3 const C.BAR = 3
const C.FOO_H = 1 const C.FOO_H = 1
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16

41
cgo/testdata/symbols.out.go предоставленный
Просмотреть файл

@ -24,41 +24,36 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
type (
C.char uint8
C.schar int8
C.uchar uint8
C.short int16
C.ushort uint16
C.int int32
C.uint uint32
C.long int32
C.ulong uint32
C.longlong int64
C.ulonglong uint64
)
//export foo //export foo
func C.foo(a C.int, b C.int) C.int func C.foo(a C.int, b C.int) C.int
var C.foo$funcaddr unsafe.Pointer
//export variadic0 //export variadic0
//go:variadic //go:variadic
func C.variadic0() func C.variadic0()
var C.variadic0$funcaddr unsafe.Pointer
//export variadic2 //export variadic2
//go:variadic //go:variadic
func C.variadic2(x C.int, y C.int) func C.variadic2(x C.int, y C.int)
var C.foo$funcaddr unsafe.Pointer
var C.variadic0$funcaddr unsafe.Pointer
var C.variadic2$funcaddr unsafe.Pointer var C.variadic2$funcaddr unsafe.Pointer
//go:extern someValue //go:extern someValue
var C.someValue C.int var C.someValue C.int
type C.int16_t = int16
type C.int32_t = int32
type C.int64_t = int64
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16

202
cgo/testdata/types.out.go предоставленный
Просмотреть файл

@ -24,132 +24,126 @@ func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
return C.__GoBytes(ptr, uintptr(length)) return C.__GoBytes(ptr, uintptr(length))
} }
const C.option2A = 20 type (
const C.optionA = 0 C.char uint8
const C.optionB = 1 C.schar int8
const C.optionC = -5 C.uchar uint8
const C.optionD = -4 C.short int16
const C.optionE = 10 C.ushort uint16
const C.optionF = 11 C.int int32
const C.optionG = 12 C.uint uint32
const C.unused1 = 5 C.long int32
C.ulong uint32
type C.int16_t = int16 C.longlong int64
type C.int32_t = int32 C.ulonglong uint64
type C.int64_t = int64 )
type C.int8_t = int8
type C.uint16_t = uint16
type C.uint32_t = uint32
type C.uint64_t = uint64
type C.uint8_t = uint8
type C.uintptr_t = uintptr
type C.char uint8
type C.int int32
type C.long int32
type C.longlong int64
type C.schar int8
type C.short int16
type C.uchar uint8
type C.uint uint32
type C.ulong uint32
type C.ulonglong uint64
type C.ushort uint16
type C.bitfield_t = C.struct_4
type C.myIntArray = [10]C.int
type C.myint = C.int type C.myint = C.int
type C.option2_t = C.uint type C._Ctype_struct___0 struct {
type C.option_t = C.enum_option
type C.point2d_t = struct {
x C.int x C.int
y C.int y C.int
} }
type C.point3d_t = C.struct_point3d type C.point2d_t = C._Ctype_struct___0
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
ptr *C.int
}
type C.union1_t = struct{ i C.int }
type C.union2d_t = C.union_union2d
type C.union3_t = C.union_1
type C.union_nested_t = C.union_3
type C.unionarray_t = struct{ arr [10]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_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_4) set_bitfield_c(value C.uchar,
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
type C.struct_4 struct {
start C.uchar
__bitfield_1 C.uchar
d C.uchar
e C.uchar
}
type C.struct_point3d struct { type C.struct_point3d struct {
x C.int x C.int
y C.int y C.int
z C.int z C.int
} }
type C.point3d_t = C.struct_point3d
type C.struct_type1 struct { type C.struct_type1 struct {
_type C.int _type C.int
__type C.int __type C.int
___type C.int ___type C.int
} }
type C.struct_type2 struct{ _type C.int } type C.struct_type2 struct{ _type C.int }
type C._Ctype_union___1 struct{ i C.int }
type C.union1_t = C._Ctype_union___1
type C._Ctype_union___2 struct{ $union uint64 }
func (union *C.union_1) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) } func (union *C._Ctype_union___2) unionfield_i() *C.int {
func (union *C.union_1) unionfield_d() *float64 { return (*float64)(unsafe.Pointer(&union.$union)) } return (*C.int)(unsafe.Pointer(&union.$union))
func (union *C.union_1) unionfield_s() *C.short { return (*C.short)(unsafe.Pointer(&union.$union)) }
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 { func (union *C._Ctype_union___2) unionfield_d() *float64 {
return (*C.point3d_t)(unsafe.Pointer(&union.$union)) return (*float64)(unsafe.Pointer(&union.$union))
}
func (union *C._Ctype_union___2) unionfield_s() *C.short {
return (*C.short)(unsafe.Pointer(&union.$union))
} }
type C.union_2 struct{ $union [3]uint32 } type C.union3_t = C._Ctype_union___2
type C.union_union2d struct{ $union [2]uint64 }
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_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
func (union *C.union_union2d) unionfield_d() *[2]float64 { func (union *C.union_union2d) unionfield_d() *[2]float64 {
return (*[2]float64)(unsafe.Pointer(&union.$union)) return (*[2]float64)(unsafe.Pointer(&union.$union))
} }
type C.union_union2d struct{ $union [2]uint64 } type C.union2d_t = C.union_union2d
type C.enum_option C.int type C._Ctype_union___3 struct{ arr [10]C.uchar }
type C.enum_unused C.uint type C.unionarray_t = C._Ctype_union___3
type C._Ctype_union___5 struct{ $union [3]uint32 }
func (union *C._Ctype_union___5) unionfield_area() *C.point2d_t {
return (*C.point2d_t)(unsafe.Pointer(&union.$union))
}
func (union *C._Ctype_union___5) unionfield_solid() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
type C._Ctype_struct___4 struct {
begin C.point2d_t
end C.point2d_t
tag C.int
coord C._Ctype_union___5
}
type C.struct_nested_t = C._Ctype_struct___4
type C._Ctype_union___6 struct{ $union [2]uint64 }
func (union *C._Ctype_union___6) unionfield_point() *C.point3d_t {
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
}
func (union *C._Ctype_union___6) unionfield_array() *C.unionarray_t {
return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
}
func (union *C._Ctype_union___6) unionfield_thing() *C.union3_t {
return (*C.union3_t)(unsafe.Pointer(&union.$union))
}
type C.union_nested_t = C._Ctype_union___6
type C.enum_option = C.int
type C.option_t = C.enum_option
type C._Ctype_enum___7 = C.uint
type C.option2_t = C._Ctype_enum___7
type C._Ctype_struct___8 struct {
f float32
d float64
ptr *C.int
}
type C.types_t = C._Ctype_struct___8
type C.myIntArray = [10]C.int
type C._Ctype_struct___9 struct {
start C.uchar
__bitfield_1 C.uchar
d C.uchar
e C.uchar
}
func (s *C._Ctype_struct___9) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
func (s *C._Ctype_struct___9) set_bitfield_a(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
}
func (s *C._Ctype_struct___9) bitfield_b() C.uchar {
return s.__bitfield_1 >> 5 & 0x1
}
func (s *C._Ctype_struct___9) set_bitfield_b(value C.uchar) {
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
}
func (s *C._Ctype_struct___9) bitfield_c() C.uchar {
return s.__bitfield_1 >> 6
}
func (s *C._Ctype_struct___9) set_bitfield_c(value C.uchar,
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
type C.bitfield_t = C._Ctype_struct___9