]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix inlining of labeled for loops
authorDan Scales <danscales@google.com>
Wed, 20 Oct 2021 20:56:15 +0000 (13:56 -0700)
committerDan Scales <danscales@google.com>
Thu, 21 Oct 2021 19:08:43 +0000 (19:08 +0000)
There is already a mechanism using inlgen to rename labels insided
inlined functions so that they are unique and don't clash with loops in
the outer function. This is used for OLABEL and OGOTO. Now that we are
doing inlining of OFOR loops, we need to do this translation for OBREAK,
OCONTINUE, and OFOR. I also added the translation for ORANGE loops, in
anticipation of a CL that will allow inlining of ORANGE for loops.

Fixes #49100

Change-Id: I2ccddc3350370825c386965f4a1e4bc54d3c369b
Reviewed-on: https://go-review.googlesource.com/c/go/+/357649
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Trust: Dan Scales <danscales@google.com>

src/cmd/compile/internal/inline/inl.go
test/fixedbugs/issue49100.go [new file with mode: 0644]
test/fixedbugs/issue49100.out [new file with mode: 0644]

index a2268a5465e020835124e6ae6401874debdd69dc..fb6cf53155be572c58597a7ef03cd4d9ddfbc34b 100644 (file)
@@ -1223,7 +1223,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                        // Don't do special substitutions if inside a closure
                        break
                }
-               // Since we don't handle bodies with closures,
+               // Because of the above test for subst.newclofn,
                // this return is guaranteed to belong to the current inlined function.
                n := n.(*ir.ReturnStmt)
                init := subst.list(n.Init())
@@ -1251,7 +1251,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                typecheck.Stmts(init)
                return ir.NewBlockStmt(base.Pos, init)
 
-       case ir.OGOTO:
+       case ir.OGOTO, ir.OBREAK, ir.OCONTINUE:
                if subst.newclofn != nil {
                        // Don't do special substitutions if inside a closure
                        break
@@ -1260,8 +1260,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                m := ir.Copy(n).(*ir.BranchStmt)
                m.SetPos(subst.updatedPos(m.Pos()))
                *m.PtrInit() = nil
-               p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
-               m.Label = typecheck.Lookup(p)
+               m.Label = translateLabel(n.Label)
                return m
 
        case ir.OLABEL:
@@ -1273,8 +1272,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
                m := ir.Copy(n).(*ir.LabelStmt)
                m.SetPos(subst.updatedPos(m.Pos()))
                *m.PtrInit() = nil
-               p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
-               m.Label = typecheck.Lookup(p)
+               m.Label = translateLabel(n.Label)
                return m
 
        case ir.OCLOSURE:
@@ -1286,6 +1284,21 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
        m.SetPos(subst.updatedPos(m.Pos()))
        ir.EditChildren(m, subst.edit)
 
+       if subst.newclofn == nil {
+               // Translate any label on FOR or RANGE loops
+               if m.Op() == ir.OFOR {
+                       m := m.(*ir.ForStmt)
+                       m.Label = translateLabel(m.Label)
+                       return m
+               }
+
+               if m.Op() == ir.ORANGE {
+                       m := m.(*ir.RangeStmt)
+                       m.Label = translateLabel(m.Label)
+                       return m
+               }
+       }
+
        switch m := m.(type) {
        case *ir.AssignStmt:
                if lhs, ok := m.X.(*ir.Name); ok && lhs.Defn == &subst.defnMarker {
@@ -1302,6 +1315,16 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
        return m
 }
 
+// translateLabel makes a label from an inlined function (if non-nil) be unique by
+// adding "·inlgen".
+func translateLabel(l *types.Sym) *types.Sym {
+       if l == nil {
+               return nil
+       }
+       p := fmt.Sprintf("%s·%d", l.Name, inlgen)
+       return typecheck.Lookup(p)
+}
+
 func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
        if subst.noPosUpdate {
                return xpos
diff --git a/test/fixedbugs/issue49100.go b/test/fixedbugs/issue49100.go
new file mode 100644 (file)
index 0000000..3a2e972
--- /dev/null
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2015 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
+
+func f(j int) {
+loop:
+       for i := 0; i < 4; i++ {
+               if i == 1 {
+                       continue loop
+               }
+               println(j, i)
+       }
+}
+
+func main() {
+loop:
+       for j := 0; j < 5; j++ {
+               f(j)
+               if j == 3 {
+                       break loop
+               }
+       }
+}
diff --git a/test/fixedbugs/issue49100.out b/test/fixedbugs/issue49100.out
new file mode 100644 (file)
index 0000000..326d413
--- /dev/null
@@ -0,0 +1,12 @@
+0 0
+0 2
+0 3
+1 0
+1 2
+1 3
+2 0
+2 2
+2 3
+3 0
+3 2
+3 3