From 0af7da9bff101070999cfe6a959f8c0791365243 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 29 Nov 2018 17:48:20 +0100 Subject: [PATCH] cgo: add support for C.int, c.uint, etc --- loader/cgo.go | 38 +++++++++++++++++++++++++++++--------- testdata/cgo/main.c | 4 ++++ testdata/cgo/main.go | 4 ++++ testdata/cgo/out.txt | 2 ++ 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/loader/cgo.go b/loader/cgo.go index c798a84c..21548f82 100644 --- a/loader/cgo.go +++ b/loader/cgo.go @@ -8,6 +8,7 @@ import ( "go/token" "sort" "strconv" + "strings" ) // fileInfo holds all Cgo-related information of a given *ast.File. @@ -54,6 +55,22 @@ var cgoAliases = map[string]string{ "C.uintptr_t": "uintptr", } +// cgoTypes lists some C types with ambiguous sizes that must be retrieved +// somehow from C. This is done by adding some typedefs to get the size of each +// type. +const cgoTypes = ` +typedef signed char _Cgo_schar; +typedef unsigned char _Cgo_uchar; +typedef short _Cgo_short; +typedef unsigned short _Cgo_ushort; +typedef int _Cgo_int; +typedef unsigned int _Cgo_uint; +typedef long _Cgo_long; +typedef unsigned long _Cgo_ulong; +typedef long long _Cgo_longlong; +typedef unsigned long long _Cgo_ulonglong; +` + // processCgo extracts the `import "C"` statement from the AST, parses the // comment with libclang, and modifies the AST to use this information. func (p *Package) processCgo(filename string, f *ast.File) error { @@ -89,7 +106,7 @@ func (p *Package) processCgo(filename string, f *ast.File) error { // source location. info.importCPos = spec.Path.ValuePos - err = info.parseFragment(cgoComment) + err = info.parseFragment(cgoComment + cgoTypes) if err != nil { return err } @@ -229,14 +246,6 @@ func (info *fileInfo) addTypedefs() { for _, typedef := range info.typedefs { newType := "C." + typedef.newName oldType := "C." + typedef.oldName - if _, ok := cgoAliases[newType]; ok { - // This is a type that also exists in Go (defined in stdint.h). - continue - } - obj := &ast.Object{ - Kind: ast.Typ, - Name: newType, - } switch oldType { // TODO: plain char (may be signed or unsigned) case "C.signed char", "C.short", "C.int", "C.long", "C.long long": @@ -262,6 +271,17 @@ func (info *fileInfo) addTypedefs() { oldType = "uint64" } } + if strings.HasPrefix(newType, "C._Cgo_") { + newType = "C." + newType[len("C._Cgo_"):] + } + if _, ok := cgoAliases[newType]; ok { + // This is a type that also exists in Go (defined in stdint.h). + continue + } + obj := &ast.Object{ + Kind: ast.Typ, + Name: newType, + } typeSpec := &ast.TypeSpec{ Name: &ast.Ident{ NamePos: info.importCPos, diff --git a/testdata/cgo/main.c b/testdata/cgo/main.c index 315805aa..0ce7b683 100644 --- a/testdata/cgo/main.c +++ b/testdata/cgo/main.c @@ -4,6 +4,10 @@ int32_t fortytwo() { return 42; } +int add(int a, int b) { + return a + b; +} + int32_t mul(int32_t a, int32_t b) { return a * b; } diff --git a/testdata/cgo/main.go b/testdata/cgo/main.go index cd927940..f37c95eb 100644 --- a/testdata/cgo/main.go +++ b/testdata/cgo/main.go @@ -5,12 +5,16 @@ package main int32_t fortytwo(void); int32_t mul(int32_t a, int32_t b); typedef int32_t myint; +int add(int a, int b); */ import "C" func main() { println("fortytwo:", C.fortytwo()) println("mul:", C.mul(C.int32_t(3), 5)) + println("add:", C.add(C.int(3), 5)) var x C.myint = 3 println("myint:", x, C.myint(5)) + var y C.longlong = -(1 << 40) + println("longlong:", y) } diff --git a/testdata/cgo/out.txt b/testdata/cgo/out.txt index ce0b312a..5f222ce0 100644 --- a/testdata/cgo/out.txt +++ b/testdata/cgo/out.txt @@ -1,3 +1,5 @@ fortytwo: 42 mul: 15 +add: 8 myint: 3 5 +longlong: -1099511627776