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)
fn = typecheck(fn, Etop)
typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil
- popdcl()
+ types.Popdcl()
if debug_dclstack != 0 {
testdclstack()
}
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)
fn = typecheck(fn, Etop)
typecheckslice(fn.Nbody.Slice(), Etop)
Curfn = nil
- popdcl()
+ types.Popdcl()
if debug_dclstack != 0 {
testdclstack()
}
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:
case OXFALL:
n := nodl(p.pos(), OXFALL, nil, nil)
- n.Xoffset = int64(block)
+ n.Xoffset = int64(types.Block)
return n
case OBREAK, OCONTINUE:
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:
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")
}
}
vargen++
gen = vargen
}
- pushdcl(s)
+ types.Pushdcl(s, lineno)
n.Name.Curfn = Curfn
}
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 {
}
}
- s.Block = block
+ s.Block = types.Block
s.Lastlineno = lineno
s.Def = asTypesNode(n)
n.Name.Vargen = int32(gen)
}
n.Sym.SetUniq(false)
- if n.Sym.Block == block {
+ if n.Sym.Block == types.Block {
continue
}
// 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
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 {
initUniverse()
- blockgen = 1
dclcontext = PEXTERN
nerrors = 0
// 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
}
func (p *noder) node() {
- block = 1
+ types.Block = 1
imported_unsafe = false
p.lineno(p.file.PkgName)
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:
}
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))
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 {
}
}
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))
n.List.Set(p.caseClauses(stmt.Body, tswitch))
- popdcl()
+ types.Popdcl()
return n
}
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))
// 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
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
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.
lineno = autogeneratedPos
dclcontext = PEXTERN
- markdcl()
+ types.Markdcl(lineno)
this := namedfield(".this", rcvr)
this.Left.Name.Param.Ntype = this.Right
funcbody(fn)
Curfn = fn
- popdcl()
+ types.Popdcl()
if debug_dclstack != 0 {
testdclstack()
}
--- /dev/null
+// 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
+}