misc/cgo/test/callback.go | 4 ++++ src/cmd/cgo/out.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++----- diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go index b6e2e3c1ce00dae4b673f970fabf49e321ebc089..c642d5f0fb7914481b257b1d3ab6312103e5c89b 100644 --- a/misc/cgo/test/callback.go +++ b/misc/cgo/test/callback.go @@ -142,6 +142,10 @@ // Test that the stack can be unwound through a call out and call back // into Go. func testCallbackCallers(t *testing.T) { + if runtime.Compiler != "gc" { + // The exact function names are not going to be the same. + t.Skip("skipping for non-gc toolchain") + } pc := make([]uintptr, 100) n := 0 name := []string{ diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index ee1d89142e9007453050550311cac55297ca664d..7fb81816897af7dde3bfe21708542484349f0554 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -318,6 +318,9 @@ Name: ast.NewIdent(n.Mangle), Type: gtype, } + // Builtins defined in the C prolog. + inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" + if *gccgo { // Gccgo style hooks. fmt.Fprint(fgo2, "\n") @@ -331,8 +334,10 @@ } conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, " {\n") - fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n") - fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n") + if !inProlog { + fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n") + fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n") + } if n.AddError { fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n") } @@ -363,7 +368,11 @@ fmt.Fprint(fgo2, "}\n") // declare the C function. - fmt.Fprintf(fgo2, "//extern %s\n", n.C) + if inProlog { + fmt.Fprintf(fgo2, "//extern %s\n", n.C) + } else { + fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle) + } d.Name = ast.NewIdent(cname) if n.AddError { l := d.Type.Results.List @@ -377,8 +386,7 @@ } conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, "\n") - if name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" { - // The builtins are already defined in the C prolog. + if inProlog { return } @@ -466,7 +474,7 @@ } p.Written[name] = true if *gccgo { - // we don't use wrappers with gccgo. + p.writeGccgoOutputFunc(fgcc, n) return } @@ -514,6 +522,54 @@ fmt.Fprintf(fgcc, ");\n") if n.AddError { fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n") } + fmt.Fprintf(fgcc, "}\n") + fmt.Fprintf(fgcc, "\n") +} + +// Write out a wrapper for a function when using gccgo. This is a +// simple wrapper that just calls the real function. We only need a +// wrapper to support static functions in the prologue--without a +// wrapper, we can't refer to the function, since the reference is in +// a different file. +func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { + if t := n.FuncType.Result; t != nil { + fmt.Fprintf(fgcc, "%s\n", t.C.String()) + } else { + fmt.Fprintf(fgcc, "void\n") + } + fmt.Fprintf(fgcc, "_cgo%s%s(", cPrefix, n.Mangle) + for i, t := range n.FuncType.Params { + if i > 0 { + fmt.Fprintf(fgcc, ", ") + } + c := t.Typedef + if c == "" { + c = t.C.String() + } + fmt.Fprintf(fgcc, "%s p%d", c, i) + } + fmt.Fprintf(fgcc, ")\n") + fmt.Fprintf(fgcc, "{\n") + fmt.Fprintf(fgcc, "\t") + if t := n.FuncType.Result; t != nil { + fmt.Fprintf(fgcc, "return ") + // Cast to void* to avoid warnings due to omitted qualifiers. + if c := t.C.String(); c[len(c)-1] == '*' { + fmt.Fprintf(fgcc, "(void*)") + } + } + fmt.Fprintf(fgcc, "%s(", n.C) + for i, t := range n.FuncType.Params { + if i > 0 { + fmt.Fprintf(fgcc, ", ") + } + // Cast to void* to avoid warnings due to omitted qualifiers. + if c := t.C.String(); c[len(c)-1] == '*' { + fmt.Fprintf(fgcc, "(void*)") + } + fmt.Fprintf(fgcc, "p%d", i) + } + fmt.Fprintf(fgcc, ");\n") fmt.Fprintf(fgcc, "}\n") fmt.Fprintf(fgcc, "\n") }