summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/cgo
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-01-18 19:04:36 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-01-18 19:04:36 +0000
commit4f4a855d82a889cebcfca150a7a43909bcb6a346 (patch)
treef12bae0781920fa34669fe30b6f4615a86d9fb80 /libgo/go/cmd/cgo
parent225220d668dafb8262db7012bced688acbe63b33 (diff)
downloadgcc-4f4a855d82a889cebcfca150a7a43909bcb6a346.tar.gz
libgo: update to Go1.12beta2
Reviewed-on: https://go-review.googlesource.com/c/158019 gotools/: * Makefile.am (go_cmd_vet_files): Update for Go1.12beta2 release. (GOTOOLS_TEST_TIMEOUT): Increase to 600. (check-runtime): Export LD_LIBRARY_PATH before computing GOARCH and GOOS. (check-vet): Copy golang.org/x/tools into check-vet-dir. * Makefile.in: Regenerate. gcc/testsuite/: * go.go-torture/execute/names-1.go: Stop using debug/xcoff, which is no longer externally visible. From-SVN: r268084
Diffstat (limited to 'libgo/go/cmd/cgo')
-rw-r--r--libgo/go/cmd/cgo/ast.go21
-rw-r--r--libgo/go/cmd/cgo/doc.go11
-rw-r--r--libgo/go/cmd/cgo/gcc.go926
-rw-r--r--libgo/go/cmd/cgo/godefs.go6
-rw-r--r--libgo/go/cmd/cgo/main.go18
-rw-r--r--libgo/go/cmd/cgo/out.go46
6 files changed, 693 insertions, 335 deletions
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go
index 4462136bf4b..83d727a8a5d 100644
--- a/libgo/go/cmd/cgo/ast.go
+++ b/libgo/go/cmd/cgo/ast.go
@@ -145,6 +145,7 @@ func (f *File) ParseGo(name string, src []byte) {
if f.Ref == nil {
f.Ref = make([]*Ref, 0, 8)
}
+ f.walk(ast2, ctxProg, (*File).validateIdents)
f.walk(ast2, ctxProg, (*File).saveExprs)
// Accumulate exported functions.
@@ -181,6 +182,14 @@ func commentText(g *ast.CommentGroup) string {
return strings.Join(pieces, "")
}
+func (f *File) validateIdents(x interface{}, context astContext) {
+ if x, ok := x.(*ast.Ident); ok {
+ if f.isMangledName(x.Name) {
+ error_(x.Pos(), "identifier %q may conflict with identifiers generated by cgo", x.Name)
+ }
+ }
+}
+
// Save various references we are going to need later.
func (f *File) saveExprs(x interface{}, context astContext) {
switch x := x.(type) {
@@ -191,6 +200,18 @@ func (f *File) saveExprs(x interface{}, context astContext) {
}
case *ast.CallExpr:
f.saveCall(x, context)
+ case *ast.GenDecl:
+ if x.Tok == token.CONST {
+ for _, spec := range x.Specs {
+ vs := spec.(*ast.ValueSpec)
+ if vs.Type == nil {
+ for _, name := range spec.(*ast.ValueSpec).Names {
+ consts[name.Name] = true
+ }
+ }
+ }
+ }
+
}
}
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
index 157cd94d653..cceb33edbdb 100644
--- a/libgo/go/cmd/cgo/doc.go
+++ b/libgo/go/cmd/cgo/doc.go
@@ -413,6 +413,8 @@ type in Go are instead represented by a uintptr. Those include:
jobjectArray
jweak
+3. The EGLDisplay type 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
pointers but data structures encoded in a pointer type. All operations
@@ -427,6 +429,11 @@ 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
+to auto-update code from Go 1.11 and earlier:
+
+ go tool fix -r egl <pkg>
+
Using cgo directly
Usage:
@@ -827,6 +834,10 @@ The directives are:
possibly version in the dynamic library, and the optional "<library>"
names the specific library where the symbol should be found.
+ On AIX, the library pattern is slightly different. It must be
+ "lib.a/obj.o" with obj.o the member of this library exporting
+ this symbol.
+
In the <remote>, # or @ can be used to introduce a symbol version.
Examples:
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index 2a2d0080d5e..a8429725209 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -13,7 +13,6 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
- "debug/xcoff"
"encoding/binary"
"errors"
"flag"
@@ -21,6 +20,7 @@ import (
"go/ast"
"go/parser"
"go/token"
+ "internal/xcoff"
"math"
"os"
"strconv"
@@ -89,8 +89,14 @@ func (f *File) DiscardCgoDirectives() {
// _cgo_flags file for the build system to use.
func (p *Package) addToFlag(flag string, args []string) {
if flag == "CFLAGS" {
- // We'll need these when preprocessing for dwarf information.
- p.GccOptions = append(p.GccOptions, args...)
+ // We'll also need these when preprocessing for dwarf information.
+ // However, discard any -g options: we need to be able
+ // to parse the debug info, so stick to what we expect.
+ for _, arg := range args {
+ if !strings.HasPrefix(arg, "-g") {
+ p.GccOptions = append(p.GccOptions, arg)
+ }
+ }
}
skip := false
@@ -182,6 +188,10 @@ func (p *Package) Translate(f *File) {
// Convert C.ulong to C.unsigned long, etc.
cref.Name.C = cname(cref.Name.Go)
}
+
+ var conv typeConv
+ conv.Init(p.PtrSize, p.IntSize)
+
p.loadDefines(f)
p.typedefs = map[string]bool{}
p.typedefList = nil
@@ -189,15 +199,17 @@ func (p *Package) Translate(f *File) {
for len(p.typedefs) > numTypedefs {
numTypedefs = len(p.typedefs)
// Also ask about any typedefs we've seen so far.
- for _, a := range p.typedefList {
- f.Name[a] = &Name{
- Go: a,
- C: a,
+ for _, info := range p.typedefList {
+ n := &Name{
+ Go: info.typedef,
+ C: info.typedef,
}
+ f.Name[info.typedef] = n
+ f.NamePos[n] = info.pos
}
needType := p.guessKinds(f)
if len(needType) > 0 {
- p.loadDWARF(f, needType)
+ p.loadDWARF(f, &conv, needType)
}
// In godefs mode we're OK with the typedefs, which
@@ -207,6 +219,7 @@ func (p *Package) Translate(f *File) {
break
}
}
+ p.prepareNames(f)
if p.rewriteCalls(f) {
// Add `import _cgo_unsafe "unsafe"` after the package statement.
f.Edit.Insert(f.offset(f.AST.Name.End()), "; import _cgo_unsafe \"unsafe\"")
@@ -491,7 +504,7 @@ func (p *Package) guessKinds(f *File) []*Name {
// loadDWARF parses the DWARF debug information generated
// by gcc to learn the details of the constants, variables, and types
// being referred to as C.xxx.
-func (p *Package) loadDWARF(f *File, names []*Name) {
+func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) {
// Extract the types from the DWARF section of an object
// from a well-formed C program. Gcc only generates DWARF info
// for symbols in the object file, so it is not enough to print the
@@ -590,7 +603,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fatalf("malformed __cgo__ name: %s", name)
}
types[i] = t.Type
- p.recordTypedefs(t.Type)
+ p.recordTypedefs(t.Type, f.NamePos[names[i]])
}
if e.Tag != dwarf.TagCompileUnit {
r.SkipChildren()
@@ -598,8 +611,6 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
}
// Record types and typedef information.
- var conv typeConv
- conv.Init(p.PtrSize, p.IntSize)
for i, n := range names {
if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true
@@ -658,10 +669,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
}
// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
-func (p *Package) recordTypedefs(dtype dwarf.Type) {
- p.recordTypedefs1(dtype, map[dwarf.Type]bool{})
+func (p *Package) recordTypedefs(dtype dwarf.Type, pos token.Pos) {
+ p.recordTypedefs1(dtype, pos, map[dwarf.Type]bool{})
}
-func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool) {
+
+func (p *Package) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[dwarf.Type]bool) {
if dtype == nil {
return
}
@@ -677,24 +689,45 @@ func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool)
}
if !p.typedefs[dt.Name] {
p.typedefs[dt.Name] = true
- p.typedefList = append(p.typedefList, dt.Name)
- p.recordTypedefs1(dt.Type, visited)
+ p.typedefList = append(p.typedefList, typedefInfo{dt.Name, pos})
+ p.recordTypedefs1(dt.Type, pos, visited)
}
case *dwarf.PtrType:
- p.recordTypedefs1(dt.Type, visited)
+ p.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.ArrayType:
- p.recordTypedefs1(dt.Type, visited)
+ p.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.QualType:
- p.recordTypedefs1(dt.Type, visited)
+ p.recordTypedefs1(dt.Type, pos, visited)
case *dwarf.FuncType:
- p.recordTypedefs1(dt.ReturnType, visited)
+ p.recordTypedefs1(dt.ReturnType, pos, visited)
for _, a := range dt.ParamType {
- p.recordTypedefs1(a, visited)
+ p.recordTypedefs1(a, pos, visited)
}
case *dwarf.StructType:
for _, f := range dt.Field {
- p.recordTypedefs1(f.Type, visited)
+ p.recordTypedefs1(f.Type, pos, visited)
+ }
+ }
+}
+
+// prepareNames finalizes the Kind field of not-type names and sets
+// the mangled name of all names.
+func (p *Package) prepareNames(f *File) {
+ for _, n := range f.Name {
+ if n.Kind == "not-type" {
+ if n.Define == "" {
+ n.Kind = "var"
+ } else {
+ n.Kind = "macro"
+ n.FuncType = &FuncType{
+ Result: n.Type,
+ Go: &ast.FuncType{
+ Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}},
+ },
+ }
+ }
}
+ p.mangleName(n)
}
}
@@ -712,24 +745,37 @@ func (p *Package) mangleName(n *Name) {
n.Mangle = prefix + n.Kind + "_" + n.Go
}
+func (f *File) isMangledName(s string) bool {
+ prefix := "_C"
+ if strings.HasPrefix(s, prefix) {
+ t := s[len(prefix):]
+ for _, k := range nameKinds {
+ if strings.HasPrefix(t, k+"_") {
+ return true
+ }
+ }
+ }
+ return false
+}
+
// rewriteCalls rewrites all calls that pass pointers to check that
// they follow the rules for passing pointers between Go and C.
-// This returns whether the package needs to import unsafe as _cgo_unsafe.
+// This reports whether the package needs to import unsafe as _cgo_unsafe.
func (p *Package) rewriteCalls(f *File) bool {
needsUnsafe := false
+ // Walk backward so that in C.f1(C.f2()) we rewrite C.f2 first.
for _, call := range f.Calls {
- // This is a call to C.xxx; set goname to "xxx".
- goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name
- if goname == "malloc" {
- continue
- }
- name := f.Name[goname]
- if name.Kind != "func" {
- // Probably a type conversion.
+ if call.Done {
continue
}
- if p.rewriteCall(f, call, name) {
- needsUnsafe = true
+ start := f.offset(call.Call.Pos())
+ end := f.offset(call.Call.End())
+ str, nu := p.rewriteCall(f, call)
+ if str != "" {
+ f.Edit.Replace(start, end, str)
+ if nu {
+ needsUnsafe = true
+ }
}
}
return needsUnsafe
@@ -739,162 +785,206 @@ func (p *Package) rewriteCalls(f *File) bool {
// If any pointer checks are required, we rewrite the call into a
// function literal that calls _cgoCheckPointer for each pointer
// argument and then calls the original function.
-// This returns whether the package needs to import unsafe as _cgo_unsafe.
-func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool {
+// This returns the rewritten call and whether the package needs to
+// import unsafe as _cgo_unsafe.
+// If it returns the empty string, the call did not need to be rewritten.
+func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
+ // This is a call to C.xxx; set goname to "xxx".
+ // It may have already been mangled by rewriteName.
+ var goname string
+ switch fun := call.Call.Fun.(type) {
+ case *ast.SelectorExpr:
+ goname = fun.Sel.Name
+ case *ast.Ident:
+ goname = strings.TrimPrefix(fun.Name, "_C2func_")
+ goname = strings.TrimPrefix(goname, "_Cfunc_")
+ }
+ if goname == "" || goname == "malloc" {
+ return "", false
+ }
+ name := f.Name[goname]
+ if name == nil || name.Kind != "func" {
+ // Probably a type conversion.
+ return "", false
+ }
+
+ params := name.FuncType.Params
+ args := call.Call.Args
+
// Avoid a crash if the number of arguments is
// less than the number of parameters.
// This will be caught when the generated file is compiled.
- if len(call.Call.Args) < len(name.FuncType.Params) {
- return false
+ if len(args) < len(params) {
+ return "", false
}
any := false
- for i, param := range name.FuncType.Params {
- if p.needsPointerCheck(f, param.Go, call.Call.Args[i]) {
+ for i, param := range params {
+ if p.needsPointerCheck(f, param.Go, args[i]) {
any = true
break
}
}
if !any {
- return false
+ return "", false
}
// We need to rewrite this call.
//
- // We are going to rewrite C.f(p) to
- // func (_cgo0 ptype) {
+ // Rewrite C.f(p) to
+ // func() {
+ // _cgo0 := p
// _cgoCheckPointer(_cgo0)
// C.f(_cgo0)
- // }(p)
- // Using a function literal like this lets us do correct
- // argument type checking, and works correctly if the call is
- // deferred.
+ // }()
+ // Using a function literal like this lets us evaluate the
+ // function arguments only once while doing pointer checks.
+ // This is particularly useful when passing additional arguments
+ // to _cgoCheckPointer, as done in checkIndex and checkAddr.
+ //
+ // When the function argument is a conversion to unsafe.Pointer,
+ // we unwrap the conversion before checking the pointer,
+ // and then wrap again when calling C.f. This lets us check
+ // the real type of the pointer in some cases. See issue #25941.
+ //
+ // When the call to C.f is deferred, we use an additional function
+ // literal to evaluate the arguments at the right time.
+ // defer func() func() {
+ // _cgo0 := p
+ // return func() {
+ // _cgoCheckPointer(_cgo0)
+ // C.f(_cgo0)
+ // }
+ // }()()
+ // This works because the defer statement evaluates the first
+ // function literal in order to get the function to call.
+
+ var sb bytes.Buffer
+ sb.WriteString("func() ")
+ if call.Deferred {
+ sb.WriteString("func() ")
+ }
+
needsUnsafe := false
- params := make([]*ast.Field, len(name.FuncType.Params))
- nargs := make([]ast.Expr, len(name.FuncType.Params))
- var stmts []ast.Stmt
- for i, param := range name.FuncType.Params {
- // params is going to become the parameters of the
- // function literal.
- // nargs is going to become the list of arguments made
- // by the call within the function literal.
- // nparam is the parameter of the function literal that
- // corresponds to param.
-
- origArg := call.Call.Args[i]
- nparam := ast.NewIdent(fmt.Sprintf("_cgo%d", i))
- nargs[i] = nparam
-
- // The Go version of the C type might use unsafe.Pointer,
- // but the file might not import unsafe.
- // Rewrite the Go type if necessary to use _cgo_unsafe.
- ptype := p.rewriteUnsafe(param.Go)
- if ptype != param.Go {
- needsUnsafe = true
+ result := false
+ twoResults := false
+ if !call.Deferred {
+ // Check whether this call expects two results.
+ for _, ref := range f.Ref {
+ if ref.Expr != &call.Call.Fun {
+ continue
+ }
+ if ref.Context == ctxCall2 {
+ sb.WriteString("(")
+ result = true
+ twoResults = true
+ }
+ break
}
- params[i] = &ast.Field{
- Names: []*ast.Ident{nparam},
- Type: ptype,
+ // Add the result type, if any.
+ if name.FuncType.Result != nil {
+ rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
+ if rtype != name.FuncType.Result.Go {
+ needsUnsafe = true
+ }
+ sb.WriteString(gofmtLine(rtype))
+ result = true
}
- if !p.needsPointerCheck(f, param.Go, origArg) {
- continue
+ // Add the second result type, if any.
+ if twoResults {
+ if name.FuncType.Result == nil {
+ // An explicit void result looks odd but it
+ // seems to be how cgo has worked historically.
+ sb.WriteString("_Ctype_void")
+ }
+ sb.WriteString(", error)")
}
+ }
- // Run the cgo pointer checks on nparam.
+ sb.WriteString("{ ")
- // Change the function literal to call the real function
- // with the parameter passed through _cgoCheckPointer.
- c := &ast.CallExpr{
- Fun: ast.NewIdent("_cgoCheckPointer"),
- Args: []ast.Expr{
- nparam,
- },
+ // Define _cgoN for each argument value.
+ // Write _cgoCheckPointer calls to sbCheck.
+ var sbCheck bytes.Buffer
+ for i, param := range params {
+ origArg := args[i]
+ arg, nu := p.mangle(f, &args[i])
+ if nu {
+ needsUnsafe = true
}
- // Add optional additional arguments for an address
- // expression.
- c.Args = p.checkAddrArgs(f, c.Args, origArg)
+ // Explicitly convert untyped constants to the
+ // parameter type, to avoid a type mismatch.
+ if p.isConst(f, arg) {
+ ptype := p.rewriteUnsafe(param.Go)
+ if ptype != param.Go {
+ needsUnsafe = true
+ }
+ arg = &ast.CallExpr{
+ Fun: ptype,
+ Args: []ast.Expr{arg},
+ }
+ }
+
+ if !p.needsPointerCheck(f, param.Go, args[i]) {
+ fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
+ continue
+ }
- stmt := &ast.ExprStmt{
- X: c,
+ // Check for &a[i].
+ if p.checkIndex(&sb, &sbCheck, arg, i) {
+ continue
+ }
+
+ // Check for &x.
+ if p.checkAddr(&sb, &sbCheck, arg, i) {
+ continue
}
- stmts = append(stmts, stmt)
+
+ fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
+ fmt.Fprintf(&sbCheck, "_cgoCheckPointer(_cgo%d); ", i)
}
- const cgoMarker = "__cgo__###__marker__"
- fcall := &ast.CallExpr{
- Fun: ast.NewIdent(cgoMarker),
- Args: nargs,
+ if call.Deferred {
+ sb.WriteString("return func() { ")
}
- ftype := &ast.FuncType{
- Params: &ast.FieldList{
- List: params,
- },
+
+ // Write out the calls to _cgoCheckPointer.
+ sb.WriteString(sbCheck.String())
+
+ if result {
+ sb.WriteString("return ")
}
- if name.FuncType.Result != nil {
- rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
- if rtype != name.FuncType.Result.Go {
- needsUnsafe = true
- }
- ftype.Results = &ast.FieldList{
- List: []*ast.Field{
- &ast.Field{
- Type: rtype,
- },
- },
- }
- }
-
- // If this call expects two results, we have to
- // adjust the results of the function we generated.
- for _, ref := range f.Ref {
- if ref.Expr == &call.Call.Fun && ref.Context == ctxCall2 {
- if ftype.Results == nil {
- // An explicit void argument
- // looks odd but it seems to
- // be how cgo has worked historically.
- ftype.Results = &ast.FieldList{
- List: []*ast.Field{
- &ast.Field{
- Type: ast.NewIdent("_Ctype_void"),
- },
- },
- }
- }
- ftype.Results.List = append(ftype.Results.List,
- &ast.Field{
- Type: ast.NewIdent("error"),
- })
- }
+
+ m, nu := p.mangle(f, &call.Call.Fun)
+ if nu {
+ needsUnsafe = true
}
+ sb.WriteString(gofmtLine(m))
- var fbody ast.Stmt
- if ftype.Results == nil {
- fbody = &ast.ExprStmt{
- X: fcall,
- }
- } else {
- fbody = &ast.ReturnStmt{
- Results: []ast.Expr{fcall},
+ sb.WriteString("(")
+ for i := range params {
+ if i > 0 {
+ sb.WriteString(", ")
}
+ fmt.Fprintf(&sb, "_cgo%d", i)
}
- lit := &ast.FuncLit{
- Type: ftype,
- Body: &ast.BlockStmt{
- List: append(stmts, fbody),
- },
+ sb.WriteString("); ")
+ if call.Deferred {
+ sb.WriteString("}")
}
- text := strings.Replace(gofmt(lit), "\n", ";", -1)
- repl := strings.Split(text, cgoMarker)
- f.Edit.Insert(f.offset(call.Call.Fun.Pos()), repl[0])
- f.Edit.Insert(f.offset(call.Call.Fun.End()), repl[1])
+ sb.WriteString("}")
+ if call.Deferred {
+ sb.WriteString("()")
+ }
+ sb.WriteString("()")
- return needsUnsafe
+ return sb.String(), needsUnsafe
}
-// needsPointerCheck returns whether the type t needs a pointer check.
+// needsPointerCheck reports whether the type t needs a pointer check.
// This is true if t is a pointer and if the value to which it points
// might contain a pointer.
func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
@@ -911,7 +1001,7 @@ func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
// hasPointer is used by needsPointerCheck. If top is true it returns
// whether t is or contains a pointer that might point to a pointer.
-// If top is false it returns whether t is or contains a pointer.
+// If top is false it reports whether t is or contains a pointer.
// f may be nil.
func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
switch t := t.(type) {
@@ -998,19 +1088,68 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
}
}
-// checkAddrArgs tries to add arguments to the call of
-// _cgoCheckPointer when the argument is an address expression. We
-// pass true to mean that the argument is an address operation of
-// something other than a slice index, which means that it's only
-// necessary to check the specific element pointed to, not the entire
-// object. This is for &s.f, where f is a field in a struct. We can
-// pass a slice or array, meaning that we should check the entire
-// slice or array but need not check any other part of the object.
-// This is for &s.a[i], where we need to check all of a. However, we
-// only pass the slice or array if we can refer to it without side
-// effects.
-func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr {
+// mangle replaces references to C names in arg with the mangled names,
+// rewriting calls when it finds them.
+// It removes the corresponding references in f.Ref and f.Calls, so that we
+// don't try to do the replacement again in rewriteRef or rewriteCall.
+func (p *Package) mangle(f *File, arg *ast.Expr) (ast.Expr, bool) {
+ needsUnsafe := false
+ f.walk(arg, ctxExpr, func(f *File, arg interface{}, context astContext) {
+ px, ok := arg.(*ast.Expr)
+ if !ok {
+ return
+ }
+ sel, ok := (*px).(*ast.SelectorExpr)
+ if ok {
+ if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
+ return
+ }
+
+ for _, r := range f.Ref {
+ if r.Expr == px {
+ *px = p.rewriteName(f, r)
+ r.Done = true
+ break
+ }
+ }
+
+ return
+ }
+
+ call, ok := (*px).(*ast.CallExpr)
+ if !ok {
+ return
+ }
+
+ for _, c := range f.Calls {
+ if !c.Done && c.Call.Lparen == call.Lparen {
+ cstr, nu := p.rewriteCall(f, c)
+ if cstr != "" {
+ // Smuggle the rewritten call through an ident.
+ *px = ast.NewIdent(cstr)
+ if nu {
+ needsUnsafe = true
+ }
+ c.Done = true
+ }
+ }
+ }
+ })
+ return *arg, needsUnsafe
+}
+
+// checkIndex checks whether arg has the form &a[i], possibly inside
+// type conversions. If so, it writes
+// _cgoIndexNN := a
+// _cgoNN := &cgoIndexNN[i] // with type conversions, if any
+// to sb, and writes
+// _cgoCheckPointer(_cgoNN, _cgoIndexNN)
+// to sbCheck, and returns true. This tells _cgoCheckPointer to check
+// the complete contents of the slice or array being indexed, but no
+// other part of the memory allocation.
+func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
// Strip type conversions.
+ x := arg
for {
c, ok := x.(*ast.CallExpr)
if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
@@ -1020,40 +1159,63 @@ func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr
}
u, ok := x.(*ast.UnaryExpr)
if !ok || u.Op != token.AND {
- return args
+ return false
}
index, ok := u.X.(*ast.IndexExpr)
if !ok {
- // This is the address of something that is not an
- // index expression. We only need to examine the
- // single value to which it points.
- // TODO: what if true is shadowed?
- return append(args, ast.NewIdent("true"))
- }
- if !p.hasSideEffects(f, index.X) {
- // Examine the entire slice.
- return append(args, index.X)
- }
- // Treat the pointer as unknown.
- return args
+ return false
+ }
+
+ fmt.Fprintf(sb, "_cgoIndex%d := %s; ", i, gofmtPos(index.X, index.X.Pos()))
+ origX := index.X
+ index.X = ast.NewIdent(fmt.Sprintf("_cgoIndex%d", i))
+ fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
+ index.X = origX
+
+ fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgo%d, _cgoIndex%d); ", i, i)
+
+ return true
}
-// hasSideEffects returns whether the expression x has any side
-// effects. x is an expression, not a statement, so the only side
-// effect is a function call.
-func (p *Package) hasSideEffects(f *File, x ast.Expr) bool {
- found := false
- f.walk(x, ctxExpr,
- func(f *File, x interface{}, context astContext) {
- switch x.(type) {
- case *ast.CallExpr:
- found = true
- }
- })
- return found
+// checkAddr checks whether arg has the form &x, possibly inside type
+// conversions. If so, it writes
+// _cgoBaseNN := &x
+// _cgoNN := _cgoBaseNN // with type conversions, if any
+// to sb, and writes
+// _cgoCheckPointer(_cgoBaseNN, true)
+// to sbCheck, and returns true. This tells _cgoCheckPointer to check
+// just the contents of the pointer being passed, not any other part
+// of the memory allocation. This is run after checkIndex, which looks
+// for the special case of &a[i], which requires different checks.
+func (p *Package) checkAddr(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
+ // Strip type conversions.
+ px := &arg
+ for {
+ c, ok := (*px).(*ast.CallExpr)
+ if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
+ break
+ }
+ px = &c.Args[0]
+ }
+ if u, ok := (*px).(*ast.UnaryExpr); !ok || u.Op != token.AND {
+ return false
+ }
+
+ fmt.Fprintf(sb, "_cgoBase%d := %s; ", i, gofmtPos(*px, (*px).Pos()))
+
+ origX := *px
+ *px = ast.NewIdent(fmt.Sprintf("_cgoBase%d", i))
+ fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
+ *px = origX
+
+ // Use "0 == 0" to do the right thing in the unlikely event
+ // that "true" is shadowed.
+ fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgoBase%d, 0 == 0); ", i)
+
+ return true
}
-// isType returns whether the expression is definitely a type.
+// isType reports whether the expression is definitely a type.
// This is conservative--it returns false for an unknown identifier.
func (p *Package) isType(t ast.Expr) bool {
switch t := t.(type) {
@@ -1082,6 +1244,9 @@ func (p *Package) isType(t ast.Expr) bool {
return true
}
+ if strings.HasPrefix(t.Name, "_Ctype_") {
+ return true
+ }
case *ast.StarExpr:
return p.isType(t.X)
case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
@@ -1092,6 +1257,47 @@ func (p *Package) isType(t ast.Expr) bool {
return false
}
+// isConst reports whether x is an untyped constant expression.
+func (p *Package) isConst(f *File, x ast.Expr) bool {
+ switch x := x.(type) {
+ case *ast.BasicLit:
+ return true
+ case *ast.SelectorExpr:
+ id, ok := x.X.(*ast.Ident)
+ if !ok || id.Name != "C" {
+ return false
+ }
+ name := f.Name[x.Sel.Name]
+ if name != nil {
+ return name.IsConst()
+ }
+ case *ast.Ident:
+ return x.Name == "nil" ||
+ strings.HasPrefix(x.Name, "_Ciconst_") ||
+ strings.HasPrefix(x.Name, "_Cfconst_") ||
+ strings.HasPrefix(x.Name, "_Csconst_") ||
+ consts[x.Name]
+ case *ast.UnaryExpr:
+ return p.isConst(f, x.X)
+ case *ast.BinaryExpr:
+ return p.isConst(f, x.X) && p.isConst(f, x.Y)
+ case *ast.ParenExpr:
+ return p.isConst(f, x.X)
+ case *ast.CallExpr:
+ // Calling the builtin function complex on two untyped
+ // constants returns an untyped constant.
+ // TODO: It's possible to construct a case that will
+ // erroneously succeed if there is a local function
+ // named "complex", shadowing the builtin, that returns
+ // a numeric type. I can't think of any cases that will
+ // erroneously fail.
+ if id, ok := x.Fun.(*ast.Ident); ok && id.Name == "complex" && len(x.Args) == 2 {
+ return p.isConst(f, x.Args[0]) && p.isConst(f, x.Args[1])
+ }
+ }
+ return false
+}
+
// rewriteUnsafe returns a version of t with references to unsafe.Pointer
// rewritten to use _cgo_unsafe.Pointer instead.
func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
@@ -1150,24 +1356,7 @@ func (p *Package) rewriteRef(f *File) {
// code for them.
functions := make(map[string]bool)
- // Assign mangled names.
for _, n := range f.Name {
- if n.Kind == "not-type" {
- if n.Define == "" {
- n.Kind = "var"
- } else {
- n.Kind = "macro"
- n.FuncType = &FuncType{
- Result: n.Type,
- Go: &ast.FuncType{
- Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}},
- },
- }
- }
- }
- if n.Mangle == "" {
- p.mangleName(n)
- }
if n.Kind == "func" {
functions[n.Go] = false
}
@@ -1181,104 +1370,16 @@ func (p *Package) rewriteRef(f *File) {
if r.Name.IsConst() && r.Name.Const == "" {
error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
}
- var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
- switch r.Context {
- case ctxCall, ctxCall2:
- if r.Name.Kind != "func" {
- if r.Name.Kind == "type" {
- 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))
- break
- }
- functions[r.Name.Go] = true
- if r.Context == ctxCall2 {
- if r.Name.Go == "_CMalloc" {
- error_(r.Pos(), "no two-result form for C.malloc")
- break
- }
- // Invent new Name for the two-result function.
- n := f.Name["2"+r.Name.Go]
- if n == nil {
- n = new(Name)
- *n = *r.Name
- n.AddError = true
- n.Mangle = "_C2func_" + n.Go
- f.Name["2"+r.Name.Go] = n
- }
- expr = ast.NewIdent(n.Mangle)
- r.Name = n
- break
- }
- case ctxExpr:
- switch r.Name.Kind {
- case "func":
- if builtinDefs[r.Name.C] != "" {
- error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
- }
- // Function is being used in an expression, to e.g. pass around a C function pointer.
- // Create a new Name for this Ref which causes the variable to be declared in Go land.
- fpName := "fp_" + r.Name.Go
- name := f.Name[fpName]
- if name == nil {
- name = &Name{
- Go: fpName,
- C: r.Name.C,
- Kind: "fpvar",
- Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
- }
- p.mangleName(name)
- f.Name[fpName] = name
- }
- r.Name = name
- // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
- // function is defined in out.go and simply returns its argument. See
- // issue 7757.
- expr = &ast.CallExpr{
- Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
- Args: []ast.Expr{ast.NewIdent(name.Mangle)},
- }
- case "type":
- // 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":
- expr = &ast.CallExpr{Fun: expr}
- }
- case ctxSelector:
- if r.Name.Kind == "var" {
- expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
- } else {
- error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
- }
- case ctxType:
- if r.Name.Kind != "type" {
- error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
- } else if r.Name.Type == nil {
- // 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" {
- error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
+ if r.Name.Kind == "func" {
+ switch r.Context {
+ case ctxCall, ctxCall2:
+ functions[r.Name.Go] = true
}
}
+ expr := p.rewriteName(f, r)
+
if *godefs {
// Substitute definition for mangled type name.
if id, ok := expr.(*ast.Ident); ok {
@@ -1295,8 +1396,7 @@ func (p *Package) rewriteRef(f *File) {
// in case expression being replaced is first on line.
// See golang.org/issue/6563.
pos := (*r.Expr).Pos()
- switch x := expr.(type) {
- case *ast.Ident:
+ if x, ok := expr.(*ast.Ident); ok {
expr = &ast.Ident{NamePos: pos, Name: x.Name}
}
@@ -1306,11 +1406,26 @@ func (p *Package) rewriteRef(f *File) {
*r.Expr = expr
// Record source-level edit for cgo output.
- repl := gofmt(expr)
- if r.Name.Kind != "type" {
- repl = "(" + repl + ")"
+ if !r.Done {
+ // Prepend a space in case the earlier code ends
+ // with '/', which would give us a "//" comment.
+ repl := " " + gofmtPos(expr, old.Pos())
+ end := fset.Position(old.End())
+ // Subtract 1 from the column if we are going to
+ // append a close parenthesis. That will set the
+ // correct column for the following characters.
+ sub := 0
+ if r.Name.Kind != "type" {
+ sub = 1
+ }
+ if end.Column > sub {
+ repl = fmt.Sprintf("%s /*line :%d:%d*/", repl, end.Line, end.Column-sub)
+ }
+ if r.Name.Kind != "type" {
+ repl = "(" + repl + ")"
+ }
+ f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl)
}
- f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl)
}
// Remove functions only used as expressions, so their respective
@@ -1322,6 +1437,118 @@ func (p *Package) rewriteRef(f *File) {
}
}
+// rewriteName returns the expression used to rewrite a reference.
+func (p *Package) rewriteName(f *File, r *Ref) ast.Expr {
+ var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
+ switch r.Context {
+ case ctxCall, ctxCall2:
+ if r.Name.Kind != "func" {
+ if r.Name.Kind == "type" {
+ 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))
+ break
+ }
+ if r.Context == ctxCall2 {
+ if r.Name.Go == "_CMalloc" {
+ error_(r.Pos(), "no two-result form for C.malloc")
+ break
+ }
+ // Invent new Name for the two-result function.
+ n := f.Name["2"+r.Name.Go]
+ if n == nil {
+ n = new(Name)
+ *n = *r.Name
+ n.AddError = true
+ n.Mangle = "_C2func_" + n.Go
+ f.Name["2"+r.Name.Go] = n
+ }
+ expr = ast.NewIdent(n.Mangle)
+ r.Name = n
+ break
+ }
+ case ctxExpr:
+ switch r.Name.Kind {
+ case "func":
+ if builtinDefs[r.Name.C] != "" {
+ error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
+ }
+
+ // Function is being used in an expression, to e.g. pass around a C function pointer.
+ // Create a new Name for this Ref which causes the variable to be declared in Go land.
+ fpName := "fp_" + r.Name.Go
+ name := f.Name[fpName]
+ if name == nil {
+ name = &Name{
+ Go: fpName,
+ C: r.Name.C,
+ Kind: "fpvar",
+ Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
+ }
+ p.mangleName(name)
+ f.Name[fpName] = name
+ }
+ r.Name = name
+ // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
+ // function is defined in out.go and simply returns its argument. See
+ // issue 7757.
+ expr = &ast.CallExpr{
+ Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
+ Args: []ast.Expr{ast.NewIdent(name.Mangle)},
+ }
+ case "type":
+ // 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":
+ expr = &ast.CallExpr{Fun: expr}
+ }
+ case ctxSelector:
+ if r.Name.Kind == "var" {
+ expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
+ } else {
+ error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
+ }
+ case ctxType:
+ if r.Name.Kind != "type" {
+ error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
+ } else if r.Name.Type == nil {
+ // 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" {
+ error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
+ }
+ }
+ return expr
+}
+
+// gofmtPos returns the gofmt-formatted string for an AST node,
+// with a comment setting the position before the node.
+func gofmtPos(n ast.Expr, pos token.Pos) string {
+ s := gofmtLine(n)
+ p := fset.Position(pos)
+ if p.Column == 0 {
+ return s
+ }
+ return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s)
+}
+
// gccBaseCmd returns the start of the compiler command line.
// It uses $CC if set, or else $GCC, or else the compiler recorded
// during the initial build as defaultCC.
@@ -1400,6 +1627,9 @@ func (p *Package) gccCmd() []string {
c = append(c, p.GccOptions...)
c = append(c, p.gccMachine()...)
+ if goos == "aix" {
+ c = append(c, "-maix64")
+ }
c = append(c, "-") //read input from standard input
return c
}
@@ -1754,10 +1984,8 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
}
buildStrings()
-
return d, ints, floats, strs
}
-
fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp())
panic("not reached")
}
@@ -1788,6 +2016,11 @@ func (p *Package) gccErrors(stdin []byte) string {
}
}
+ // Force -O0 optimization but keep the trailing "-" at the end.
+ nargs = append(nargs, "-O0")
+ nl := len(nargs)
+ nargs[nl-2], nargs[nl-1] = nargs[nl-1], nargs[nl-2]
+
if *debugGcc {
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
os.Stderr.Write(stdin)
@@ -1829,10 +2062,10 @@ func runGcc(stdin []byte, args []string) (string, string) {
// with equivalent memory layout.
type typeConv struct {
// Cache of already-translated or in-progress types.
- m map[dwarf.Type]*Type
+ m map[string]*Type
// Map from types to incomplete pointers to those types.
- ptrs map[dwarf.Type][]*Type
+ ptrs map[string][]*Type
// Keys of ptrs in insertion order (deterministic worklist)
// ptrKeys contains exactly the keys in ptrs.
ptrKeys []dwarf.Type
@@ -1867,8 +2100,8 @@ var unionWithPointer = make(map[ast.Expr]bool)
func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
c.intSize = intSize
- c.m = make(map[dwarf.Type]*Type)
- c.ptrs = make(map[dwarf.Type][]*Type)
+ c.m = make(map[string]*Type)
+ c.ptrs = make(map[string][]*Type)
c.getTypeIDs = make(map[string]bool)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
@@ -1976,11 +2209,12 @@ func (c *typeConv) FinishType(pos token.Pos) {
// Keep looping until they're all done.
for len(c.ptrKeys) > 0 {
dtype := c.ptrKeys[0]
+ dtypeKey := dtype.String()
c.ptrKeys = c.ptrKeys[1:]
- ptrs := c.ptrs[dtype]
- delete(c.ptrs, dtype)
+ ptrs := c.ptrs[dtypeKey]
+ delete(c.ptrs, dtypeKey)
- // Note Type might invalidate c.ptrs[dtype].
+ // Note Type might invalidate c.ptrs[dtypeKey].
t := c.Type(dtype, pos)
for _, ptr := range ptrs {
ptr.Go.(*ast.StarExpr).X = t.Go
@@ -1992,18 +2226,29 @@ func (c *typeConv) FinishType(pos token.Pos) {
// Type returns a *Type with the same memory layout as
// dtype when used as the type of a variable or a struct field.
func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
- if t, ok := c.m[dtype]; ok {
- if t.Go == nil {
- fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
+ // Always recompute bad pointer typedefs, as the set of such
+ // typedefs changes as we see more types.
+ checkCache := true
+ if dtt, ok := dtype.(*dwarf.TypedefType); ok && c.badPointerTypedef(dtt) {
+ checkCache = false
+ }
+
+ key := dtype.String()
+
+ if checkCache {
+ if t, ok := c.m[key]; ok {
+ if t.Go == nil {
+ fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
+ }
+ return t
}
- return t
}
t := new(Type)
t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
t.Align = -1
t.C = &TypeRepr{Repr: dtype.Common().Name}
- c.m[dtype] = t
+ c.m[key] = t
switch dt := dtype.(type) {
default:
@@ -2166,10 +2411,11 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
// Placeholder initialization; completed in FinishType.
t.Go = &ast.StarExpr{}
t.C.Set("<incomplete>*")
- if _, ok := c.ptrs[dt.Type]; !ok {
+ key := dt.Type.String()
+ if _, ok := c.ptrs[key]; !ok {
c.ptrKeys = append(c.ptrKeys, dt.Type)
}
- c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
+ c.ptrs[key] = append(c.ptrs[key], t)
case *dwarf.QualType:
t1 := c.Type(dt.Type, pos)
@@ -2557,11 +2803,6 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
anon := 0
for _, f := range dt.Field {
- if f.ByteOffset > off {
- fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
- off = f.ByteOffset
- }
-
name := f.Name
ft := f.Type
@@ -2610,6 +2851,19 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
// structs are in system headers that cannot be corrected.
continue
}
+
+ // Round off up to talign, assumed to be a power of 2.
+ off = (off + talign - 1) &^ (talign - 1)
+
+ if f.ByteOffset > off {
+ fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
+ off = f.ByteOffset
+ }
+ if f.ByteOffset < off {
+ // Drop a packed field that we can't represent.
+ continue
+ }
+
n := len(fld)
fld = fld[0 : n+1]
if name == "" {
@@ -2659,7 +2913,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
return
}
-// dwarfHasPointer returns whether the DWARF type dt contains a pointer.
+// dwarfHasPointer reports whether the DWARF type dt contains a pointer.
func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
switch dt := dt.(type) {
default:
@@ -2776,6 +3030,9 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
if c.badJNI(dt) {
return true
}
+ if c.badEGLDisplay(dt) {
+ return true
+ }
return false
}
@@ -2912,6 +3169,19 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
return false
}
+func (c *typeConv) badEGLDisplay(dt *dwarf.TypedefType) bool {
+ if dt.Name != "EGLDisplay" {
+ return false
+ }
+ // Check that the typedef is "typedef void *EGLDisplay".
+ if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
+ if _, ok := ptr.Type.(*dwarf.VoidType); ok {
+ return true
+ }
+ }
+ return false
+}
+
// jniTypes maps from JNI types that we want to be uintptrs, to the underlying type to which
// they are mapped. The base "jobject" maps to the empty string.
var jniTypes = map[string]string{
diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go
index 6720945cddd..9c763a22fb0 100644
--- a/libgo/go/cmd/cgo/godefs.go
+++ b/libgo/go/cmd/cgo/godefs.go
@@ -126,3 +126,9 @@ func gofmt(n interface{}) string {
}
return gofmtBuf.String()
}
+
+// gofmtLine returns the gofmt-formatted string for an AST node,
+// ensuring that it is on a single line.
+func gofmtLine(n interface{}) string {
+ return strings.Replace(gofmt(n), "\n", ";", -1)
+}
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
index 8e7567b5b0e..4a5c0ca2bab 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -47,7 +47,14 @@ type Package struct {
GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h
typedefs map[string]bool // type names that appear in the types of the objects we're interested in
- typedefList []string
+ typedefList []typedefInfo
+}
+
+// A typedefInfo is an element on Package.typedefList: a typedef name
+// and the position where it was required.
+type typedefInfo struct {
+ typedef string
+ pos token.Pos
}
// A File collects information about a single Go input file.
@@ -64,6 +71,9 @@ type File struct {
Edit *edit.Buffer
}
+// Untyped constants in the current package.
+var consts = make(map[string]bool)
+
func (f *File) offset(p token.Pos) int {
return fset.Position(p).Offset
}
@@ -81,6 +91,7 @@ func nameKeys(m map[string]*Name) []string {
type Call struct {
Call *ast.CallExpr
Deferred bool
+ Done bool
}
// A Ref refers to an expression of the form C.xxx in the AST.
@@ -88,19 +99,22 @@ type Ref struct {
Name *Name
Expr *ast.Expr
Context astContext
+ Done bool
}
func (r *Ref) Pos() token.Pos {
return (*r.Expr).Pos()
}
+var nameKinds = []string{"iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"}
+
// A Name collects information about C.xxx.
type Name struct {
Go string // name used in Go referring to package C
Mangle string // name used in generated Go
C string // name used in C
Define string // #define expansion
- Kind string // "iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"
+ Kind string // one of the nameKinds
Type *Type // the type of xxx
FuncType *FuncType
AddError bool
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 50e57157793..f44da9c8b12 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -9,11 +9,11 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
- "debug/xcoff"
"fmt"
"go/ast"
"go/printer"
"go/token"
+ "internal/xcoff"
"io"
"io/ioutil"
"os"
@@ -251,7 +251,22 @@ func (p *Package) writeDefs() {
init := gccgoInit.String()
if init != "" {
- fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));")
+ // The init function does nothing but simple
+ // assignments, so it won't use much stack space, so
+ // it's OK to not split the stack. Splitting the stack
+ // can run into a bug in clang (as of 2018-11-09):
+ // this is a leaf function, and when clang sees a leaf
+ // function it won't emit the split stack prologue for
+ // the function. However, if this function refers to a
+ // non-split-stack function, which will happen if the
+ // cgo code refers to a C function not compiled with
+ // -fsplit-stack, then the linker will think that it
+ // needs to adjust the split stack prologue, but there
+ // won't be one. Marking the function explicitly
+ // no_split_stack works around this problem by telling
+ // the linker that it's OK if there is no split stack
+ // prologue.
+ fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor, no_split_stack));")
fmt.Fprintln(fc, "static void init(void) {")
fmt.Fprint(fc, init)
fmt.Fprintln(fc, "}")
@@ -1193,7 +1208,7 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
}
-// gccgoUsesNewMangling returns whether gccgo uses the new collision-free
+// gccgoUsesNewMangling reports whether gccgo uses the new collision-free
// packagepath mangling scheme (see determineGccgoManglingScheme for more
// info).
func gccgoUsesNewMangling() bool {
@@ -1545,6 +1560,7 @@ const builtinProlog = `
/* Define intgo when compiling with GCC. */
typedef ptrdiff_t intgo;
+#define GO_CGO_GOSTRING_TYPEDEF
typedef struct { const char *p; intgo n; } _GoString_;
typedef struct { char *p; intgo n; intgo c; } _GoBytes_;
_GoString_ GoString(char *p);
@@ -1555,7 +1571,7 @@ void *CBytes(_GoBytes_);
void *_CMalloc(size_t);
__attribute__ ((unused))
-static size_t _GoStringLen(_GoString_ s) { return s.n; }
+static size_t _GoStringLen(_GoString_ s) { return (size_t)s.n; }
__attribute__ ((unused))
static const char *_GoStringPtr(_GoString_ s) { return s.p; }
@@ -1796,15 +1812,20 @@ void localCgoCheckResult(Eface val) {
// because _cgo_export.h defines GoString as a struct while builtinProlog
// defines it as a function. We don't change this to avoid unnecessarily
// breaking existing code.
+// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
+// error if a Go file with a cgo comment #include's the export header
+// generated by a different package.
const builtinExportProlog = `
-#line 1 "cgo-builtin-prolog"
+#line 1 "cgo-builtin-export-prolog"
#include <stddef.h> /* for ptrdiff_t below */
#ifndef GO_CGO_EXPORT_PROLOGUE_H
#define GO_CGO_EXPORT_PROLOGUE_H
+#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
+#endif
#endif
`
@@ -1813,6 +1834,19 @@ func (p *Package) gccExportHeaderProlog() string {
return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
}
+// gccExportHeaderProlog is written to the exported header, after the
+// import "C" comment preamble but before the generated declarations
+// of exported functions. This permits the generated declarations to
+// use the type names that appear in goTypes, above.
+//
+// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
+// error if a Go file with a cgo comment #include's the export header
+// generated by a different package. Unfortunately GoString means two
+// different things: in this prolog it means a C name for the Go type,
+// while in the prolog written into the start of the C code generated
+// from a cgo-using Go file it means the C.GoString function. There is
+// no way to resolve this conflict, but it also doesn't make much
+// difference, as Go code never wants to refer to the latter meaning.
const gccExportHeaderProlog = `
/* Start of boilerplate cgo prologue. */
#line 1 "cgo-gcc-export-header-prolog"
@@ -1842,7 +1876,9 @@ typedef double _Complex GoComplex128;
*/
typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
+#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef _GoString_ GoString;
+#endif
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;