]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: use []*Node instead of NodeList in sinit
authorDave Cheney <dave@cheney.net>
Thu, 3 Sep 2015 07:07:00 +0000 (17:07 +1000)
committerDave Cheney <dave@cheney.net>
Sat, 5 Sep 2015 02:25:01 +0000 (02:25 +0000)
This is a first of a set of changes to make the transition away from NodeList
easier by removing cases in which NodeList doesn't act semi-trivially like a
[]*Node.

This CL was originally prepared by Josh Bleecher Snyder <josharian@gmail.com>.

This change passes go build -toolexec 'toolstash -cmp' -a std.

Change-Id: Iad10b75e42b5b24e1694407841282fa3bab2dc9f
Reviewed-on: https://go-review.googlesource.com/14232
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/cmd/compile/internal/gc/sinit.go
test/initloop.go [new file with mode: 0644]

index 27bcb0bdac4b3cee2d0421781bd6209b64127d86..74e8b55bf118b13d3dde14457be37b987450c07e 100644 (file)
@@ -19,7 +19,7 @@ const (
 )
 
 var (
-       initlist  *NodeList
+       initlist  []*Node
        initplans map[*Node]*InitPlan
        inittemps = make(map[*Node]*Node)
 )
@@ -47,15 +47,12 @@ func init1(n *Node, out **NodeList) {
        }
        switch n.Class {
        case PEXTERN, PFUNC:
-               break
-
        default:
                if isblank(n) && n.Name.Curfn == nil && n.Name.Defn != nil && n.Name.Defn.Initorder == InitNotStarted {
                        // blank names initialization is part of init() but not
                        // when they are inside a function.
                        break
                }
-
                return
        }
 
@@ -72,90 +69,43 @@ func init1(n *Node, out **NodeList) {
                // Conversely, if there exists an initialization cycle involving
                // a variable in the program, the tree walk will reach a cycle
                // involving that variable.
-               var nv *Node
                if n.Class != PFUNC {
-                       nv = n
-                       goto foundinitloop
+                       foundinitloop(n, n)
                }
 
-               for l := initlist; l.N != n; l = l.Next {
-                       if l.N.Class != PFUNC {
-                               nv = l.N
-                               goto foundinitloop
+               for i := len(initlist) - 1; i >= 0; i-- {
+                       x := initlist[i]
+                       if x == n {
+                               break
+                       }
+                       if x.Class != PFUNC {
+                               foundinitloop(n, x)
                        }
                }
 
                // The loop involves only functions, ok.
                return
-
-               // if there have already been errors printed,
-               // those errors probably confused us and
-               // there might not be a loop.  let the user
-               // fix those first.
-       foundinitloop:
-               Flusherrors()
-
-               if nerrors > 0 {
-                       errorexit()
-               }
-
-               // There is a loop involving nv. We know about
-               // n and initlist = n1 <- ... <- nv <- ... <- n <- ...
-               fmt.Printf("%v: initialization loop:\n", nv.Line())
-
-               // Build back pointers in initlist.
-               for l := initlist; l != nil; l = l.Next {
-                       if l.Next != nil {
-                               l.Next.End = l
-                       }
-               }
-
-               // Print nv -> ... -> n1 -> n.
-               var l *NodeList
-               for l = initlist; l.N != nv; l = l.Next {
-               }
-               for ; l != nil; l = l.End {
-                       fmt.Printf("\t%v %v refers to\n", l.N.Line(), l.N.Sym)
-               }
-
-               // Print n -> ... -> nv.
-               for l = initlist; l.N != n; l = l.Next {
-               }
-               for ; l.N != nv; l = l.End {
-                       fmt.Printf("\t%v %v refers to\n", l.N.Line(), l.N.Sym)
-               }
-               fmt.Printf("\t%v %v\n", nv.Line(), nv.Sym)
-               errorexit()
        }
 
        // reached a new unvisited node.
        n.Initorder = InitPending
-
-       l := new(NodeList)
-       if l == nil {
-               Flusherrors()
-               Yyerror("out of memory")
-               errorexit()
-       }
-
-       l.Next = initlist
-       l.N = n
-       l.End = nil
-       initlist = l
+       initlist = append(initlist, n)
 
        // make sure that everything n depends on is initialized.
        // n->defn is an assignment to n
        if defn := n.Name.Defn; defn != nil {
                switch defn.Op {
                default:
-                       goto bad
+                       Dump("defn", defn)
+                       Fatalf("init1: bad defn")
 
                case ODCLFUNC:
                        init2list(defn.Nbody, out)
 
                case OAS:
                        if defn.Left != n {
-                               goto bad
+                               Dump("defn", defn)
+                               Fatalf("init1: bad defn")
                        }
                        if isblank(defn.Left) && candiscard(defn.Right) {
                                defn.Op = OEMPTY
@@ -190,18 +140,51 @@ func init1(n *Node, out **NodeList) {
                }
        }
 
-       l = initlist
-       initlist = l.Next
-       if l.N != n {
-               Fatalf("bad initlist")
+       last := len(initlist) - 1
+       if initlist[last] != n {
+               Fatalf("bad initlist %v", initlist)
        }
+       initlist[last] = nil // allow GC
+       initlist = initlist[:last]
 
        n.Initorder = InitDone
        return
+}
+
+// foundinitloop prints an init loop error and exits.
+func foundinitloop(node, visited *Node) {
+       // If there have already been errors printed,
+       // those errors probably confused us and
+       // there might not be a loop. Let the user
+       // fix those first.
+       Flusherrors()
+       if nerrors > 0 {
+               errorexit()
+       }
+
+       // Find the index of node and visited in the initlist.
+       var nodeindex, visitedindex int
+       for ; initlist[nodeindex] != node; nodeindex++ {
+       }
+       for ; initlist[visitedindex] != visited; visitedindex++ {
+       }
+
+       // There is a loop involving visited. We know about node and
+       // initlist = n1 <- ... <- visited <- ... <- node <- ...
+       fmt.Printf("%v: initialization loop:\n", visited.Line())
+
+       // Print visited -> ... -> n1 -> node.
+       for _, n := range initlist[visitedindex:] {
+               fmt.Printf("\t%v %v refers to\n", n.Line(), n.Sym)
+       }
+
+       // Print node -> ... -> visited.
+       for _, n := range initlist[nodeindex:visitedindex] {
+               fmt.Printf("\t%v %v refers to\n", n.Line(), n.Sym)
+       }
 
-bad:
-       Dump("defn", n.Name.Defn)
-       Fatalf("init1: bad defn")
+       fmt.Printf("\t%v %v\n", visited.Line(), visited.Sym)
+       errorexit()
 }
 
 // recurse over n, doing init1 everywhere.
diff --git a/test/initloop.go b/test/initloop.go
new file mode 100644 (file)
index 0000000..d90395d
--- /dev/null
@@ -0,0 +1,17 @@
+// errorcheck
+
+// 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.
+
+// Verify that initialization loops are caught
+// and that the errors print correctly.
+
+package main
+
+var (
+       x int = a
+       a int = b // ERROR "a refers to\n.*b refers to\n.*c refers to\n.*a"
+       b int = c
+       c int = a
+)