cmd/cgo: fix cgo checking when fetching errno value
Fixes #18126.
Change-Id: I7ae090945ef203673b06eb94817cc5c894b5eadc
Reviewed-on: https://go-review.googlesource.com/33752
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index 2f59137..a6de999 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -75,5 +75,6 @@
func TestThreadLock(t *testing.T) { testThreadLockFunc(t) }
func TestCheckConst(t *testing.T) { testCheckConst(t) }
func Test17537(t *testing.T) { test17537(t) }
+func Test18126(t *testing.T) { test18126(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/misc/cgo/test/issue18126.go b/misc/cgo/test/issue18126.go
new file mode 100644
index 0000000..ac94a66
--- /dev/null
+++ b/misc/cgo/test/issue18126.go
@@ -0,0 +1,26 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 18126: cgo check of void function returning errno.
+
+package cgotest
+
+/*
+#include <stdlib.h>
+
+void Issue18126C(void **p) {
+}
+*/
+import "C"
+
+import (
+ "testing"
+)
+
+func test18126(t *testing.T) {
+ p := C.malloc(1)
+ _, err := C.Issue18126C(&p)
+ C.free(p)
+ _ = err
+}
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index f6ddfbe..670a73f 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -713,15 +713,7 @@
List: params,
},
}
- var fbody ast.Stmt
- if name.FuncType.Result == nil {
- fbody = &ast.ExprStmt{
- X: fcall,
- }
- } else {
- fbody = &ast.ReturnStmt{
- Results: []ast.Expr{fcall},
- }
+ if name.FuncType.Result != nil {
rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
if rtype != name.FuncType.Result.Go {
needsUnsafe = true
@@ -734,6 +726,45 @@
},
}
}
+
+ // There is a Ref pointing to the old call.Call.Fun.
+ for _, ref := range f.Ref {
+ if ref.Expr == &call.Call.Fun {
+ ref.Expr = &fcall.Fun
+
+ // If this call expects two results, we have to
+ // adjust the results of the function we generated.
+ if ref.Context == "call2" {
+ 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"),
+ })
+ }
+ }
+ }
+
+ var fbody ast.Stmt
+ if ftype.Results == nil {
+ fbody = &ast.ExprStmt{
+ X: fcall,
+ }
+ } else {
+ fbody = &ast.ReturnStmt{
+ Results: []ast.Expr{fcall},
+ }
+ }
call.Call.Fun = &ast.FuncLit{
Type: ftype,
Body: &ast.BlockStmt{
@@ -743,22 +774,6 @@
call.Call.Lparen = token.NoPos
call.Call.Rparen = token.NoPos
- // There is a Ref pointing to the old call.Call.Fun.
- for _, ref := range f.Ref {
- if ref.Expr == &call.Call.Fun {
- ref.Expr = &fcall.Fun
-
- // If this call expects two results, we have to
- // adjust the results of the function we generated.
- if ref.Context == "call2" {
- ftype.Results.List = append(ftype.Results.List,
- &ast.Field{
- Type: ast.NewIdent("error"),
- })
- }
- }
- }
-
return needsUnsafe
}