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 ( ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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
}
// 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: fmt.Printf("\t%v %v\n", visited.Line(), visited.Sym)
Dump("defn", n.Name.Defn) errorexit()
Fatalf("init1: bad defn")
} }
// recurse over n, doing init1 everywhere. // 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