Skip to content

Commit 2ad53d5

Browse files
griesemergopherbot
authored andcommitted
go/types, types2: disallow new methods on (aliases to) cgo-generated types
This makes methods on aliases of cgo-generated types a new compiler error. That is ok because cgo-behavior is not covered by the G1 compatibility guarantee. Background: In 2023 we fixed a gopls issue related to this by actually enabling methods on cgo-generated types in the first place (#59944). See the discussion in #60725 and this CL for why we believe it is ok to make this an error now. Based on a variation of CL 503596 (by Xie Cui). Fixes #60725. For #59944. Change-Id: I7e9e6e1a76447167483a282b268f5183214027c9 Reviewed-on: https://go-review.googlesource.com/c/go/+/629715 Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 91af711 commit 2ad53d5

File tree

5 files changed

+50
-6
lines changed

5 files changed

+50
-6
lines changed

src/cmd/compile/internal/types2/issues_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,8 @@ func TestIssue59944(t *testing.T) {
839839
testenv.MustHaveCGO(t)
840840

841841
// The typechecker should resolve methods declared on aliases of cgo types.
842-
const src = `
842+
const src = `// -gotypesalias=1
843+
843844
package p
844845
845846
/*
@@ -851,7 +852,7 @@ import "C"
851852
852853
type Layout = C.struct_layout
853854
854-
func (l *Layout) Binding() {}
855+
func (l /* ERROR "cannot define new methods on non-local type Layout" */ *Layout) Binding() {}
855856
856857
func _() {
857858
_ = (*Layout).Binding

src/cmd/compile/internal/types2/signature.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"cmd/compile/internal/syntax"
99
"fmt"
1010
. "internal/types/errors"
11+
"path/filepath"
12+
"strings"
1113
)
1214

1315
// ----------------------------------------------------------------------------
@@ -410,7 +412,7 @@ func (check *Checker) validRecv(recv *Var) {
410412
// as the method."
411413
switch T := atyp.(type) {
412414
case *Named:
413-
if T.obj.pkg != check.pkg {
415+
if T.obj.pkg != check.pkg || isCGoTypeObj(T.obj) {
414416
check.errorf(recv, InvalidRecv, "cannot define new methods on non-local type %s", rtyp)
415417
break
416418
}
@@ -437,3 +439,9 @@ func (check *Checker) validRecv(recv *Var) {
437439
check.errorf(recv, InvalidRecv, "invalid receiver type %s", recv.typ)
438440
}
439441
}
442+
443+
// isCGoTypeObj reports whether the given type name was created by cgo.
444+
func isCGoTypeObj(obj *TypeName) bool {
445+
return strings.HasPrefix(obj.name, "_Ctype_") ||
446+
strings.HasPrefix(filepath.Base(obj.pos.FileBase().Filename()), "_cgo_")
447+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[short] skip
2+
[!cgo] skip
3+
4+
# Test that cgo rejects attempts to declare methods
5+
# on the types A or *A; see issue #60725.
6+
7+
! go build ./a
8+
stderr 'cannot define new methods on non-local type A'
9+
stderr 'cannot define new methods on non-local type A'
10+
11+
-- go.mod --
12+
module example.com
13+
go 1.24
14+
15+
-- a/a.go --
16+
package a
17+
18+
/*
19+
typedef int T;
20+
*/
21+
import "C"
22+
23+
type A = C.T
24+
25+
func (A) m1() {}
26+
func (*A) m2() {}

src/go/types/issues_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,8 @@ func TestIssue59944(t *testing.T) {
848848
testenv.MustHaveCGO(t)
849849

850850
// The typechecker should resolve methods declared on aliases of cgo types.
851-
const src = `
851+
const src = `// -gotypesalias=1
852+
852853
package p
853854
854855
/*
@@ -860,7 +861,7 @@ import "C"
860861
861862
type Layout = C.struct_layout
862863
863-
func (l *Layout) Binding() {}
864+
func (l /* ERROR "cannot define new methods on non-local type Layout" */ *Layout) Binding() {}
864865
865866
func _() {
866867
_ = (*Layout).Binding

src/go/types/signature.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"go/ast"
1010
"go/token"
1111
. "internal/types/errors"
12+
"path/filepath"
13+
"strings"
1214
)
1315

1416
// ----------------------------------------------------------------------------
@@ -430,7 +432,7 @@ func (check *Checker) validRecv(recv *Var) {
430432
// as the method."
431433
switch T := atyp.(type) {
432434
case *Named:
433-
if T.obj.pkg != check.pkg {
435+
if T.obj.pkg != check.pkg || isCGoTypeObj(check.fset, T.obj) {
434436
check.errorf(recv, InvalidRecv, "cannot define new methods on non-local type %s", rtyp)
435437
break
436438
}
@@ -457,3 +459,9 @@ func (check *Checker) validRecv(recv *Var) {
457459
check.errorf(recv, InvalidRecv, "invalid receiver type %s", recv.typ)
458460
}
459461
}
462+
463+
// isCGoTypeObj reports whether the given type name was created by cgo.
464+
func isCGoTypeObj(fset *token.FileSet, obj *TypeName) bool {
465+
return strings.HasPrefix(obj.name, "_Ctype_") ||
466+
strings.HasPrefix(filepath.Base(fset.File(obj.pos).Name()), "_cgo_")
467+
}

0 commit comments

Comments
 (0)