aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/cmd/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/cgo')
-rw-r--r--libgo/go/cmd/cgo/doc.go11
-rw-r--r--libgo/go/cmd/cgo/gcc.go42
-rw-r--r--libgo/go/cmd/cgo/out.go51
3 files changed, 77 insertions, 27 deletions
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
index 8c3bf81..ca18c45 100644
--- a/libgo/go/cmd/cgo/doc.go
+++ b/libgo/go/cmd/cgo/doc.go
@@ -413,7 +413,7 @@ type in Go are instead represented by a uintptr. Those include:
jobjectArray
jweak
-3. The EGLDisplay type from the EGL API.
+3. The EGLDisplay and EGLConfig types from the EGL API.
These types are uintptr on the Go side because they would otherwise
confuse the Go garbage collector; they are sometimes not really
@@ -429,11 +429,16 @@ from Go 1.9 and earlier, use the cftype or jni rewrites in the Go fix tool:
It will replace nil with 0 in the appropriate places.
-The EGLDisplay case were introduced in Go 1.12. Use the egl rewrite
+The EGLDisplay case was introduced in Go 1.12. Use the egl rewrite
to auto-update code from Go 1.11 and earlier:
go tool fix -r egl <pkg>
+The EGLConfig case was introduced in Go 1.15. Use the eglconf rewrite
+to auto-update code from Go 1.14 and earlier:
+
+ go tool fix -r eglconf <pkg>
+
Using cgo directly
Usage:
@@ -985,7 +990,7 @@ produces a file named a.out, even if cmd/link does so by invoking the host
linker in external linking mode.
By default, cmd/link will decide the linking mode as follows: if the only
-packages using cgo are those on a whitelist of standard library
+packages using cgo are those on a list of known standard library
packages (net, os/user, runtime/cgo), cmd/link will use internal linking
mode. Otherwise, there are non-standard cgo packages involved, and cmd/link
will use external linking mode. The first rule means that a build of
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index 310316b..249cfe4 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -200,6 +200,9 @@ func (p *Package) Translate(f *File) {
numTypedefs = len(p.typedefs)
// Also ask about any typedefs we've seen so far.
for _, info := range p.typedefList {
+ if f.Name[info.typedef] != nil {
+ continue
+ }
n := &Name{
Go: info.typedef,
C: info.typedef,
@@ -351,7 +354,7 @@ func (p *Package) guessKinds(f *File) []*Name {
// void __cgo_f_xxx_5(void) { static const char __cgo_undefined__5[] = (name); }
//
// If we see an error at not-declared:xxx, the corresponding name is not declared.
- // If we see an error at not-type:xxx, the corresponding name is a type.
+ // If we see an error at not-type:xxx, the corresponding name is not a type.
// If we see an error at not-int-const:xxx, the corresponding name is not an integer constant.
// If we see an error at not-num-const:xxx, the corresponding name is not a number constant.
// If we see an error at not-str-lit:xxx, the corresponding name is not a string literal.
@@ -728,6 +731,9 @@ func (p *Package) prepareNames(f *File) {
}
}
p.mangleName(n)
+ if n.Kind == "type" && typedef[n.Mangle] == nil {
+ typedef[n.Mangle] = n.Type
+ }
}
}
@@ -1366,6 +1372,9 @@ func (p *Package) rewriteRef(f *File) {
if *godefs {
// Substitute definition for mangled type name.
+ if r.Name.Type != nil && r.Name.Kind == "type" {
+ expr = r.Name.Type.Go
+ }
if id, ok := expr.(*ast.Ident); ok {
if t := typedef[id.Name]; t != nil {
expr = t.Go
@@ -1431,9 +1440,7 @@ func (p *Package) rewriteName(f *File, r *Ref) ast.Expr {
r.Context = ctxType
if r.Name.Type == nil {
error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
- break
}
- expr = r.Name.Type.Go
break
}
error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
@@ -1490,9 +1497,7 @@ func (p *Package) rewriteName(f *File, r *Ref) ast.Expr {
// Okay - might be new(T)
if r.Name.Type == nil {
error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
- break
}
- expr = r.Name.Type.Go
case "var":
expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
case "macro":
@@ -1511,8 +1516,6 @@ func (p *Package) rewriteName(f *File, r *Ref) ast.Expr {
// Use of C.enum_x, C.struct_x or C.union_x without C definition.
// GCC won't raise an error when using pointers to such unknown types.
error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
- } else {
- expr = r.Name.Type.Go
}
default:
if r.Name.Kind == "func" {
@@ -2082,6 +2085,10 @@ var goIdent = make(map[string]*ast.Ident)
// that may contain a pointer. This is used for cgo pointer checking.
var unionWithPointer = make(map[ast.Expr]bool)
+// anonymousStructTag provides a consistent tag for an anonymous struct.
+// The same dwarf.StructType pointer will always get the same tag.
+var anonymousStructTag = make(map[*dwarf.StructType]string)
+
func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
c.intSize = intSize
@@ -2430,8 +2437,12 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ
break
}
if tag == "" {
- tag = "__" + strconv.Itoa(tagGen)
- tagGen++
+ tag = anonymousStructTag[dt]
+ if tag == "" {
+ tag = "__" + strconv.Itoa(tagGen)
+ tagGen++
+ anonymousStructTag[dt] = tag
+ }
} else if t.C.Empty() {
t.C.Set(dt.Kind + " " + tag)
}
@@ -3028,8 +3039,9 @@ func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool {
return ok && st.StructName == ""
}
-// badPointerTypedef reports whether t is a C typedef that should not be considered a pointer in Go.
-// A typedef is bad if C code sometimes stores non-pointers in this type.
+// badPointerTypedef reports whether dt is a C typedef that should not be
+// considered a pointer in Go. A typedef is bad if C code sometimes stores
+// non-pointers in this type.
// TODO: Currently our best solution is to find these manually and list them as
// they come up. A better solution is desired.
func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
@@ -3039,7 +3051,7 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
if c.badJNI(dt) {
return true
}
- if c.badEGLDisplay(dt) {
+ if c.badEGLType(dt) {
return true
}
return false
@@ -3178,11 +3190,11 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
return false
}
-func (c *typeConv) badEGLDisplay(dt *dwarf.TypedefType) bool {
- if dt.Name != "EGLDisplay" {
+func (c *typeConv) badEGLType(dt *dwarf.TypedefType) bool {
+ if dt.Name != "EGLDisplay" && dt.Name != "EGLConfig" {
return false
}
- // Check that the typedef is "typedef void *EGLDisplay".
+ // Check that the typedef is "typedef void *<name>".
if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
if _, ok := ptr.Type.(*dwarf.VoidType); ok {
return true
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 4d66e1b..1d23fc1 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -22,6 +22,7 @@ import (
"regexp"
"sort"
"strings"
+ "unicode"
)
var (
@@ -102,6 +103,11 @@ func (p *Package) writeDefs() {
typedefNames := make([]string, 0, len(typedef))
for name := range typedef {
+ if name == "_Ctype_void" {
+ // We provide an appropriate declaration for
+ // _Ctype_void below (#39877).
+ continue
+ }
typedefNames = append(typedefNames, name)
}
sort.Strings(typedefNames)
@@ -122,7 +128,9 @@ func (p *Package) writeDefs() {
// Moreover, empty file name makes compile emit no source debug info at all.
var buf bytes.Buffer
noSourceConf.Fprint(&buf, fset, def.Go)
- if bytes.HasPrefix(buf.Bytes(), []byte("_Ctype_")) {
+ if bytes.HasPrefix(buf.Bytes(), []byte("_Ctype_")) ||
+ strings.HasPrefix(name, "_Ctype_enum_") ||
+ strings.HasPrefix(name, "_Ctype_union_") {
// This typedef is of the form `typedef a b` and should be an alias.
fmt.Fprintf(fgo2, "= ")
}
@@ -807,6 +815,28 @@ func (p *Package) packedAttribute() string {
return s + "))"
}
+// exportParamName returns the value of param as it should be
+// displayed in a c header file. If param contains any non-ASCII
+// characters, this function will return the character p followed by
+// the value of position; otherwise, this function will return the
+// value of param.
+func exportParamName(param string, position int) string {
+ if param == "" {
+ return fmt.Sprintf("p%d", position)
+ }
+
+ pname := param
+
+ for i := 0; i < len(param); i++ {
+ if param[i] > unicode.MaxASCII {
+ pname = fmt.Sprintf("p%d", position)
+ break
+ }
+ }
+
+ return pname
+}
+
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
@@ -920,42 +950,45 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
if i > 0 || fn.Recv != nil {
s += ", "
}
- s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
+ s += fmt.Sprintf("%s %s", p.cgoType(atype).C, exportParamName(aname, i))
})
s += ")"
if len(exp.Doc) > 0 {
fmt.Fprintf(fgcch, "\n%s", exp.Doc)
+ if !strings.HasSuffix(exp.Doc, "\n") {
+ fmt.Fprint(fgcch, "\n")
+ }
}
- fmt.Fprintf(fgcch, "\nextern %s;\n", s)
+ fmt.Fprintf(fgcch, "extern %s;\n", s)
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
- fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
+ fmt.Fprintf(fgcc, "\t%s %v _cgo_a;\n", ctype, p.packedAttribute())
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
}
if fn.Recv != nil {
- fmt.Fprintf(fgcc, "\ta.recv = recv;\n")
+ fmt.Fprintf(fgcc, "\t_cgo_a.recv = recv;\n")
}
forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) {
- fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
+ fmt.Fprintf(fgcc, "\t_cgo_a.p%d = %s;\n", i, exportParamName(aname, i))
})
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
- fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
+ fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &_cgo_a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n")
if gccResult != "void" {
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
- fmt.Fprintf(fgcc, "\treturn a.r0;\n")
+ fmt.Fprintf(fgcc, "\treturn _cgo_a.r0;\n")
} else {
forFieldList(fntype.Results,
func(i int, aname string, atype ast.Expr) {
- fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i)
+ fmt.Fprintf(fgcc, "\tr.r%d = _cgo_a.r%d;\n", i, i)
})
fmt.Fprintf(fgcc, "\treturn r;\n")
}