mirror of
https://github.com/golang/go
synced 2024-11-26 09:58:04 -07:00
cmd/compile: use []*Node instead of NodeList in sinit
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>
This commit is contained in:
parent
928fe05a4f
commit
703bd83623
@ -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
|
||||
}
|
||||
|
||||
bad:
|
||||
Dump("defn", n.Name.Defn)
|
||||
Fatalf("init1: bad defn")
|
||||
// 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)
|
||||
}
|
||||
|
||||
fmt.Printf("\t%v %v\n", visited.Line(), visited.Sym)
|
||||
errorexit()
|
||||
}
|
||||
|
||||
// recurse over n, doing init1 everywhere.
|
||||
|
17
test/initloop.go
Normal file
17
test/initloop.go
Normal file
@ -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
|
||||
)
|
Loading…
Reference in New Issue
Block a user