From a593ca9d657efb1ea021c9fc51cb528c398bbf4e Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 24 Nov 2025 08:14:18 +0000 Subject: [PATCH] runtime/cgo: add support for `any` param and return type When using `any` as param or return type of an exported function, we currently have the error `unrecognized Go type any`. `any` is an alias of `interface{}` which is already supported. This would avoid such change: https://github.com/php/frankenphp/pull/1976 Fixes #76340 Change-Id: I301838ff72e99ae78b035a8eff2405f6a145ed1a GitHub-Last-Rev: 7dfbccfa582bbc6e79ed29677391b9ae81a9b5bd GitHub-Pull-Request: golang/go#76325 Reviewed-on: https://go-review.googlesource.com/c/go/+/720960 Reviewed-by: Mark Freeman Auto-Submit: Ian Lance Taylor Reviewed-by: Keith Randall Reviewed-by: Ian Lance Taylor Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/cmd/cgo/gcc.go | 3 +++ src/cmd/cgo/internal/test/cgo_test.go | 1 + src/cmd/cgo/internal/test/test.go | 31 +++++++++++++++++++++++++++ src/cmd/cgo/internal/test/testx.go | 18 ++++++++++++++++ src/cmd/cgo/out.go | 3 +++ src/runtime/cgocall.go | 3 +++ 6 files changed, 59 insertions(+) diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index d3de3906b4..300ccae350 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -1121,6 +1121,9 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool { if t.Name == "error" { return true } + if t.Name == "any" { + return true + } if goTypes[t.Name] != nil { return false } diff --git a/src/cmd/cgo/internal/test/cgo_test.go b/src/cmd/cgo/internal/test/cgo_test.go index 5393552e07..04e06cf95e 100644 --- a/src/cmd/cgo/internal/test/cgo_test.go +++ b/src/cmd/cgo/internal/test/cgo_test.go @@ -106,6 +106,7 @@ func TestSetEnv(t *testing.T) { testSetEnv(t) } func TestThreadLock(t *testing.T) { testThreadLockFunc(t) } func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) } func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) } +func Test76340(t *testing.T) { test76340(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } func BenchmarkGoString(b *testing.B) { benchGoString(b) } diff --git a/src/cmd/cgo/internal/test/test.go b/src/cmd/cgo/internal/test/test.go index e83e367174..4dd14facb5 100644 --- a/src/cmd/cgo/internal/test/test.go +++ b/src/cmd/cgo/internal/test/test.go @@ -959,6 +959,18 @@ char * const issue75751p = &issue75751v; #define issue75751m issue75751p char * const volatile issue75751p2 = &issue75751v; #define issue75751m2 issue75751p2 + +typedef struct { void *t; void *v; } GoInterface; +extern int exportAny76340Param(GoInterface); +extern GoInterface exportAny76340Return(int); + +int issue76340testFromC(GoInterface obj) { + return exportAny76340Param(obj); +} + +GoInterface issue76340returnFromC(int val) { + return exportAny76340Return(val); +} */ import "C" @@ -2407,3 +2419,22 @@ func test69086(t *testing.T) { func test75751() int { return int(*C.issue75751m) + int(*C.issue75751m2) } + +// Issue 76340. +func test76340(t *testing.T) { + var emptyInterface C.GoInterface + r1 := C.issue76340testFromC(emptyInterface) + if r1 != 0 { + t.Errorf("issue76340testFromC with nil interface: got %d, want 0", r1) + } + + r2 := C.issue76340returnFromC(42) + if r2.t == nil && r2.v == nil { + t.Error("issue76340returnFromC(42) returned nil interface") + } + + r3 := C.issue76340returnFromC(0) + if r3.t != nil || r3.v != nil { + t.Errorf("issue76340returnFromC(0) returned non-nil interface: got %v, want nil", r3) + } +} diff --git a/src/cmd/cgo/internal/test/testx.go b/src/cmd/cgo/internal/test/testx.go index 9a63b9e100..21ba52260e 100644 --- a/src/cmd/cgo/internal/test/testx.go +++ b/src/cmd/cgo/internal/test/testx.go @@ -595,3 +595,21 @@ func test49633(t *testing.T) { t.Errorf("msg = %q, want 'hello'", v.msg) } } + +//export exportAny76340Param +func exportAny76340Param(obj any) C.int { + if obj == nil { + return 0 + } + + return 1 +} + +//export exportAny76340Return +func exportAny76340Return(val C.int) any { + if val == 0 { + return nil + } + + return int(val) +} diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 00c9e8c9a3..dc1e5b29e5 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -1558,6 +1558,9 @@ func (p *Package) doCgoType(e ast.Expr, m map[ast.Expr]bool) *Type { if t.Name == "error" { return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")} } + if t.Name == "any" { + return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")} + } if r, ok := goTypes[t.Name]; ok { return goTypesFixup(r) } diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go index f01353ffa6..55e7bdbdb5 100644 --- a/src/runtime/cgocall.go +++ b/src/runtime/cgocall.go @@ -796,6 +796,9 @@ func cgoCheckResult(val any) { ep := efaceOf(&val) t := ep._type + if t == nil { + return + } cgoCheckArg(t, ep.data, !t.IsDirectIface(), false, cgoResultFail) } -- 2.52.0