diff options
Diffstat (limited to 'libgo/go/cmd/cgo')
-rw-r--r-- | libgo/go/cmd/cgo/doc.go | 11 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/gcc.go | 42 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/out.go | 51 |
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") } |