]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: ensure dictionary assignment statements are defining statements
authorKeith Randall <khr@golang.org>
Fri, 25 Feb 2022 23:10:24 +0000 (15:10 -0800)
committerKeith Randall <khr@golang.org>
Sat, 26 Feb 2022 01:16:03 +0000 (01:16 +0000)
The problem in 51355 is that escape analysis decided that the
dictionary variable was captured by reference instead of by value. We
want dictionaries to always be captured by value.

Escape analysis was confused because it saw what it thought was a
reassignment of the dictionary variable. In fact, it was the only
assignment, it just wasn't marked as the defining assignment. Fix
that.

Add an assert to make sure this stays true.

Fixes #51355

Change-Id: Ifd9342455fa107b113f5ff521a94cdbf1b8a7733
Reviewed-on: https://go-review.googlesource.com/c/go/+/388115
Trust: Keith Randall <khr@golang.org>
Run-TryBot: Keith Randall <khr@golang.org>
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Dan Scales <danscales@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/escape/escape.go
src/cmd/compile/internal/noder/stencil.go
test/typeparam/issue51355.go [new file with mode: 0644]

index c2145bdf91ec5457d6747db57e8e015e613bf698..bc6f7c93bb663be0c7d3131a3a1a1c7e83244de7 100644 (file)
@@ -10,6 +10,7 @@ import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/logopt"
+       "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
 )
 
@@ -243,6 +244,9 @@ func (b *batch) flowClosure(k hole, clo *ir.ClosureExpr) {
                n.SetByval(!loc.addrtaken && !loc.reassigned && n.Type().Size() <= 128)
                if !n.Byval() {
                        n.SetAddrtaken(true)
+                       if n.Sym().Name == typecheck.LocalDictName {
+                               base.FatalfAt(n.Pos(), "dictionary variable not captured by value")
+                       }
                }
 
                if base.Flag.LowerM > 1 {
index 03937094e1d2b475acf69d333b38834f6c1e2e89..807794dc3007bf562b0042343e7c6644eea22c53 100644 (file)
@@ -410,7 +410,8 @@ func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
        fn, formalParams, formalResults := startClosure(pos, outer, typ)
 
        // This is the dictionary we want to use.
-       // It may be a constant, or it may be a dictionary acquired from the outer function's dictionary.
+       // It may be a constant, it may be the outer functions's dictionary, or it may be
+       // a subdictionary acquired from the outer function's dictionary.
        // For the latter, dictVar is a variable in the outer function's scope, set to the subdictionary
        // read from the outer function's dictionary.
        var dictVar *ir.Name
@@ -1145,6 +1146,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
                        newfn.Dcl = append(newfn.Dcl, ldict)
                        as := ir.NewAssignStmt(x.Pos(), ldict, cdict)
                        as.SetTypecheck(1)
+                       ldict.Defn = as
                        newfn.Body.Append(as)
 
                        // Create inst info for the instantiated closure. The dict
diff --git a/test/typeparam/issue51355.go b/test/typeparam/issue51355.go
new file mode 100644 (file)
index 0000000..15ffa4b
--- /dev/null
@@ -0,0 +1,31 @@
+// compile -G=3
+
+// Copyright 2022 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.
+
+package main
+
+type Cache[E comparable] struct {
+       adder func(...E)
+}
+
+func New[E comparable]() *Cache[E] {
+       c := &Cache[E]{}
+
+       c.adder = func(elements ...E) {
+               for _, value := range elements {
+                       value := value
+                       go func() {
+                               println(value)
+                       }()
+               }
+       }
+
+       return c
+}
+
+func main() {
+       c := New[string]()
+       c.adder("test")
+}