Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/cmd/cgo/internal/test/issue44648.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2026 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 44648. The C wrapper for an exported Go function failed to
// compile if a parameter had the same name as a C type used by the
// function. No runtime test; just make sure it compiles.

package cgotest

/*
typedef int issue44648T;
typedef int (*issue44648F)(void *);
*/
import "C"

import "unsafe"

//export Issue44648A
func Issue44648A(issue44648F C.issue44648F, data unsafe.Pointer) C.int {
return 0
}

//export Issue44648B
func Issue44648B(issue44648T C.issue44648T) (C.issue44648T, C.issue44648T) {
return issue44648T, issue44648T
}

//export Issue44648C
func Issue44648C(r C.int) (a, b C.int) {
return r, r
}
50 changes: 30 additions & 20 deletions src/cmd/cgo/out.go
Original file line number Diff line number Diff line change
Expand Up @@ -1047,37 +1047,47 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}

// Build the wrapper function compiled by gcc.
var s strings.Builder
fmt.Fprintf(&s, "%s %s(", gccResult, exp.ExpName)
if fn.Recv != nil {
s.WriteString(p.cgoType(fn.Recv.List[0].Type).C.String())
s.WriteString(" recv")
}
// The declaration in the header uses the Go parameter
// names, but the definition uses generated names so
// that a parameter cannot shadow a C type or variable
// used in the body of the wrapper (issue 44648).
cdecl := func(paramName func(aname string, i int) string) string {
var s strings.Builder
fmt.Fprintf(&s, "%s %s(", gccResult, exp.ExpName)
if fn.Recv != nil {
s.WriteString(p.cgoType(fn.Recv.List[0].Type).C.String())
s.WriteString(" recv")
}

if len(fntype.Params.List) > 0 {
forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
s.WriteString(", ")
}
fmt.Fprintf(&s, "%s %s", p.cgoType(atype).C, exportParamName(aname, i))
})
} else {
s.WriteString("void")
if len(fntype.Params.List) > 0 {
forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) {
if i > 0 || fn.Recv != nil {
s.WriteString(", ")
}
fmt.Fprintf(&s, "%s %s", p.cgoType(atype).C, paramName(aname, i))
})
} else {
s.WriteString("void")
}
s.WriteByte(')')
return s.String()
}
genParamName := func(aname string, i int) string {
return fmt.Sprintf("p%d", i)
}
s.WriteByte(')')

if len(exp.Doc) > 0 {
fmt.Fprintf(fgcch, "\n%s", exp.Doc)
if !strings.HasSuffix(exp.Doc, "\n") {
fmt.Fprint(fgcch, "\n")
}
}
fmt.Fprintf(fgcch, "extern %s;\n", s.String())
fmt.Fprintf(fgcch, "extern %s;\n", cdecl(exportParamName))

fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
fmt.Fprintf(fgcc, "\n%s\n", s.String())
fmt.Fprintf(fgcc, "\n%s\n", cdecl(genParamName))
fmt.Fprintf(fgcc, "{\n")
fmt.Fprintf(fgcc, "\tsize_t _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
// The results part of the argument structure must be
Expand All @@ -1104,7 +1114,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
}
forFieldList(fntype.Params,
func(i int, aname string, atype ast.Expr) {
fmt.Fprintf(fgcc, "\t_cgo_a.p%d = %s;\n", i, exportParamName(aname, i))
fmt.Fprintf(fgcc, "\t_cgo_a.p%d = p%d;\n", i, i)
})
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &_cgo_a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
Expand Down
Loading