)
var (
- initlist *NodeList
+ initlist []*Node
initplans map[*Node]*InitPlan
inittemps = make(map[*Node]*Node)
)
}
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
}
// 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
}
}
- 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.