mirror of
https://github.com/golang/go
synced 2024-11-26 09:48:14 -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 (
|
var (
|
||||||
initlist *NodeList
|
initlist []*Node
|
||||||
initplans map[*Node]*InitPlan
|
initplans map[*Node]*InitPlan
|
||||||
inittemps = make(map[*Node]*Node)
|
inittemps = make(map[*Node]*Node)
|
||||||
)
|
)
|
||||||
@ -47,15 +47,12 @@ func init1(n *Node, out **NodeList) {
|
|||||||
}
|
}
|
||||||
switch n.Class {
|
switch n.Class {
|
||||||
case PEXTERN, PFUNC:
|
case PEXTERN, PFUNC:
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if isblank(n) && n.Name.Curfn == nil && n.Name.Defn != nil && n.Name.Defn.Initorder == InitNotStarted {
|
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
|
// blank names initialization is part of init() but not
|
||||||
// when they are inside a function.
|
// when they are inside a function.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,90 +69,43 @@ func init1(n *Node, out **NodeList) {
|
|||||||
// Conversely, if there exists an initialization cycle involving
|
// Conversely, if there exists an initialization cycle involving
|
||||||
// a variable in the program, the tree walk will reach a cycle
|
// a variable in the program, the tree walk will reach a cycle
|
||||||
// involving that variable.
|
// involving that variable.
|
||||||
var nv *Node
|
|
||||||
if n.Class != PFUNC {
|
if n.Class != PFUNC {
|
||||||
nv = n
|
foundinitloop(n, n)
|
||||||
goto foundinitloop
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for l := initlist; l.N != n; l = l.Next {
|
for i := len(initlist) - 1; i >= 0; i-- {
|
||||||
if l.N.Class != PFUNC {
|
x := initlist[i]
|
||||||
nv = l.N
|
if x == n {
|
||||||
goto foundinitloop
|
break
|
||||||
|
}
|
||||||
|
if x.Class != PFUNC {
|
||||||
|
foundinitloop(n, x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The loop involves only functions, ok.
|
// The loop involves only functions, ok.
|
||||||
return
|
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.
|
// reached a new unvisited node.
|
||||||
n.Initorder = InitPending
|
n.Initorder = InitPending
|
||||||
|
initlist = append(initlist, n)
|
||||||
l := new(NodeList)
|
|
||||||
if l == nil {
|
|
||||||
Flusherrors()
|
|
||||||
Yyerror("out of memory")
|
|
||||||
errorexit()
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Next = initlist
|
|
||||||
l.N = n
|
|
||||||
l.End = nil
|
|
||||||
initlist = l
|
|
||||||
|
|
||||||
// make sure that everything n depends on is initialized.
|
// make sure that everything n depends on is initialized.
|
||||||
// n->defn is an assignment to n
|
// n->defn is an assignment to n
|
||||||
if defn := n.Name.Defn; defn != nil {
|
if defn := n.Name.Defn; defn != nil {
|
||||||
switch defn.Op {
|
switch defn.Op {
|
||||||
default:
|
default:
|
||||||
goto bad
|
Dump("defn", defn)
|
||||||
|
Fatalf("init1: bad defn")
|
||||||
|
|
||||||
case ODCLFUNC:
|
case ODCLFUNC:
|
||||||
init2list(defn.Nbody, out)
|
init2list(defn.Nbody, out)
|
||||||
|
|
||||||
case OAS:
|
case OAS:
|
||||||
if defn.Left != n {
|
if defn.Left != n {
|
||||||
goto bad
|
Dump("defn", defn)
|
||||||
|
Fatalf("init1: bad defn")
|
||||||
}
|
}
|
||||||
if isblank(defn.Left) && candiscard(defn.Right) {
|
if isblank(defn.Left) && candiscard(defn.Right) {
|
||||||
defn.Op = OEMPTY
|
defn.Op = OEMPTY
|
||||||
@ -190,18 +140,51 @@ func init1(n *Node, out **NodeList) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
l = initlist
|
last := len(initlist) - 1
|
||||||
initlist = l.Next
|
if initlist[last] != n {
|
||||||
if l.N != n {
|
Fatalf("bad initlist %v", initlist)
|
||||||
Fatalf("bad initlist")
|
|
||||||
}
|
}
|
||||||
|
initlist[last] = nil // allow GC
|
||||||
|
initlist = initlist[:last]
|
||||||
|
|
||||||
n.Initorder = InitDone
|
n.Initorder = InitDone
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
|
||||||
bad:
|
// foundinitloop prints an init loop error and exits.
|
||||||
Dump("defn", n.Name.Defn)
|
func foundinitloop(node, visited *Node) {
|
||||||
Fatalf("init1: bad defn")
|
// 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.
|
// 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