[release-branch.go1.1] cmd/cgo: gccgo fixes

««« CL 11406047 / 4d9c3095de9d
cmd/cgo: gccgo fixes

Don't require a full-scale callback for calls to the special
prologue functions.

Always use a simple wrapper function for C functions, so that
we can handle static functions defined in the import "C"
comment.

Disable a test that relies on gc-specific function names.

Fixes #5905.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/11406047

»»»

Update #5928

R=golang-dev, dave
CC=golang-dev
https://golang.org/cl/11887043
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index b6e2e3c..c642d5f 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 ee1d891..7fb8181 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -318,6 +318,9 @@
 		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
 	}
 
@@ -518,6 +526,54 @@
 	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")
+}
+
 // Write out the various stubs we need to support functions exported
 // from Go so that they are callable from C.
 func (p *Package) writeExports(fgo2, fc, fm *os.File) {