Skip to content

Commit 896de17

Browse files
mauri870gopherbot
authored andcommitted
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. Fixes #68411 Change-Id: Iab9456aa0236200bf21d1181a2e18e82869df63f GitHub-Last-Rev: 6ff21a9 GitHub-Pull-Request: #70981 Reviewed-on: https://go-review.googlesource.com/c/go/+/638635 Reviewed-by: Michael Knyszek <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent a73c654 commit 896de17

File tree

3 files changed

+68
-7
lines changed

3 files changed

+68
-7
lines changed

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

Lines changed: 41 additions & 0 deletions
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.Lines(data) {
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+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2025 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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,13 +1015,18 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
10151015
s.WriteString(p.cgoType(fn.Recv.List[0].Type).C.String())
10161016
s.WriteString(" recv")
10171017
}
1018-
forFieldList(fntype.Params,
1019-
func(i int, aname string, atype ast.Expr) {
1020-
if i > 0 || fn.Recv != nil {
1021-
s.WriteString(", ")
1022-
}
1023-
fmt.Fprintf(&s, "%s %s", p.cgoType(atype).C, exportParamName(aname, i))
1024-
})
1018+
1019+
if len(fntype.Params.List) > 0 {
1020+
forFieldList(fntype.Params,
1021+
func(i int, aname string, atype ast.Expr) {
1022+
if i > 0 || fn.Recv != nil {
1023+
s.WriteString(", ")
1024+
}
1025+
fmt.Fprintf(&s, "%s %s", p.cgoType(atype).C, exportParamName(aname, i))
1026+
})
1027+
} else {
1028+
s.WriteString("void")
1029+
}
10251030
s.WriteByte(')')
10261031

10271032
if len(exp.Doc) > 0 {

0 commit comments

Comments
 (0)