Skip to content

Commit ac78501

Browse files
committed
[dev.typeparams] cmd/compile: make sure closures inside generic funcs are not compiled
Closures inside generic functions were being added to the g.target.Decls list during noding, just like other closures. We remove generic functions/methods from g.target.Decls, so they don't get compiled (they're only available for export and stenciling). Most closures inside generic functions/methods were similarly being removed from g.target.Decls, because they have a generic parameter. But we need to ensure no closures in generic function/methods are left remaining in g.target.Decls, since we don't want them transformed and compiled. So, we set a flag in (*irgen) that records when we are noding a top-level generic function/method, and don't add any closures to g.target.Decls when the flag is true. Updates #47514 Change-Id: Id66b4c41d307ffa8f54cab6ce3646ade81606862 Reviewed-on: https://go-review.googlesource.com/c/go/+/340258 Trust: Dan Scales <danscales@google.com> Reviewed-by: Keith Randall <khr@golang.org>
1 parent f78d538 commit ac78501

File tree

4 files changed

+37
-1
lines changed

4 files changed

+37
-1
lines changed

src/cmd/compile/internal/noder/decl.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,11 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
102102
g.target.Inits = append(g.target.Inits, fn)
103103
}
104104

105+
if fn.Type().HasTParam() {
106+
g.topFuncIsGeneric = true
107+
}
105108
g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
109+
g.topFuncIsGeneric = false
106110
if fn.Type().HasTParam() && fn.Body != nil {
107111
// Set pointers to the dcls/body of a generic function/method in
108112
// the Inl struct, so it is marked for export, is available for

src/cmd/compile/internal/noder/expr.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,14 @@ func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node {
465465
cv.SetWalkdef(1)
466466
}
467467

468-
return ir.UseClosure(fn.OClosure, g.target)
468+
if g.topFuncIsGeneric {
469+
// Don't add any closure inside a generic function/method to the
470+
// g.target.Decls list, even though it may not be generic itself.
471+
// See issue #47514.
472+
return ir.UseClosure(fn.OClosure, nil)
473+
} else {
474+
return ir.UseClosure(fn.OClosure, g.target)
475+
}
469476
}
470477

471478
func (g *irgen) typeExpr(typ syntax.Expr) *types.Type {

src/cmd/compile/internal/noder/irgen.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ type irgen struct {
154154
// dictionary syms which we need to finish, by writing out any itabconv
155155
// entries.
156156
dictSymsToFinalize []*delayInfo
157+
158+
// True when we are compiling a top-level generic function or method. Use to
159+
// avoid adding closures of generic functions/methods to the target.Decls
160+
// list.
161+
topFuncIsGeneric bool
157162
}
158163

159164
type delayInfo struct {

test/typeparam/issue47514.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run -gcflags=-G=3
2+
3+
// Copyright 2021 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
// Test that closures inside a generic function are not exported,
8+
// even though not themselves generic.
9+
10+
package main
11+
12+
func Do[T any]() {
13+
_ = func() string {
14+
return ""
15+
}
16+
}
17+
18+
func main() {
19+
Do[int]()
20+
}

0 commit comments

Comments
 (0)