Skip to content

Commit 6663cca

Browse files
committed
cmd/cgo: explicitly use void for functions with no parameters
Currently, exported Go functions with no parameters generate C functions with an empty parameter list. In C, a function with an empty parameter list can accept any number of arguments, whereas a function with a single void parameter explicitly declares that it takes no arguments. To align the generated C functions with their Go prototypes, update the code generation to explicitly include a void parameter for functions with no parameters. Change-Id: I6d813815228efda95a7a6a9bbf9c9a787ff4f420
1 parent a9922d0 commit 6663cca

File tree

3 files changed

+76
-7
lines changed

3 files changed

+76
-7
lines changed

src/cmd/cgo/internal/testcshared/cshared_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -880,3 +880,52 @@ func TestIssue36233(t *testing.T) {
880880
t.Error("missing functions")
881881
}
882882
}
883+
884+
func TestIssue68411(t *testing.T) {
885+
globalSkip(t)
886+
testenv.MustHaveCGO(t)
887+
888+
t.Parallel()
889+
890+
// Test that the export header uses a void function parameter for
891+
// exported Go functions with no parameters.
892+
893+
tmpdir, err := os.MkdirTemp("", "cshared-TestIssue68411")
894+
if err != nil {
895+
t.Fatal(err)
896+
}
897+
defer os.RemoveAll(tmpdir)
898+
899+
const exportHeader = "issue68411.h"
900+
901+
run(t, nil, "go", "tool", "cgo", "-exportheader", exportHeader, "-objdir", tmpdir, "./issue68411/issue68411.go")
902+
data, err := os.ReadFile(exportHeader)
903+
if err != nil {
904+
t.Fatal(err)
905+
}
906+
907+
funcs := []struct{ name, signature string }{
908+
{"exportFuncWithNoParams", "extern void exportFuncWithNoParams(void)"},
909+
{"exportFuncWithParams", "extern void exportFuncWithParams(GoInt a, GoInt b)"},
910+
}
911+
912+
scanner := bufio.NewScanner(bytes.NewReader(data))
913+
var found int
914+
for scanner.Scan() {
915+
b := scanner.Bytes()
916+
for _, fn := range funcs {
917+
if bytes.Contains(b, []byte(fn.name)) {
918+
found++
919+
if !bytes.Contains(b, []byte(fn.signature)) {
920+
t.Errorf("function signature mismatch; got %q, want %q", b, fn.signature)
921+
}
922+
}
923+
}
924+
}
925+
if err = scanner.Err(); err != nil {
926+
t.Errorf("scanner encountered error: %v", err)
927+
}
928+
if found != len(funcs) {
929+
t.Error("missing functions")
930+
}
931+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import "C"
8+
9+
//export exportFuncWithNoParams
10+
func exportFuncWithNoParams() {}
11+
12+
//export exportFuncWithParams
13+
func exportFuncWithParams(a, b int) {}
14+
15+
func main() {}

src/cmd/cgo/out.go

+12-7
Original file line numberDiff line numberDiff line change
@@ -1012,13 +1012,18 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
10121012
s += p.cgoType(fn.Recv.List[0].Type).C.String()
10131013
s += " recv"
10141014
}
1015-
forFieldList(fntype.Params,
1016-
func(i int, aname string, atype ast.Expr) {
1017-
if i > 0 || fn.Recv != nil {
1018-
s += ", "
1019-
}
1020-
s += fmt.Sprintf("%s %s", p.cgoType(atype).C, exportParamName(aname, i))
1021-
})
1015+
1016+
if len(fntype.Params.List) > 0 {
1017+
forFieldList(fntype.Params,
1018+
func(i int, aname string, atype ast.Expr) {
1019+
if i > 0 || fn.Recv != nil {
1020+
s += ", "
1021+
}
1022+
s += fmt.Sprintf("%s %s", p.cgoType(atype).C, exportParamName(aname, i))
1023+
})
1024+
} else {
1025+
s += "void"
1026+
}
10221027
s += ")"
10231028

10241029
if len(exp.Doc) > 0 {

0 commit comments

Comments
 (0)