Commit fd44d872 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: factor out dcl stack ops into package types

Change-Id: I000bb530e00d0f0bc59e0f1366b5fb586adf4f37
Reviewed-on: https://go-review.googlesource.com/39912
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 3cf1ce40
......@@ -191,7 +191,7 @@ func genhash(sym *types.Sym, t *types.Type) {
lineno = autogeneratedPos // less confusing than end of input
dclcontext = PEXTERN
markdcl()
types.Markdcl(lineno)
// func sym(p *T, h uintptr) uintptr
fn := nod(ODCLFUNC, nil, nil)
......@@ -305,7 +305,7 @@ func genhash(sym *types.Sym, t *types.Type) {
fn = typecheck(fn, Etop)
typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil
popdcl()
types.Popdcl()
if debug_dclstack != 0 {
testdclstack()
}
......@@ -369,7 +369,7 @@ func geneq(sym *types.Sym, t *types.Type) {
lineno = autogeneratedPos // less confusing than end of input
dclcontext = PEXTERN
markdcl()
types.Markdcl(lineno)
// func sym(p, q *T) bool
fn := nod(ODCLFUNC, nil, nil)
......@@ -497,7 +497,7 @@ func geneq(sym *types.Sym, t *types.Type) {
fn = typecheck(fn, Etop)
typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil
popdcl()
types.Popdcl()
if debug_dclstack != 0 {
testdclstack()
}
......
......@@ -1091,54 +1091,54 @@ func (p *importer) node() *Node {
return nodl(p.pos(), op, p.expr(), nil)
case OIF:
markdcl()
types.Markdcl(lineno)
n := nodl(p.pos(), OIF, nil, nil)
n.Ninit.Set(p.stmtList())
n.Left = p.expr()
n.Nbody.Set(p.stmtList())
n.Rlist.Set(p.stmtList())
popdcl()
types.Popdcl()
return n
case OFOR:
markdcl()
types.Markdcl(lineno)
n := nodl(p.pos(), OFOR, nil, nil)
n.Ninit.Set(p.stmtList())
n.Left, n.Right = p.exprsOrNil()
n.Nbody.Set(p.stmtList())
popdcl()
types.Popdcl()
return n
case ORANGE:
markdcl()
types.Markdcl(lineno)
n := nodl(p.pos(), ORANGE, nil, nil)
n.List.Set(p.stmtList())
n.Right = p.expr()
n.Nbody.Set(p.stmtList())
popdcl()
types.Popdcl()
return n
case OSELECT, OSWITCH:
markdcl()
types.Markdcl(lineno)
n := nodl(p.pos(), op, nil, nil)
n.Ninit.Set(p.stmtList())
n.Left, _ = p.exprsOrNil()
n.List.Set(p.stmtList())
popdcl()
types.Popdcl()
return n
// case OCASE, OXCASE:
// unreachable - mapped to OXCASE case below by exporter
case OXCASE:
markdcl()
types.Markdcl(lineno)
n := nodl(p.pos(), OXCASE, nil, nil)
n.Xoffset = int64(block)
n.Xoffset = int64(types.Block)
n.List.Set(p.exprList())
// TODO(gri) eventually we must declare variables for type switch
// statements (type switch statements are not yet exported)
n.Nbody.Set(p.stmtList())
popdcl()
types.Popdcl()
return n
// case OFALL:
......@@ -1146,7 +1146,7 @@ func (p *importer) node() *Node {
case OXFALL:
n := nodl(p.pos(), OXFALL, nil, nil)
n.Xoffset = int64(block)
n.Xoffset = int64(types.Block)
return n
case OBREAK, OCONTINUE:
......@@ -1162,7 +1162,7 @@ func (p *importer) node() *Node {
case OGOTO, OLABEL:
n := nodl(p.pos(), op, newname(p.expr().Sym), nil)
n.Sym = dclstack // context, for goto restrictions
n.Sym = types.Dclstack // context, for goto restrictions
return n
case OEND:
......
......@@ -15,99 +15,12 @@ import (
var externdcl []*Node
var blockgen int32 // max block number
var block int32 // current block number
// dclstack maintains a stack of shadowed symbol declarations so that
// popdcl can restore their declarations when a block scope ends.
// The stack is maintained as a linked list, using Sym's Link field.
//
// In practice, the "stack" actually ends up forming a tree: goto and label
// statements record the current state of dclstack so that checkgoto can
// validate that a goto statement does not jump over any declarations or
// into a new block scope.
//
// Finally, the Syms in this list are not "real" Syms as they don't actually
// represent object names. Sym is just a convenient type for saving shadowed
// Sym definitions, and only a subset of its fields are actually used.
var dclstack *types.Sym
func dcopy(a, b *types.Sym) {
a.Pkg = b.Pkg
a.Name = b.Name
a.Def = b.Def
a.Block = b.Block
a.Lastlineno = b.Lastlineno
}
func push() *types.Sym {
d := new(types.Sym)
d.Lastlineno = lineno
d.Link = dclstack
dclstack = d
return d
}
// pushdcl pushes the current declaration for symbol s (if any) so that
// it can be shadowed by a new declaration within a nested block scope.
func pushdcl(s *types.Sym) *types.Sym {
d := push()
dcopy(d, s)
return d
}
// popdcl pops the innermost block scope and restores all symbol declarations
// to their previous state.
func popdcl() {
d := dclstack
for ; d != nil && d.Name != ""; d = d.Link {
s := d.Pkg.Lookup(d.Name)
lno := s.Lastlineno
dcopy(s, d)
d.Lastlineno = lno
}
if d == nil {
Fatalf("popdcl: no mark")
}
dclstack = d.Link // pop mark
block = d.Block
}
// markdcl records the start of a new block scope for declarations.
func markdcl() {
d := push()
d.Name = "" // used as a mark in fifo
d.Block = block
blockgen++
block = blockgen
}
// keep around for debugging
func dumpdclstack() {
i := 0
for d := dclstack; d != nil; d = d.Link {
fmt.Printf("%6d %p", i, d)
if d.Name != "" {
fmt.Printf(" '%s' %v\n", d.Name, d.Pkg.Lookup(d.Name))
} else {
fmt.Printf(" ---\n")
}
i++
}
}
func testdclstack() {
for d := dclstack; d != nil; d = d.Link {
if d.Name == "" {
if nerrors != 0 {
errorexit()
}
Fatalf("mark left on the stack")
if !types.IsDclstackValid() {
if nerrors != 0 {
errorexit()
}
Fatalf("mark left on the dclstack")
}
}
......@@ -191,7 +104,7 @@ func declare(n *Node, ctxt Class) {
vargen++
gen = vargen
}
pushdcl(s)
types.Pushdcl(s, lineno)
n.Name.Curfn = Curfn
}
......@@ -199,7 +112,7 @@ func declare(n *Node, ctxt Class) {
n.Xoffset = 0
}
if s.Block == block {
if s.Block == types.Block {
// functype will print errors about duplicate function arguments.
// Don't repeat the error here.
if ctxt != PPARAM && ctxt != PPARAMOUT {
......@@ -207,7 +120,7 @@ func declare(n *Node, ctxt Class) {
}
}
s.Block = block
s.Block = types.Block
s.Lastlineno = lineno
s.Def = asTypesNode(n)
n.Name.Vargen = int32(gen)
......@@ -418,7 +331,7 @@ func colasdefn(left []*Node, defn *Node) {
}
n.Sym.SetUniq(false)
if n.Sym.Block == block {
if n.Sym.Block == types.Block {
continue
}
......@@ -597,7 +510,7 @@ var funcdepth int32 // len(funcstack) during parsing, but then forced to be th
// start the function.
// called before funcargs; undone at end of funcbody.
func funcstart(n *Node) {
markdcl()
types.Markdcl(lineno)
funcstack = append(funcstack, Curfn)
funcdepth++
Curfn = n
......@@ -611,7 +524,7 @@ func funcbody(n *Node) {
if dclcontext != PAUTO {
Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
}
popdcl()
types.Popdcl()
funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
funcdepth--
if funcdepth == 0 {
......
......@@ -381,7 +381,6 @@ func Main(archInit func(*Arch)) {
initUniverse()
blockgen = 1
dclcontext = PEXTERN
nerrors = 0
......@@ -756,7 +755,7 @@ func findpkg(name string) (file string, ok bool) {
// so that the compiler can generate calls to them,
// but does not make them visible to user code.
func loadsys() {
block = 1
types.Block = 1
inimport = true
typecheckok = true
......
......@@ -85,7 +85,7 @@ type linkname struct {
}
func (p *noder) node() {
block = 1
types.Block = 1
imported_unsafe = false
p.lineno(p.file.PkgName)
......@@ -726,10 +726,10 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
n.Left = p.newname(stmt.Label)
}
if op == OGOTO {
n.Sym = dclstack // context, for goto restriction
n.Sym = types.Dclstack // context, for goto restriction
}
if op == OXFALL {
n.Xoffset = int64(block)
n.Xoffset = int64(types.Block)
}
return n
case *syntax.CallStmt:
......@@ -777,14 +777,14 @@ func (p *noder) stmt(stmt syntax.Stmt) *Node {
}
func (p *noder) blockStmt(stmt *syntax.BlockStmt) []*Node {
markdcl()
types.Markdcl(lineno)
nodes := p.stmts(stmt.List)
popdcl()
types.Popdcl()
return nodes
}
func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
markdcl()
types.Markdcl(lineno)
n := p.nod(stmt, OIF, nil, nil)
if stmt.Init != nil {
n.Ninit.Set1(p.stmt(stmt.Init))
......@@ -801,12 +801,12 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
n.Rlist.Set1(e)
}
}
popdcl()
types.Popdcl()
return n
}
func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
markdcl()
types.Markdcl(lineno)
var n *Node
if r, ok := stmt.Init.(*syntax.RangeClause); ok {
if stmt.Cond != nil || stmt.Post != nil {
......@@ -835,12 +835,12 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
}
}
n.Nbody.Set(p.blockStmt(stmt.Body))
popdcl()
types.Popdcl()
return n
}
func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
markdcl()
types.Markdcl(lineno)
n := p.nod(stmt, OSWITCH, nil, nil)
if stmt.Init != nil {
n.Ninit.Set1(p.stmt(stmt.Init))
......@@ -856,7 +856,7 @@ func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
n.List.Set(p.caseClauses(stmt.Body, tswitch))
popdcl()
types.Popdcl()
return n
}
......@@ -864,7 +864,7 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node
var nodes []*Node
for _, clause := range clauses {
p.lineno(clause)
markdcl()
types.Markdcl(lineno)
n := p.nod(clause, OXCASE, nil, nil)
if clause.Cases != nil {
n.List.Set(p.exprList(clause.Cases))
......@@ -876,9 +876,9 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node
// keep track of the instances for reporting unused
nn.Name.Defn = tswitch
}
n.Xoffset = int64(block)
n.Xoffset = int64(types.Block)
n.Nbody.Set(p.stmts(clause.Body))
popdcl()
types.Popdcl()
nodes = append(nodes, n)
}
return nodes
......@@ -894,14 +894,14 @@ func (p *noder) commClauses(clauses []*syntax.CommClause) []*Node {
var nodes []*Node
for _, clause := range clauses {
p.lineno(clause)
markdcl()
types.Markdcl(lineno)
n := p.nod(clause, OXCASE, nil, nil)
if clause.Comm != nil {
n.List.Set1(p.stmt(clause.Comm))
}
n.Xoffset = int64(block)
n.Xoffset = int64(types.Block)
n.Nbody.Set(p.stmts(clause.Body))
popdcl()
types.Popdcl()
nodes = append(nodes, n)
}
return nodes
......@@ -909,7 +909,7 @@ func (p *noder) commClauses(clauses []*syntax.CommClause) []*Node {
func (p *noder) labeledStmt(label *syntax.LabeledStmt) *Node {
lhs := p.nod(label, OLABEL, p.newname(label.Label), nil)
lhs.Sym = dclstack
lhs.Sym = types.Dclstack
var ls *Node
if label.Stmt != nil { // TODO(mdempsky): Should always be present.
......
......@@ -1687,7 +1687,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym, iface
lineno = autogeneratedPos
dclcontext = PEXTERN
markdcl()
types.Markdcl(lineno)
this := namedfield(".this", rcvr)
this.Left.Name.Param.Ntype = this.Right
......@@ -1784,7 +1784,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym, iface
funcbody(fn)
Curfn = fn
popdcl()
types.Popdcl()
if debug_dclstack != 0 {
testdclstack()
}
......
// Copyright 2017 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.
package types
import (
"cmd/internal/src"
"fmt"
)
// Declaration stack & operations
var blockgen int32 = 1 // max block number
var Block int32 // current block number
// Dclstack maintains a stack of shadowed symbol declarations so that
// popdcl can restore their declarations when a block scope ends.
// The stack is maintained as a linked list, using Sym's Link field.
//
// In practice, the "stack" actually ends up forming a tree: goto and label
// statements record the current state of Dclstack so that checkgoto can
// validate that a goto statement does not jump over any declarations or
// into a new block scope.
//
// Finally, the Syms in this list are not "real" Syms as they don't actually
// represent object names. Sym is just a convenient type for saving shadowed
// Sym definitions, and only a subset of its fields are actually used.
var Dclstack *Sym
func dcopy(a, b *Sym) {
a.Pkg = b.Pkg
a.Name = b.Name
a.Def = b.Def
a.Block = b.Block
a.Lastlineno = b.Lastlineno
}
func push(pos src.XPos) *Sym {
d := new(Sym)
d.Lastlineno = pos
d.Link = Dclstack
Dclstack = d
return d
}
// Pushdcl pushes the current declaration for symbol s (if any) so that
// it can be shadowed by a new declaration within a nested block scope.
func Pushdcl(s *Sym, pos src.XPos) *Sym {
d := push(pos)
dcopy(d, s)
return d
}
// Popdcl pops the innermost block scope and restores all symbol declarations
// to their previous state.
func Popdcl() {
d := Dclstack
for ; d != nil && d.Name != ""; d = d.Link {
s := d.Pkg.Lookup(d.Name)
lno := s.Lastlineno
dcopy(s, d)
d.Lastlineno = lno
}
if d == nil {
Fatalf("popdcl: no mark")
}
Dclstack = d.Link // pop mark
Block = d.Block
}
// Markdcl records the start of a new block scope for declarations.
func Markdcl(lineno src.XPos) {
d := push(lineno)
d.Name = "" // used as a mark in fifo
d.Block = Block
blockgen++
Block = blockgen
}
// keep around for debugging
func DumpDclstack() {
i := 0
for d := Dclstack; d != nil; d = d.Link {
fmt.Printf("%6d %p", i, d)
if d.Name != "" {
fmt.Printf(" '%s' %v\n", d.Name, d.Pkg.Lookup(d.Name))
} else {
fmt.Printf(" ---\n")
}
i++
}
}
func IsDclstackValid() bool {
for d := Dclstack; d != nil; d = d.Link {
if d.Name == "" {
return false
}
}
return true
}
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