]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: make sure closures inside generic funcs are not compiled
authorDan Scales <danscales@google.com>
Fri, 6 Aug 2021 06:26:21 +0000 (23:26 -0700)
committerDan Scales <danscales@google.com>
Fri, 6 Aug 2021 18:50:46 +0000 (18:50 +0000)
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>
src/cmd/compile/internal/noder/decl.go
src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/irgen.go
test/typeparam/issue47514.go [new file with mode: 0644]

index 2416d1a49e26f1596a0f4669d7856ad1337269e6..429c8a14c8ad1f1b436ac25742e671ab215b46f3 100644 (file)
@@ -102,7 +102,11 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) {
                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.topFuncIsGeneric = false
        if fn.Type().HasTParam() && fn.Body != nil {
                // Set pointers to the dcls/body of a generic function/method in
                // the Inl struct, so it is marked for export, is available for
index a0d3cad699476a2267b985c7373f1b5e8f5f01c7..6e2b1a839bee6c4162c9815d3e732c04658e37b7 100644 (file)
@@ -465,7 +465,14 @@ func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node {
                cv.SetWalkdef(1)
        }
 
-       return ir.UseClosure(fn.OClosure, g.target)
+       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)
+       }
 }
 
 func (g *irgen) typeExpr(typ syntax.Expr) *types.Type {
index 6a8763c908847548c2e5ea588a40dfe9d3fd562a..571e294416a4ddf6cb23537db010512b147b03a9 100644 (file)
@@ -154,6 +154,11 @@ type irgen struct {
        // dictionary syms which we need to finish, by writing out any itabconv
        // entries.
        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 {
diff --git a/test/typeparam/issue47514.go b/test/typeparam/issue47514.go
new file mode 100644 (file)
index 0000000..947f254
--- /dev/null
@@ -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]()
+}