Commit 703bd836 authored by Dave Cheney's avatar Dave Cheney

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: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 928fe05a
......@@ -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.
......
// 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
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment