diff options
author | Ian Lance Taylor <iant@golang.org> | 2019-01-18 19:04:36 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-01-18 19:04:36 +0000 |
commit | 4f4a855d82a889cebcfca150a7a43909bcb6a346 (patch) | |
tree | f12bae0781920fa34669fe30b6f4615a86d9fb80 /libgo/go/cmd/cgo | |
parent | 225220d668dafb8262db7012bced688acbe63b33 (diff) | |
download | gcc-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.go | 21 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/doc.go | 11 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/gcc.go | 926 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/godefs.go | 6 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/main.go | 18 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/out.go | 46 |
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; |