1
0
mirror of https://github.com/golang/go synced 2024-11-26 11:38:01 -07:00

[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>
This commit is contained in:
Dan Scales 2021-08-05 23:26:21 -07:00
parent f78d538858
commit ac78501b9c
4 changed files with 37 additions and 1 deletions

View File

@ -102,7 +102,11 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
g.target.Inits = append(g.target.Inits, fn) g.target.Inits = append(g.target.Inits, fn)
} }
if fn.Type().HasTParam() {
g.topFuncIsGeneric = true
}
g.funcBody(fn, decl.Recv, decl.Type, decl.Body) g.funcBody(fn, decl.Recv, decl.Type, decl.Body)
g.topFuncIsGeneric = false
if fn.Type().HasTParam() && fn.Body != nil { if fn.Type().HasTParam() && fn.Body != nil {
// Set pointers to the dcls/body of a generic function/method in // Set pointers to the dcls/body of a generic function/method in
// the Inl struct, so it is marked for export, is available for // the Inl struct, so it is marked for export, is available for

View File

@ -465,8 +465,15 @@ func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node {
cv.SetWalkdef(1) cv.SetWalkdef(1)
} }
if g.topFuncIsGeneric {
// Don't add any closure inside a generic function/method to the
// g.target.Decls list, even though it may not be generic itself.
// See issue #47514.
return ir.UseClosure(fn.OClosure, nil)
} else {
return ir.UseClosure(fn.OClosure, g.target) return ir.UseClosure(fn.OClosure, g.target)
} }
}
func (g *irgen) typeExpr(typ syntax.Expr) *types.Type { func (g *irgen) typeExpr(typ syntax.Expr) *types.Type {
n := g.expr(typ) n := g.expr(typ)

View File

@ -154,6 +154,11 @@ type irgen struct {
// dictionary syms which we need to finish, by writing out any itabconv // dictionary syms which we need to finish, by writing out any itabconv
// entries. // entries.
dictSymsToFinalize []*delayInfo dictSymsToFinalize []*delayInfo
// True when we are compiling a top-level generic function or method. Use to
// avoid adding closures of generic functions/methods to the target.Decls
// list.
topFuncIsGeneric bool
} }
type delayInfo struct { type delayInfo struct {

View File

@ -0,0 +1,20 @@
// run -gcflags=-G=3
// Copyright 2021 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.
// Test that closures inside a generic function are not exported,
// even though not themselves generic.
package main
func Do[T any]() {
_ = func() string {
return ""
}
}
func main() {
Do[int]()
}