Skip to content

Commit 67a8169

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 67a8169

File tree

3 files changed

+68
-7
lines changed

3 files changed

+68
-7
lines changed

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

+41
Original file line numberDiff line numberDiff line change
@@ -880,3 +880,44 @@ 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 := t.TempDir()
894+
895+
const exportHeader = "issue68411.h"
896+
897+
run(t, nil, "go", "tool", "cgo", "-exportheader", exportHeader, "-objdir", tmpdir, "./issue68411/issue68411.go")
898+
data, err := os.ReadFile(exportHeader)
899+
if err != nil {
900+
t.Fatal(err)
901+
}
902+
903+
funcs := []struct{ name, signature string }{
904+
{"exportFuncWithNoParams", "void exportFuncWithNoParams(void)"},
905+
{"exportFuncWithParams", "exportFuncWithParams(GoInt a, GoInt b)"},
906+
}
907+
908+
var found int
909+
for _, line := range bytes.Split(data, []byte("\n")) {
910+
for _, fn := range funcs {
911+
if bytes.Contains(line, []byte(fn.name)) {
912+
found++
913+
if !bytes.Contains(line, []byte(fn.signature)) {
914+
t.Errorf("function signature mismatch; got %q, want %q", line, fn.signature)
915+
}
916+
}
917+
}
918+
}
919+
920+
if found != len(funcs) {
921+
t.Error("missing functions")
922+
}
923+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2024 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)