aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2021-01-05 10:10:56 -0800
committerMatthew Dempsky <mdempsky@google.com>2021-01-05 10:13:59 -0800
commita8fe098a12a75801e13e99cdcc03a9d8a59c72ce (patch)
tree8a004f89ddd7252c39c9c312e4401163b1409c14 /src/cmd/compile
parenta800acaae140318896e319edc25845d643d8e273 (diff)
parent77365c5ed739f4882020ff76b2a4f5bfe4e8fc9d (diff)
downloadgo-a8fe098a12a75801e13e99cdcc03a9d8a59c72ce.tar.gz
go-a8fe098a12a75801e13e99cdcc03a9d8a59c72ce.zip
[dev.typeparams] all: merge dev.regabi (77365c5) into dev.typeparams
Conflicts: - src/cmd/compile/internal/gc/main.go - test/fixedbugs/issue15055.go Merge List: + 2021-01-05 77365c5ed7 [dev.regabi] cmd/compile: add Name.Canonical and move Byval + 2021-01-05 e09783cbc0 [dev.regabi] cmd/compile: make ir.StaticValue safer + 2021-01-05 9aa950c407 [dev.regabi] cmd/compile: make ir.OuterValue safer + 2021-01-05 eb626409d1 [dev.regabi] cmd/compile: simplify CaptureVars + 2021-01-05 c28ca67a96 [dev.regabi] cmd/compile: fix ir.Dump for []*CaseClause, etc + 2021-01-04 f24e40c14a [dev.regabi] cmd/compile: remove Name.Class_ accessors + 2021-01-04 d89705e087 [dev.regabi] cmd/compile: fix re-export of parameters + 2021-01-04 290b4154b7 [dev.regabi] cmd/compile: fix ICE due to large uint64 constants + 2021-01-04 a30fd52884 [dev.regabi] cmd/compile: use ir.NewNameAt in SubstArgTypes + 2021-01-03 8fc44cf0fa [dev.regabi] cmd/compile: remove a couple CloneName calls + 2021-01-03 907a4bfdc7 [dev.regabi] cmd/compile: fix map assignment order + 2021-01-03 f2e6dab048 [dev.regabi] cmd/compile: remove walkReturn "common case" path + 2021-01-03 d36a6bf44d [dev.regabi] cmd/compile: improve walkReturn common case + 2021-01-03 a317067d65 [dev.regabi] cmd/compile: improve ascompatee + 2021-01-03 5d80a590a2 [dev.regabi] cmd/compile: simplify walkReturn + 2021-01-03 bb1b6c95c2 [dev.regabi] cmd/compile: remove Node.{,Set}Walkdef + 2021-01-03 57c426c9a5 [dev.regabi] cmd/compile: tighten typecheckdef to *ir.Name + 2021-01-03 b1747756e3 [dev.regabi] cmd/compile: reorganize escape analysis somewhat + 2021-01-02 f2538033c0 [dev.regabi] cmd/compile: remove Nodes.Set [generated] + 2021-01-02 2f2d4b4e68 [dev.regabi] cmd/compile: remove {Ptr,Set}Init from Node interface + 2021-01-01 1544a03198 [dev.regabi] cmd/compile: refactor redundant type conversion [generated] + 2021-01-01 7958a23ea3 [dev.regabi] cmd/compile: use *ir.Name where possible in inl.go + 2021-01-01 bfa97ba48f [dev.regabi] test: add another closure test case + 2021-01-01 67ad695416 [dev.regabi] cmd/compile: split escape analysis state + 2021-01-01 fad9a8b528 [dev.regabi] cmd/compile: simplify inlining of closures + 2021-01-01 7d55669847 [dev.regabi] cmd/compile: simplify dwarfgen.declPos + 2021-01-01 9ed1577779 [dev.regabi] cmd/compile: remove Func.ClosureEnter + 2021-01-01 ece345aa69 [dev.regabi] cmd/compile: expand documentation for Func.Closure{Vars,Enter} + 2021-01-01 6ddbc75efd [dev.regabi] cmd/compile: earlier deadcode removal + 2021-01-01 68e6fa4f68 [dev.regabi] cmd/compile: fix package-initialization order + 2021-01-01 3a4474cdfd [dev.regabi] cmd/compile: some more manual shuffling + 2021-01-01 0f1d2129c4 [dev.regabi] cmd/compile: reshuffle type-checking code [generated] + 2021-01-01 b8fd3440cd [dev.regabi] cmd/compile: report unused variables during typecheck + 2021-01-01 fd22df9905 [dev.regabi] cmd/compile: remove idempotent Name() calls [generated] + 2020-12-31 dfbcff80c6 [dev.regabi] cmd/compile: make copyExpr return *ir.Name directly + 2020-12-31 77fd81a3e6 [dev.regabi] cmd/compile: use names for keep alive variables in function call + 2020-12-31 8fe1197654 [dev.regabi] cmd/compile: remove Name.orig + 2020-12-31 477b049060 [dev.regabi] cmd/compile: fix printing of method expressions + 2020-12-30 178c667db2 [dev.regabi] cmd/compile: fix OSLICEARR comments + 2020-12-30 f0d99def5b [dev.regabi] cmd/compile: add newline to ir.Dump + 2020-12-30 451693af71 [dev.regabi] cmd/compile: simplify typecheckdef + 2020-12-30 0c1a899a6c [dev.regabi] cmd/compile: fix defined-pointer method call check + 2020-12-30 f9b67f76a5 [dev.regabi] cmd/compile: change ir.DoChildren to use bool result type + 2020-12-30 499851bac8 [dev.regabi] cmd/compile: generalize ir/mknode.go + 2020-12-30 82ab3d1448 [dev.regabi] cmd/compile: use *ir.Name for Decl.X + 2020-12-30 9958b7ed3e [dev.regabi] cmd/compile: unexport ir.FmtNode + 2020-12-29 f5816624cd [dev.regabi] cmd/compile: change AddrExpr.Alloc to AddrExpr.Prealloc + 2020-12-29 850aa7c60c [dev.regabi] cmd/compile: use *ir.Name instead of ir.Node for CaseClause.Var + 2020-12-29 37babc97bb [dev.regabi] cmd/compile: allow visitor visits *ir.Name + 2020-12-29 5cf3c87fa6 [dev.regabi] cmd/compile: generate case/comm clause functions in mknode.go + 2020-12-29 b3e1ec97fd [dev.regabi] cmd/compile: move new addrtaken bit back to the old name + 2020-12-29 0620c674dd [dev.regabi] cmd/compile: remove original addrtaken bit + 2020-12-29 0523d525ae [dev.regabi] cmd/compile: separate out address taken computation from typechecker + 2020-12-29 9ea272e5ec [dev.regabi] cmd/compile: simplify ir.Func somewhat + 2020-12-29 e40cb4d4ae [dev.regabi] cmd/compile: remove more unused code + 2020-12-29 6f30c95048 [dev.regabi] cmd/compile: remove unneeded indirection + 2020-12-29 171fc6f223 [dev.regabi] cmd/compile: remove workarounds for go/constant issues + 2020-12-29 33801cdc62 [dev.regabi] cmd/compile: use Ntype where possible + 2020-12-29 82ad3083f8 [dev.regabi] cmd/compile: remove typ from AssignOpStmt + 2020-12-29 e34c44a7c4 [dev.regabi] cmd/compile: refactoring typecheck arith + 2020-12-29 a5ec920160 [dev.regabi] cmd/compile: more Linksym cleanup + 2020-12-29 ec59b197d5 [dev.regabi] cmd/compile: rewrite to use linksym helpers [generated] + 2020-12-29 25c613c02d [dev.regabi] cmd/compile: add Linksym helpers + 2020-12-29 289da2b33e [dev.regabi] cmd/compile: move Node.Opt to Name + 2020-12-29 6acbae4fcc [dev.regabi] cmd/compile: address some ir TODOs + 2020-12-29 4629f6a51d [dev.regabi] cmd/compile: merge {Selector,CallPart,Method}Expr + 2020-12-29 e563715b30 [dev.regabi] cmd/compile: remove Sym.Importdef + 2020-12-29 3f370b75fb [dev.regabi] cmd/compile: cleanup //go:generate directives Change-Id: Ibb254630924ac5873ebda6762ceb066f54a82649
Diffstat (limited to 'src/cmd/compile')
-rw-r--r--src/cmd/compile/internal/deadcode/deadcode.go152
-rw-r--r--src/cmd/compile/internal/dwarfgen/dwarf.go71
-rw-r--r--src/cmd/compile/internal/escape/escape.go305
-rw-r--r--src/cmd/compile/internal/gc/abiutils_test.go9
-rw-r--r--src/cmd/compile/internal/gc/abiutilsaux_test.go2
-rw-r--r--src/cmd/compile/internal/gc/compile.go4
-rw-r--r--src/cmd/compile/internal/gc/export.go2
-rw-r--r--src/cmd/compile/internal/gc/main.go74
-rw-r--r--src/cmd/compile/internal/gc/obj.go16
-rw-r--r--src/cmd/compile/internal/inline/inl.go188
-rw-r--r--src/cmd/compile/internal/ir/class_string.go2
-rw-r--r--src/cmd/compile/internal/ir/copy.go8
-rw-r--r--src/cmd/compile/internal/ir/expr.go193
-rw-r--r--src/cmd/compile/internal/ir/fmt.go46
-rw-r--r--src/cmd/compile/internal/ir/func.go44
-rw-r--r--src/cmd/compile/internal/ir/mini.go19
-rw-r--r--src/cmd/compile/internal/ir/mknode.go259
-rw-r--r--src/cmd/compile/internal/ir/name.go74
-rw-r--r--src/cmd/compile/internal/ir/node.go71
-rw-r--r--src/cmd/compile/internal/ir/node_gen.go1564
-rw-r--r--src/cmd/compile/internal/ir/op_string.go2
-rw-r--r--src/cmd/compile/internal/ir/scc.go2
-rw-r--r--src/cmd/compile/internal/ir/sizeof_test.go4
-rw-r--r--src/cmd/compile/internal/ir/stmt.go93
-rw-r--r--src/cmd/compile/internal/ir/type.go86
-rw-r--r--src/cmd/compile/internal/ir/visit.go123
-rw-r--r--src/cmd/compile/internal/liveness/plive.go28
-rw-r--r--src/cmd/compile/internal/noder/import.go2
-rw-r--r--src/cmd/compile/internal/noder/noder.go160
-rw-r--r--src/cmd/compile/internal/pkginit/init.go18
-rw-r--r--src/cmd/compile/internal/pkginit/initorder.go12
-rw-r--r--src/cmd/compile/internal/reflectdata/alg.go12
-rw-r--r--src/cmd/compile/internal/reflectdata/reflect.go126
-rw-r--r--src/cmd/compile/internal/ssa/deadstore.go8
-rw-r--r--src/cmd/compile/internal/ssa/export_test.go2
-rw-r--r--src/cmd/compile/internal/ssa/writebarrier.go5
-rw-r--r--src/cmd/compile/internal/ssagen/abi.go6
-rw-r--r--src/cmd/compile/internal/ssagen/nowb.go4
-rw-r--r--src/cmd/compile/internal/ssagen/pgen.go34
-rw-r--r--src/cmd/compile/internal/ssagen/pgen_test.go4
-rw-r--r--src/cmd/compile/internal/ssagen/ssa.go78
-rw-r--r--src/cmd/compile/internal/staticdata/data.go31
-rw-r--r--src/cmd/compile/internal/staticdata/embed.go4
-rw-r--r--src/cmd/compile/internal/staticinit/sched.go34
-rw-r--r--src/cmd/compile/internal/syntax/operator_string.go30
-rw-r--r--src/cmd/compile/internal/syntax/token_string.go55
-rw-r--r--src/cmd/compile/internal/syntax/tokens.go4
-rw-r--r--src/cmd/compile/internal/typecheck/const.go15
-rw-r--r--src/cmd/compile/internal/typecheck/dcl.go123
-rw-r--r--src/cmd/compile/internal/typecheck/export.go11
-rw-r--r--src/cmd/compile/internal/typecheck/expr.go206
-rw-r--r--src/cmd/compile/internal/typecheck/func.go107
-rw-r--r--src/cmd/compile/internal/typecheck/iexport.go50
-rw-r--r--src/cmd/compile/internal/typecheck/iimport.go56
-rw-r--r--src/cmd/compile/internal/typecheck/stmt.go2
-rw-r--r--src/cmd/compile/internal/typecheck/subr.go51
-rw-r--r--src/cmd/compile/internal/typecheck/syms.go17
-rw-r--r--src/cmd/compile/internal/typecheck/type.go12
-rw-r--r--src/cmd/compile/internal/typecheck/typecheck.go565
-rw-r--r--src/cmd/compile/internal/typecheck/universe.go10
-rw-r--r--src/cmd/compile/internal/types/sizeof_test.go2
-rw-r--r--src/cmd/compile/internal/types/sym.go7
-rw-r--r--src/cmd/compile/internal/types/type.go5
-rw-r--r--src/cmd/compile/internal/types/utils.go11
-rw-r--r--src/cmd/compile/internal/walk/assign.go108
-rw-r--r--src/cmd/compile/internal/walk/builtin.go8
-rw-r--r--src/cmd/compile/internal/walk/closure.go44
-rw-r--r--src/cmd/compile/internal/walk/complit.go20
-rw-r--r--src/cmd/compile/internal/walk/convert.go20
-rw-r--r--src/cmd/compile/internal/walk/expr.go32
-rw-r--r--src/cmd/compile/internal/walk/order.go72
-rw-r--r--src/cmd/compile/internal/walk/race.go8
-rw-r--r--src/cmd/compile/internal/walk/range.go4
-rw-r--r--src/cmd/compile/internal/walk/select.go17
-rw-r--r--src/cmd/compile/internal/walk/stmt.go24
-rw-r--r--src/cmd/compile/internal/walk/switch.go11
-rw-r--r--src/cmd/compile/internal/walk/walk.go43
77 files changed, 2977 insertions, 2754 deletions
diff --git a/src/cmd/compile/internal/deadcode/deadcode.go b/src/cmd/compile/internal/deadcode/deadcode.go
new file mode 100644
index 0000000000..c409320fc4
--- /dev/null
+++ b/src/cmd/compile/internal/deadcode/deadcode.go
@@ -0,0 +1,152 @@
+// Copyright 2009 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 deadcode
+
+import (
+ "go/constant"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+)
+
+func Func(fn *ir.Func) {
+ stmts(&fn.Body)
+
+ if len(fn.Body) == 0 {
+ return
+ }
+
+ for _, n := range fn.Body {
+ if len(n.Init()) > 0 {
+ return
+ }
+ switch n.Op() {
+ case ir.OIF:
+ n := n.(*ir.IfStmt)
+ if !ir.IsConst(n.Cond, constant.Bool) || len(n.Body) > 0 || len(n.Else) > 0 {
+ return
+ }
+ case ir.OFOR:
+ n := n.(*ir.ForStmt)
+ if !ir.IsConst(n.Cond, constant.Bool) || ir.BoolVal(n.Cond) {
+ return
+ }
+ default:
+ return
+ }
+ }
+
+ fn.Body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)}
+}
+
+func stmts(nn *ir.Nodes) {
+ var lastLabel = -1
+ for i, n := range *nn {
+ if n != nil && n.Op() == ir.OLABEL {
+ lastLabel = i
+ }
+ }
+ for i, n := range *nn {
+ // Cut is set to true when all nodes after i'th position
+ // should be removed.
+ // In other words, it marks whole slice "tail" as dead.
+ cut := false
+ if n == nil {
+ continue
+ }
+ if n.Op() == ir.OIF {
+ n := n.(*ir.IfStmt)
+ n.Cond = expr(n.Cond)
+ if ir.IsConst(n.Cond, constant.Bool) {
+ var body ir.Nodes
+ if ir.BoolVal(n.Cond) {
+ n.Else = ir.Nodes{}
+ body = n.Body
+ } else {
+ n.Body = ir.Nodes{}
+ body = n.Else
+ }
+ // If "then" or "else" branch ends with panic or return statement,
+ // it is safe to remove all statements after this node.
+ // isterminating is not used to avoid goto-related complications.
+ // We must be careful not to deadcode-remove labels, as they
+ // might be the target of a goto. See issue 28616.
+ if body := body; len(body) != 0 {
+ switch body[(len(body) - 1)].Op() {
+ case ir.ORETURN, ir.ORETJMP, ir.OPANIC:
+ if i > lastLabel {
+ cut = true
+ }
+ }
+ }
+ }
+ }
+
+ if len(n.Init()) != 0 {
+ stmts(n.(ir.InitNode).PtrInit())
+ }
+ switch n.Op() {
+ case ir.OBLOCK:
+ n := n.(*ir.BlockStmt)
+ stmts(&n.List)
+ case ir.OFOR:
+ n := n.(*ir.ForStmt)
+ stmts(&n.Body)
+ case ir.OIF:
+ n := n.(*ir.IfStmt)
+ stmts(&n.Body)
+ stmts(&n.Else)
+ case ir.ORANGE:
+ n := n.(*ir.RangeStmt)
+ stmts(&n.Body)
+ case ir.OSELECT:
+ n := n.(*ir.SelectStmt)
+ for _, cas := range n.Cases {
+ stmts(&cas.Body)
+ }
+ case ir.OSWITCH:
+ n := n.(*ir.SwitchStmt)
+ for _, cas := range n.Cases {
+ stmts(&cas.Body)
+ }
+ }
+
+ if cut {
+ *nn = (*nn)[:i+1]
+ break
+ }
+ }
+}
+
+func expr(n ir.Node) ir.Node {
+ // Perform dead-code elimination on short-circuited boolean
+ // expressions involving constants with the intent of
+ // producing a constant 'if' condition.
+ switch n.Op() {
+ case ir.OANDAND:
+ n := n.(*ir.LogicalExpr)
+ n.X = expr(n.X)
+ n.Y = expr(n.Y)
+ if ir.IsConst(n.X, constant.Bool) {
+ if ir.BoolVal(n.X) {
+ return n.Y // true && x => x
+ } else {
+ return n.X // false && x => false
+ }
+ }
+ case ir.OOROR:
+ n := n.(*ir.LogicalExpr)
+ n.X = expr(n.X)
+ n.Y = expr(n.Y)
+ if ir.IsConst(n.X, constant.Bool) {
+ if ir.BoolVal(n.X) {
+ return n.X // true || x => true
+ } else {
+ return n.Y // false || x => x
+ }
+ }
+ }
+ return n
+}
diff --git a/src/cmd/compile/internal/dwarfgen/dwarf.go b/src/cmd/compile/internal/dwarfgen/dwarf.go
index 19cb70058c..ff249c1f4e 100644
--- a/src/cmd/compile/internal/dwarfgen/dwarf.go
+++ b/src/cmd/compile/internal/dwarfgen/dwarf.go
@@ -26,7 +26,7 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope,
fn := curfn.(*ir.Func)
if fn.Nname != nil {
- expect := fn.Sym().Linksym()
+ expect := fn.Linksym()
if fnsym.ABI() == obj.ABI0 {
expect = fn.Sym().LinksymABI0()
}
@@ -76,7 +76,7 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope,
if n.Op() != ir.ONAME { // might be OTYPE or OLITERAL
continue
}
- switch n.Class_ {
+ switch n.Class {
case ir.PAUTO:
if !n.Used() {
// Text == nil -> generating abstract function
@@ -90,7 +90,7 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope,
continue
}
apdecls = append(apdecls, n)
- fnsym.Func().RecordAutoType(reflectdata.TypeSym(n.Type()).Linksym())
+ fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
}
}
@@ -127,24 +127,7 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope,
}
func declPos(decl *ir.Name) src.XPos {
- if decl.Name().Defn != nil && (decl.Name().Captured() || decl.Name().Byval()) {
- // It's not clear which position is correct for captured variables here:
- // * decl.Pos is the wrong position for captured variables, in the inner
- // function, but it is the right position in the outer function.
- // * decl.Name.Defn is nil for captured variables that were arguments
- // on the outer function, however the decl.Pos for those seems to be
- // correct.
- // * decl.Name.Defn is the "wrong" thing for variables declared in the
- // header of a type switch, it's their position in the header, rather
- // than the position of the case statement. In principle this is the
- // right thing, but here we prefer the latter because it makes each
- // instance of the header variable local to the lexical block of its
- // case statement.
- // This code is probably wrong for type switch variables that are also
- // captured.
- return decl.Name().Defn.Pos()
- }
- return decl.Pos()
+ return decl.Canonical().Pos()
}
// createDwarfVars process fn, returning a list of DWARF variables and the
@@ -185,7 +168,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
if c == '.' || n.Type().IsUntyped() {
continue
}
- if n.Class_ == ir.PPARAM && !ssagen.TypeOK(n.Type()) {
+ if n.Class == ir.PPARAM && !ssagen.TypeOK(n.Type()) {
// SSA-able args get location lists, and may move in and
// out of registers, so those are handled elsewhere.
// Autos and named output params seem to get handled
@@ -200,10 +183,10 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
decls = append(decls, n)
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
- isReturnValue := (n.Class_ == ir.PPARAMOUT)
- if n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT {
+ isReturnValue := (n.Class == ir.PPARAMOUT)
+ if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
- } else if n.Class_ == ir.PAUTOHEAP {
+ } else if n.Class == ir.PAUTOHEAP {
// If dcl in question has been promoted to heap, do a bit
// of extra work to recover original class (auto or param);
// see issue 30908. This insures that we get the proper
@@ -211,17 +194,17 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
// misleading location for the param (we want pointer-to-heap
// and not stack).
// TODO(thanm): generate a better location expression
- stackcopy := n.Name().Stackcopy
- if stackcopy != nil && (stackcopy.Class_ == ir.PPARAM || stackcopy.Class_ == ir.PPARAMOUT) {
+ stackcopy := n.Stackcopy
+ if stackcopy != nil && (stackcopy.Class == ir.PPARAM || stackcopy.Class == ir.PPARAMOUT) {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
- isReturnValue = (stackcopy.Class_ == ir.PPARAMOUT)
+ isReturnValue = (stackcopy.Class == ir.PPARAMOUT)
}
}
inlIndex := 0
if base.Flag.GenDwarfInl > 1 {
- if n.Name().InlFormal() || n.Name().InlLocal() {
+ if n.InlFormal() || n.InlLocal() {
inlIndex = posInlIndex(n.Pos()) + 1
- if n.Name().InlFormal() {
+ if n.InlFormal() {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
}
}
@@ -240,7 +223,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
ChildIndex: -1,
})
// Record go type of to insure that it gets emitted by the linker.
- fnsym.Func().RecordAutoType(reflectdata.TypeSym(n.Type()).Linksym())
+ fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
}
return decls, vars
@@ -289,7 +272,7 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
var abbrev int
var offs int64
- switch n.Class_ {
+ switch n.Class {
case ir.PAUTO:
offs = n.FrameOffset()
abbrev = dwarf.DW_ABRV_AUTO
@@ -305,16 +288,16 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
abbrev = dwarf.DW_ABRV_PARAM
offs = n.FrameOffset() + base.Ctxt.FixedFrameSize()
default:
- base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class_, n)
+ base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class, n)
}
typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
- delete(fnsym.Func().Autot, reflectdata.TypeSym(n.Type()).Linksym())
+ delete(fnsym.Func().Autot, reflectdata.TypeLinksym(n.Type()))
inlIndex := 0
if base.Flag.GenDwarfInl > 1 {
- if n.Name().InlFormal() || n.Name().InlLocal() {
+ if n.InlFormal() || n.InlLocal() {
inlIndex = posInlIndex(n.Pos()) + 1
- if n.Name().InlFormal() {
+ if n.InlFormal() {
abbrev = dwarf.DW_ABRV_PARAM
}
}
@@ -322,8 +305,8 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
declpos := base.Ctxt.InnermostPos(declPos(n))
return &dwarf.Var{
Name: n.Sym().Name,
- IsReturnValue: n.Class_ == ir.PPARAMOUT,
- IsInlFormal: n.Name().InlFormal(),
+ IsReturnValue: n.Class == ir.PPARAMOUT,
+ IsInlFormal: n.InlFormal(),
Abbrev: abbrev,
StackOffset: int32(offs),
Type: base.Ctxt.Lookup(typename),
@@ -367,7 +350,7 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
n := debug.Vars[varID]
var abbrev int
- switch n.Class_ {
+ switch n.Class {
case ir.PAUTO:
abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
case ir.PPARAM, ir.PPARAMOUT:
@@ -376,14 +359,14 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
return nil
}
- gotype := reflectdata.TypeSym(n.Type()).Linksym()
+ gotype := reflectdata.TypeLinksym(n.Type())
delete(fnsym.Func().Autot, gotype)
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
inlIndex := 0
if base.Flag.GenDwarfInl > 1 {
- if n.Name().InlFormal() || n.Name().InlLocal() {
+ if n.InlFormal() || n.InlLocal() {
inlIndex = posInlIndex(n.Pos()) + 1
- if n.Name().InlFormal() {
+ if n.InlFormal() {
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
}
}
@@ -391,8 +374,8 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
declpos := base.Ctxt.InnermostPos(n.Pos())
dvar := &dwarf.Var{
Name: n.Sym().Name,
- IsReturnValue: n.Class_ == ir.PPARAMOUT,
- IsInlFormal: n.Name().InlFormal(),
+ IsReturnValue: n.Class == ir.PPARAMOUT,
+ IsInlFormal: n.InlFormal(),
Abbrev: abbrev,
Type: base.Ctxt.Lookup(typename),
// The stack offset is used as a sorting key, so for decomposed
diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go
index d8f0111d2d..794c52f5ae 100644
--- a/src/cmd/compile/internal/escape/escape.go
+++ b/src/cmd/compile/internal/escape/escape.go
@@ -85,20 +85,29 @@ import (
// u[2], etc. However, we do record the implicit dereference involved
// in indexing a slice.
-type escape struct {
+// A batch holds escape analysis state that's shared across an entire
+// batch of functions being analyzed at once.
+type batch struct {
allLocs []*location
- labels map[*types.Sym]labelState // known labels
- curfn *ir.Func
+ heapLoc location
+ blankLoc location
+}
+
+// An escape holds state specific to a single function being analyzed
+// within a batch.
+type escape struct {
+ *batch
+
+ curfn *ir.Func // function being analyzed
+
+ labels map[*types.Sym]labelState // known labels
// loopDepth counts the current loop nesting depth within
// curfn. It increments within each "for" loop and at each
// label with a corresponding backwards "goto" (i.e.,
// unstructured loop).
loopDepth int
-
- heapLoc location
- blankLoc location
}
// An location represents an abstract location that stores a Go
@@ -165,12 +174,16 @@ func Fmt(n ir.Node) string {
text = fmt.Sprintf("esc(%d)", n.Esc())
}
- if e, ok := n.Opt().(*location); ok && e.loopDepth != 0 {
- if text != "" {
- text += " "
+ if n.Op() == ir.ONAME {
+ n := n.(*ir.Name)
+ if loc, ok := n.Opt.(*location); ok && loc.loopDepth != 0 {
+ if text != "" {
+ text += " "
+ }
+ text += fmt.Sprintf("ld(%d)", loc.loopDepth)
}
- text += fmt.Sprintf("ld(%d)", e.loopDepth)
}
+
return text
}
@@ -183,23 +196,33 @@ func Batch(fns []*ir.Func, recursive bool) {
}
}
- var e escape
- e.heapLoc.escapes = true
+ var b batch
+ b.heapLoc.escapes = true
// Construct data-flow graph from syntax trees.
for _, fn := range fns {
- e.initFunc(fn)
+ b.initFunc(fn)
}
for _, fn := range fns {
- e.walkFunc(fn)
+ if !fn.IsHiddenClosure() {
+ b.walkFunc(fn)
+ }
}
- e.curfn = nil
- e.walkAll()
- e.finish(fns)
+ b.walkAll()
+ b.finish(fns)
}
-func (e *escape) initFunc(fn *ir.Func) {
+func (b *batch) with(fn *ir.Func) *escape {
+ return &escape{
+ batch: b,
+ curfn: fn,
+ loopDepth: 1,
+ }
+}
+
+func (b *batch) initFunc(fn *ir.Func) {
+ e := b.with(fn)
if fn.Esc() != escFuncUnknown {
base.Fatalf("unexpected node: %v", fn)
}
@@ -208,9 +231,6 @@ func (e *escape) initFunc(fn *ir.Func) {
ir.Dump("escAnalyze", fn)
}
- e.curfn = fn
- e.loopDepth = 1
-
// Allocate locations for local variables.
for _, dcl := range fn.Dcl {
if dcl.Op() == ir.ONAME {
@@ -219,7 +239,8 @@ func (e *escape) initFunc(fn *ir.Func) {
}
}
-func (e *escape) walkFunc(fn *ir.Func) {
+func (b *batch) walkFunc(fn *ir.Func) {
+ e := b.with(fn)
fn.SetEsc(escFuncStarted)
// Identify labels that mark the head of an unstructured loop.
@@ -242,8 +263,6 @@ func (e *escape) walkFunc(fn *ir.Func) {
}
})
- e.curfn = fn
- e.loopDepth = 1
e.block(fn.Body)
if len(e.labels) != 0 {
@@ -349,54 +368,52 @@ func (e *escape) stmt(n ir.Node) {
case ir.ORANGE:
// for Key, Value = range X { Body }
n := n.(*ir.RangeStmt)
- e.loopDepth++
- e.addr(n.Key)
- k := e.addr(n.Value)
- e.block(n.Body)
- e.loopDepth--
// X is evaluated outside the loop.
+ tmp := e.newLoc(nil, false)
+ e.expr(tmp.asHole(), n.X)
+
+ e.loopDepth++
+ ks := e.addrs([]ir.Node{n.Key, n.Value})
if n.X.Type().IsArray() {
- k = k.note(n, "range")
+ e.flow(ks[1].note(n, "range"), tmp)
} else {
- k = k.deref(n, "range-deref")
+ e.flow(ks[1].deref(n, "range-deref"), tmp)
}
- e.expr(e.later(k), n.X)
+
+ e.block(n.Body)
+ e.loopDepth--
case ir.OSWITCH:
n := n.(*ir.SwitchStmt)
- typesw := n.Tag != nil && n.Tag.Op() == ir.OTYPESW
- var ks []hole
- for _, cas := range n.Cases { // cases
- if typesw && n.Tag.(*ir.TypeSwitchGuard).Tag != nil {
- cv := cas.Var
- k := e.dcl(cv) // type switch variables have no ODCL.
- if cv.Type().HasPointers() {
- ks = append(ks, k.dotType(cv.Type(), cas, "switch case"))
+ if guard, ok := n.Tag.(*ir.TypeSwitchGuard); ok {
+ var ks []hole
+ if guard.Tag != nil {
+ for _, cas := range n.Cases {
+ cv := cas.Var
+ k := e.dcl(cv) // type switch variables have no ODCL.
+ if cv.Type().HasPointers() {
+ ks = append(ks, k.dotType(cv.Type(), cas, "switch case"))
+ }
}
}
-
- e.discards(cas.List)
- e.block(cas.Body)
- }
-
- if typesw {
e.expr(e.teeHole(ks...), n.Tag.(*ir.TypeSwitchGuard).X)
} else {
e.discard(n.Tag)
}
+ for _, cas := range n.Cases {
+ e.discards(cas.List)
+ e.block(cas.Body)
+ }
+
case ir.OSELECT:
n := n.(*ir.SelectStmt)
for _, cas := range n.Cases {
e.stmt(cas.Comm)
e.block(cas.Body)
}
- case ir.OSELRECV2:
- n := n.(*ir.AssignListStmt)
- e.assign(n.Lhs[0], n.Rhs[0], "selrecv", n)
- e.assign(n.Lhs[1], nil, "selrecv", n)
case ir.ORECV:
// TODO(mdempsky): Consider e.discard(n.Left).
n := n.(*ir.UnaryExpr)
@@ -408,28 +425,24 @@ func (e *escape) stmt(n ir.Node) {
case ir.OAS:
n := n.(*ir.AssignStmt)
- e.assign(n.X, n.Y, "assign", n)
+ e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n)
case ir.OASOP:
n := n.(*ir.AssignOpStmt)
- e.assign(n.X, n.Y, "assign", n)
+ // TODO(mdempsky): Worry about OLSH/ORSH?
+ e.assignList([]ir.Node{n.X}, []ir.Node{n.Y}, "assign", n)
case ir.OAS2:
n := n.(*ir.AssignListStmt)
- for i, nl := range n.Lhs {
- e.assign(nl, n.Rhs[i], "assign-pair", n)
- }
+ e.assignList(n.Lhs, n.Rhs, "assign-pair", n)
case ir.OAS2DOTTYPE: // v, ok = x.(type)
n := n.(*ir.AssignListStmt)
- e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-dot-type", n)
- e.assign(n.Lhs[1], nil, "assign-pair-dot-type", n)
+ e.assignList(n.Lhs, n.Rhs, "assign-pair-dot-type", n)
case ir.OAS2MAPR: // v, ok = m[k]
n := n.(*ir.AssignListStmt)
- e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-mapr", n)
- e.assign(n.Lhs[1], nil, "assign-pair-mapr", n)
- case ir.OAS2RECV: // v, ok = <-ch
+ e.assignList(n.Lhs, n.Rhs, "assign-pair-mapr", n)
+ case ir.OAS2RECV, ir.OSELRECV2: // v, ok = <-ch
n := n.(*ir.AssignListStmt)
- e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-receive", n)
- e.assign(n.Lhs[1], nil, "assign-pair-receive", n)
+ e.assignList(n.Lhs, n.Rhs, "assign-pair-receive", n)
case ir.OAS2FUNC:
n := n.(*ir.AssignListStmt)
@@ -438,9 +451,11 @@ func (e *escape) stmt(n ir.Node) {
case ir.ORETURN:
n := n.(*ir.ReturnStmt)
results := e.curfn.Type().Results().FieldSlice()
- for i, v := range n.Results {
- e.assign(ir.AsNode(results[i].Nname), v, "return", n)
+ dsts := make([]ir.Node, len(results))
+ for i, res := range results {
+ dsts[i] = res.Nname.(*ir.Name)
}
+ e.assignList(dsts, n.Results, "return", n)
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
e.call(nil, n, nil)
case ir.OGO, ir.ODEFER:
@@ -504,7 +519,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
case ir.ONAME:
n := n.(*ir.Name)
- if n.Class_ == ir.PFUNC || n.Class_ == ir.PEXTERN {
+ if n.Class == ir.PFUNC || n.Class == ir.PEXTERN {
return
}
e.flow(k, e.oldLoc(n))
@@ -612,10 +627,10 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
// Flow the receiver argument to both the closure and
// to the receiver parameter.
- n := n.(*ir.CallPartExpr)
+ n := n.(*ir.SelectorExpr)
closureK := e.spill(k, n)
- m := n.Method
+ m := n.Selection
// We don't know how the method value will be called
// later, so conservatively assume the result
@@ -676,9 +691,13 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
case ir.OCLOSURE:
n := n.(*ir.ClosureExpr)
- k = e.spill(k, n)
+
+ if fn := n.Func; fn.IsHiddenClosure() {
+ e.walkFunc(fn)
+ }
// Link addresses of captured variables to closure.
+ k = e.spill(k, n)
for _, v := range n.Func.ClosureVars {
k := k
if !v.Byval() {
@@ -772,13 +791,13 @@ func (e *escape) addr(n ir.Node) hole {
base.Fatalf("unexpected addr: %v", n)
case ir.ONAME:
n := n.(*ir.Name)
- if n.Class_ == ir.PEXTERN {
+ if n.Class == ir.PEXTERN {
break
}
k = e.oldLoc(n).asHole()
case ir.ONAMEOFFSET:
n := n.(*ir.NameOffsetExpr)
- e.addr(n.Name_)
+ k = e.addr(n.Name_)
case ir.ODOT:
n := n.(*ir.SelectorExpr)
k = e.addr(n.X)
@@ -798,10 +817,6 @@ func (e *escape) addr(n ir.Node) hole {
e.assignHeap(n.Index, "key of map put", n)
}
- if !n.Type().HasPointers() {
- k = e.discardHole()
- }
-
return k
}
@@ -813,6 +828,16 @@ func (e *escape) addrs(l ir.Nodes) []hole {
return ks
}
+func (e *escape) assignList(dsts, srcs []ir.Node, why string, where ir.Node) {
+ for i, dst := range dsts {
+ var src ir.Node
+ if i < len(srcs) {
+ src = srcs[i]
+ }
+ e.assign(dst, src, why, where)
+ }
+}
+
// assign evaluates the assignment dst = src.
func (e *escape) assign(dst, src ir.Node, why string, where ir.Node) {
// Filter out some no-op assignments for escape analysis.
@@ -874,7 +899,7 @@ func (e *escape) call(ks []hole, call, where ir.Node) {
switch call.Op() {
case ir.OCALLFUNC:
switch v := ir.StaticValue(call.X); {
- case v.Op() == ir.ONAME && v.(*ir.Name).Class_ == ir.PFUNC:
+ case v.Op() == ir.ONAME && v.(*ir.Name).Class == ir.PFUNC:
fn = v.(*ir.Name)
case v.Op() == ir.OCLOSURE:
fn = v.(*ir.ClosureExpr).Func.Nname
@@ -1097,7 +1122,7 @@ func (e *escape) teeHole(ks ...hole) hole {
return loc.asHole()
}
-func (e *escape) dcl(n ir.Node) hole {
+func (e *escape) dcl(n *ir.Name) hole {
loc := e.oldLoc(n)
loc.loopDepth = e.loopDepth
return loc.asHole()
@@ -1121,19 +1146,6 @@ func (e *escape) later(k hole) hole {
return loc.asHole()
}
-// canonicalNode returns the canonical *Node that n logically
-// represents.
-func canonicalNode(n ir.Node) ir.Node {
- if n != nil && n.Op() == ir.ONAME && n.Name().IsClosureVar() {
- n = n.Name().Defn
- if n.Name().IsClosureVar() {
- base.Fatalf("still closure var")
- }
- }
-
- return n
-}
-
func (e *escape) newLoc(n ir.Node, transient bool) *location {
if e.curfn == nil {
base.Fatalf("e.curfn isn't set")
@@ -1142,7 +1154,9 @@ func (e *escape) newLoc(n ir.Node, transient bool) *location {
base.ErrorfAt(n.Pos(), "%v is incomplete (or unallocatable); stack allocation disallowed", n.Type())
}
- n = canonicalNode(n)
+ if n != nil && n.Op() == ir.ONAME {
+ n = n.(*ir.Name).Canonical()
+ }
loc := &location{
n: n,
curfn: e.curfn,
@@ -1151,15 +1165,17 @@ func (e *escape) newLoc(n ir.Node, transient bool) *location {
}
e.allLocs = append(e.allLocs, loc)
if n != nil {
- if n.Op() == ir.ONAME && n.Name().Curfn != e.curfn {
+ if n.Op() == ir.ONAME {
n := n.(*ir.Name)
- base.Fatalf("curfn mismatch: %v != %v", n.Name().Curfn, e.curfn)
- }
+ if n.Curfn != e.curfn {
+ base.Fatalf("curfn mismatch: %v != %v", n.Curfn, e.curfn)
+ }
- if n.Opt() != nil {
- base.Fatalf("%v already has a location", n)
+ if n.Opt != nil {
+ base.Fatalf("%v already has a location", n)
+ }
+ n.Opt = loc
}
- n.SetOpt(loc)
if why := HeapAllocReason(n); why != "" {
e.flow(e.heapHole().addr(n, why), loc)
@@ -1168,9 +1184,8 @@ func (e *escape) newLoc(n ir.Node, transient bool) *location {
return loc
}
-func (e *escape) oldLoc(n ir.Node) *location {
- n = canonicalNode(n)
- return n.Opt().(*location)
+func (b *batch) oldLoc(n *ir.Name) *location {
+ return n.Canonical().Opt.(*location)
}
func (l *location) asHole() hole {
@@ -1210,7 +1225,7 @@ func (e *escape) discardHole() hole { return e.blankLoc.asHole() }
// walkAll computes the minimal dereferences between all pairs of
// locations.
-func (e *escape) walkAll() {
+func (b *batch) walkAll() {
// We use a work queue to keep track of locations that we need
// to visit, and repeatedly walk until we reach a fixed point.
//
@@ -1220,7 +1235,7 @@ func (e *escape) walkAll() {
// happen at most once. So we take Θ(len(e.allLocs)) walks.
// LIFO queue, has enough room for e.allLocs and e.heapLoc.
- todo := make([]*location, 0, len(e.allLocs)+1)
+ todo := make([]*location, 0, len(b.allLocs)+1)
enqueue := func(loc *location) {
if !loc.queued {
todo = append(todo, loc)
@@ -1228,10 +1243,10 @@ func (e *escape) walkAll() {
}
}
- for _, loc := range e.allLocs {
+ for _, loc := range b.allLocs {
enqueue(loc)
}
- enqueue(&e.heapLoc)
+ enqueue(&b.heapLoc)
var walkgen uint32
for len(todo) > 0 {
@@ -1240,13 +1255,13 @@ func (e *escape) walkAll() {
root.queued = false
walkgen++
- e.walkOne(root, walkgen, enqueue)
+ b.walkOne(root, walkgen, enqueue)
}
}
// walkOne computes the minimal number of dereferences from root to
// all other locations.
-func (e *escape) walkOne(root *location, walkgen uint32, enqueue func(*location)) {
+func (b *batch) walkOne(root *location, walkgen uint32, enqueue func(*location)) {
// The data flow graph has negative edges (from addressing
// operations), so we use the Bellman-Ford algorithm. However,
// we don't have to worry about infinite negative cycles since
@@ -1281,7 +1296,7 @@ func (e *escape) walkOne(root *location, walkgen uint32, enqueue func(*location)
}
}
- if e.outlives(root, l) {
+ if b.outlives(root, l) {
// l's value flows to root. If l is a function
// parameter and root is the heap or a
// corresponding result parameter, then record
@@ -1290,12 +1305,13 @@ func (e *escape) walkOne(root *location, walkgen uint32, enqueue func(*location)
if l.isName(ir.PPARAM) {
if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.escapes {
if base.Flag.LowerM >= 2 {
- fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", base.FmtPos(l.n.Pos()), l.n, e.explainLoc(root), derefs)
+ fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", base.FmtPos(l.n.Pos()), l.n, b.explainLoc(root), derefs)
}
- explanation := e.explainPath(root, l)
+ explanation := b.explainPath(root, l)
if logopt.Enabled() {
- logopt.LogOpt(l.n.Pos(), "leak", "escape", ir.FuncName(e.curfn),
- fmt.Sprintf("parameter %v leaks to %s with derefs=%d", l.n, e.explainLoc(root), derefs), explanation)
+ var e_curfn *ir.Func // TODO(mdempsky): Fix.
+ logopt.LogOpt(l.n.Pos(), "leak", "escape", ir.FuncName(e_curfn),
+ fmt.Sprintf("parameter %v leaks to %s with derefs=%d", l.n, b.explainLoc(root), derefs), explanation)
}
}
l.leakTo(root, derefs)
@@ -1309,9 +1325,10 @@ func (e *escape) walkOne(root *location, walkgen uint32, enqueue func(*location)
if base.Flag.LowerM >= 2 {
fmt.Printf("%s: %v escapes to heap:\n", base.FmtPos(l.n.Pos()), l.n)
}
- explanation := e.explainPath(root, l)
+ explanation := b.explainPath(root, l)
if logopt.Enabled() {
- logopt.LogOpt(l.n.Pos(), "escape", "escape", ir.FuncName(e.curfn), fmt.Sprintf("%v escapes to heap", l.n), explanation)
+ var e_curfn *ir.Func // TODO(mdempsky): Fix.
+ logopt.LogOpt(l.n.Pos(), "escape", "escape", ir.FuncName(e_curfn), fmt.Sprintf("%v escapes to heap", l.n), explanation)
}
}
l.escapes = true
@@ -1337,7 +1354,7 @@ func (e *escape) walkOne(root *location, walkgen uint32, enqueue func(*location)
}
// explainPath prints an explanation of how src flows to the walk root.
-func (e *escape) explainPath(root, src *location) []*logopt.LoggedOpt {
+func (b *batch) explainPath(root, src *location) []*logopt.LoggedOpt {
visited := make(map[*location]bool)
pos := base.FmtPos(src.n.Pos())
var explanation []*logopt.LoggedOpt
@@ -1356,7 +1373,7 @@ func (e *escape) explainPath(root, src *location) []*logopt.LoggedOpt {
base.Fatalf("path inconsistency: %v != %v", edge.src, src)
}
- explanation = e.explainFlow(pos, dst, src, edge.derefs, edge.notes, explanation)
+ explanation = b.explainFlow(pos, dst, src, edge.derefs, edge.notes, explanation)
if dst == root {
break
@@ -1367,14 +1384,14 @@ func (e *escape) explainPath(root, src *location) []*logopt.LoggedOpt {
return explanation
}
-func (e *escape) explainFlow(pos string, dst, srcloc *location, derefs int, notes *note, explanation []*logopt.LoggedOpt) []*logopt.LoggedOpt {
+func (b *batch) explainFlow(pos string, dst, srcloc *location, derefs int, notes *note, explanation []*logopt.LoggedOpt) []*logopt.LoggedOpt {
ops := "&"
if derefs >= 0 {
ops = strings.Repeat("*", derefs)
}
print := base.Flag.LowerM >= 2
- flow := fmt.Sprintf(" flow: %s = %s%v:", e.explainLoc(dst), ops, e.explainLoc(srcloc))
+ flow := fmt.Sprintf(" flow: %s = %s%v:", b.explainLoc(dst), ops, b.explainLoc(srcloc))
if print {
fmt.Printf("%s:%s\n", pos, flow)
}
@@ -1385,7 +1402,8 @@ func (e *escape) explainFlow(pos string, dst, srcloc *location, derefs int, note
} else if srcloc != nil && srcloc.n != nil {
epos = srcloc.n.Pos()
}
- explanation = append(explanation, logopt.NewLoggedOpt(epos, "escflow", "escape", ir.FuncName(e.curfn), flow))
+ var e_curfn *ir.Func // TODO(mdempsky): Fix.
+ explanation = append(explanation, logopt.NewLoggedOpt(epos, "escflow", "escape", ir.FuncName(e_curfn), flow))
}
for note := notes; note != nil; note = note.next {
@@ -1393,15 +1411,16 @@ func (e *escape) explainFlow(pos string, dst, srcloc *location, derefs int, note
fmt.Printf("%s: from %v (%v) at %s\n", pos, note.where, note.why, base.FmtPos(note.where.Pos()))
}
if logopt.Enabled() {
- explanation = append(explanation, logopt.NewLoggedOpt(note.where.Pos(), "escflow", "escape", ir.FuncName(e.curfn),
+ var e_curfn *ir.Func // TODO(mdempsky): Fix.
+ explanation = append(explanation, logopt.NewLoggedOpt(note.where.Pos(), "escflow", "escape", ir.FuncName(e_curfn),
fmt.Sprintf(" from %v (%v)", note.where, note.why)))
}
}
return explanation
}
-func (e *escape) explainLoc(l *location) string {
- if l == &e.heapLoc {
+func (b *batch) explainLoc(l *location) string {
+ if l == &b.heapLoc {
return "{heap}"
}
if l.n == nil {
@@ -1416,7 +1435,7 @@ func (e *escape) explainLoc(l *location) string {
// outlives reports whether values stored in l may survive beyond
// other's lifetime if stack allocated.
-func (e *escape) outlives(l, other *location) bool {
+func (b *batch) outlives(l, other *location) bool {
// The heap outlives everything.
if l.escapes {
return true
@@ -1497,7 +1516,7 @@ func (l *location) leakTo(sink *location, derefs int) {
l.paramEsc.AddHeap(derefs)
}
-func (e *escape) finish(fns []*ir.Func) {
+func (b *batch) finish(fns []*ir.Func) {
// Record parameter tags for package export data.
for _, fn := range fns {
fn.SetEsc(escFuncTagged)
@@ -1506,17 +1525,20 @@ func (e *escape) finish(fns []*ir.Func) {
for _, fs := range &types.RecvsParams {
for _, f := range fs(fn.Type()).Fields().Slice() {
narg++
- f.Note = e.paramTag(fn, narg, f)
+ f.Note = b.paramTag(fn, narg, f)
}
}
}
- for _, loc := range e.allLocs {
+ for _, loc := range b.allLocs {
n := loc.n
if n == nil {
continue
}
- n.SetOpt(nil)
+ if n.Op() == ir.ONAME {
+ n := n.(*ir.Name)
+ n.Opt = nil
+ }
// Update n.Esc based on escape analysis results.
@@ -1526,7 +1548,8 @@ func (e *escape) finish(fns []*ir.Func) {
base.WarnfAt(n.Pos(), "%v escapes to heap", n)
}
if logopt.Enabled() {
- logopt.LogOpt(n.Pos(), "escape", "escape", ir.FuncName(e.curfn))
+ var e_curfn *ir.Func // TODO(mdempsky): Fix.
+ logopt.LogOpt(n.Pos(), "escape", "escape", ir.FuncName(e_curfn))
}
}
n.SetEsc(ir.EscHeap)
@@ -1542,7 +1565,7 @@ func (e *escape) finish(fns []*ir.Func) {
n := n.(*ir.ClosureExpr)
n.SetTransient(true)
case ir.OCALLPART:
- n := n.(*ir.CallPartExpr)
+ n := n.(*ir.SelectorExpr)
n.SetTransient(true)
case ir.OSLICELIT:
n := n.(*ir.CompLitExpr)
@@ -1554,7 +1577,7 @@ func (e *escape) finish(fns []*ir.Func) {
}
func (l *location) isName(c ir.Class) bool {
- return l.n != nil && l.n.Op() == ir.ONAME && l.n.(*ir.Name).Class_ == c
+ return l.n != nil && l.n.Op() == ir.ONAME && l.n.(*ir.Name).Class == c
}
const numEscResults = 7
@@ -1847,7 +1870,7 @@ func HeapAllocReason(n ir.Node) string {
// Parameters are always passed via the stack.
if n.Op() == ir.ONAME {
n := n.(*ir.Name)
- if n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT {
+ if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
return ""
}
}
@@ -1863,7 +1886,7 @@ func HeapAllocReason(n ir.Node) string {
if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
return "too large for stack"
}
- if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.CallPartExpr)).Size() >= ir.MaxImplicitStackVarSize {
+ if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.SelectorExpr)).Size() >= ir.MaxImplicitStackVarSize {
return "too large for stack"
}
@@ -1904,7 +1927,7 @@ func addrescapes(n ir.Node) {
// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
// on PPARAM it means something different.
- if n.Class_ == ir.PAUTO && n.Esc() == ir.EscNever {
+ if n.Class == ir.PAUTO && n.Esc() == ir.EscNever {
break
}
@@ -1914,7 +1937,7 @@ func addrescapes(n ir.Node) {
break
}
- if n.Class_ != ir.PPARAM && n.Class_ != ir.PPARAMOUT && n.Class_ != ir.PAUTO {
+ if n.Class != ir.PPARAM && n.Class != ir.PPARAMOUT && n.Class != ir.PAUTO {
break
}
@@ -1968,7 +1991,7 @@ func moveToHeap(n *ir.Name) {
if base.Flag.CompilingRuntime {
base.Errorf("%v escapes to heap, not allowed in runtime", n)
}
- if n.Class_ == ir.PAUTOHEAP {
+ if n.Class == ir.PAUTOHEAP {
ir.Dump("n", n)
base.Fatalf("double move to heap")
}
@@ -1987,7 +2010,7 @@ func moveToHeap(n *ir.Name) {
// Parameters have a local stack copy used at function start/end
// in addition to the copy in the heap that may live longer than
// the function.
- if n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT {
+ if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
if n.FrameOffset() == types.BADWIDTH {
base.Fatalf("addrescapes before param assignment")
}
@@ -1999,9 +2022,9 @@ func moveToHeap(n *ir.Name) {
stackcopy := typecheck.NewName(n.Sym())
stackcopy.SetType(n.Type())
stackcopy.SetFrameOffset(n.FrameOffset())
- stackcopy.Class_ = n.Class_
+ stackcopy.Class = n.Class
stackcopy.Heapaddr = heapaddr
- if n.Class_ == ir.PPARAMOUT {
+ if n.Class == ir.PPARAMOUT {
// Make sure the pointer to the heap copy is kept live throughout the function.
// The function could panic at any point, and then a defer could recover.
// Thus, we need the pointer to the heap copy always available so the
@@ -2023,7 +2046,7 @@ func moveToHeap(n *ir.Name) {
}
// Parameters are before locals, so can stop early.
// This limits the search even in functions with many local variables.
- if d.Class_ == ir.PAUTO {
+ if d.Class == ir.PAUTO {
break
}
}
@@ -2034,7 +2057,7 @@ func moveToHeap(n *ir.Name) {
}
// Modify n in place so that uses of n now mean indirection of the heapaddr.
- n.Class_ = ir.PAUTOHEAP
+ n.Class = ir.PAUTOHEAP
n.SetFrameOffset(0)
n.Heapaddr = heapaddr
n.SetEsc(ir.EscHeap)
@@ -2052,7 +2075,7 @@ const UnsafeUintptrNote = "unsafe-uintptr"
// marked go:uintptrescapes.
const UintptrEscapesNote = "uintptr-escapes"
-func (e *escape) paramTag(fn *ir.Func, narg int, f *types.Field) string {
+func (b *batch) paramTag(fn *ir.Func, narg int, f *types.Field) string {
name := func() string {
if f.Sym != nil {
return f.Sym.Name
@@ -2122,8 +2145,8 @@ func (e *escape) paramTag(fn *ir.Func, narg int, f *types.Field) string {
return esc.Encode()
}
- n := ir.AsNode(f.Nname)
- loc := e.oldLoc(n)
+ n := f.Nname.(*ir.Name)
+ loc := b.oldLoc(n)
esc := loc.paramEsc
esc.Optimize()
diff --git a/src/cmd/compile/internal/gc/abiutils_test.go b/src/cmd/compile/internal/gc/abiutils_test.go
index a421a229dc..6fd0af1b1f 100644
--- a/src/cmd/compile/internal/gc/abiutils_test.go
+++ b/src/cmd/compile/internal/gc/abiutils_test.go
@@ -7,7 +7,6 @@ package gc
import (
"bufio"
"cmd/compile/internal/base"
- "cmd/compile/internal/reflectdata"
"cmd/compile/internal/ssagen"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
@@ -39,13 +38,7 @@ func TestMain(m *testing.M) {
base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
types.PtrSize = ssagen.Arch.LinkArch.PtrSize
types.RegSize = ssagen.Arch.LinkArch.RegSize
- types.TypeLinkSym = func(t *types.Type) *obj.LSym {
- return reflectdata.TypeSym(t).Linksym()
- }
- types.TypeLinkSym = func(t *types.Type) *obj.LSym {
- return reflectdata.TypeSym(t).Linksym()
- }
- typecheck.Init()
+ typecheck.InitUniverse()
os.Exit(m.Run())
}
diff --git a/src/cmd/compile/internal/gc/abiutilsaux_test.go b/src/cmd/compile/internal/gc/abiutilsaux_test.go
index e6590beac0..9386b554b0 100644
--- a/src/cmd/compile/internal/gc/abiutilsaux_test.go
+++ b/src/cmd/compile/internal/gc/abiutilsaux_test.go
@@ -21,7 +21,7 @@ import (
func mkParamResultField(t *types.Type, s *types.Sym, which ir.Class) *types.Field {
field := types.NewField(src.NoXPos, s, t)
n := typecheck.NewName(s)
- n.Class_ = which
+ n.Class = which
field.Nname = n
n.SetType(t)
return field
diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go
index 926b2dee95..25b1c76737 100644
--- a/src/cmd/compile/internal/gc/compile.go
+++ b/src/cmd/compile/internal/gc/compile.go
@@ -83,7 +83,7 @@ func compile(fn *ir.Func) {
// because symbols must be allocated before the parallel
// phase of the compiler.
for _, n := range fn.Dcl {
- switch n.Class_ {
+ switch n.Class {
case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
if liveness.ShouldTrack(n) && n.Addrtaken() {
reflectdata.WriteType(n.Type())
@@ -174,5 +174,5 @@ func isInlinableButNotInlined(fn *ir.Func) bool {
if fn.Sym() == nil {
return true
}
- return !fn.Sym().Linksym().WasInlined()
+ return !fn.Linksym().WasInlined()
}
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index c65c6c8335..356fcfa671 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -83,7 +83,7 @@ type exporter struct {
func (p *exporter) markObject(n ir.Node) {
if n.Op() == ir.ONAME {
n := n.(*ir.Name)
- if n.Class_ == ir.PFUNC {
+ if n.Class == ir.PFUNC {
inline.Inline_Flood(n, typecheck.Export)
}
}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 6fc9695d41..2ea614e17f 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:generate go run mkbuiltin.go
-
package gc
import (
"bufio"
"bytes"
"cmd/compile/internal/base"
+ "cmd/compile/internal/deadcode"
"cmd/compile/internal/devirtualize"
"cmd/compile/internal/dwarfgen"
"cmd/compile/internal/escape"
@@ -192,9 +191,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
types.PtrSize = ssagen.Arch.LinkArch.PtrSize
types.RegSize = ssagen.Arch.LinkArch.RegSize
types.MaxWidth = ssagen.Arch.MAXWIDTH
- types.TypeLinkSym = func(t *types.Type) *obj.LSym {
- return reflectdata.TypeSym(t).Linksym()
- }
typecheck.Target = new(ir.Package)
@@ -204,37 +200,60 @@ func Main(archInit func(*ssagen.ArchInfo)) {
base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
- types.TypeLinkSym = func(t *types.Type) *obj.LSym {
- return reflectdata.TypeSym(t).Linksym()
- }
- typecheck.Init()
+ typecheck.InitUniverse()
- // Parse input.
- base.Timer.Start("fe", "parse")
- lines := noder.ParseFiles(flag.Args())
- ssagen.CgoSymABIs()
- base.Timer.Stop()
- base.Timer.AddEvent(int64(lines), "lines")
- if base.Flag.G != 0 && base.Flag.G < 3 {
- // can only parse generic code for now
- base.ExitIfErrors()
- return
- }
+ // Parse and typecheck input.
+ noder.LoadPackage(flag.Args())
dwarfgen.RecordPackageName()
-
- // Typecheck.
- typecheck.Package()
-
- // With all user code typechecked, it's now safe to verify unused dot imports.
- noder.CheckDotImports()
- base.ExitIfErrors()
+ ssagen.CgoSymABIs()
// Build init task.
if initTask := pkginit.Task(); initTask != nil {
typecheck.Export(initTask)
}
+ // Eliminate some obviously dead code.
+ // Must happen after typechecking.
+ for _, n := range typecheck.Target.Decls {
+ if n.Op() == ir.ODCLFUNC {
+ deadcode.Func(n.(*ir.Func))
+ }
+ }
+
+ // Compute Addrtaken for names.
+ // We need to wait until typechecking is done so that when we see &x[i]
+ // we know that x has its address taken if x is an array, but not if x is a slice.
+ // We compute Addrtaken in bulk here.
+ // After this phase, we maintain Addrtaken incrementally.
+ if typecheck.DirtyAddrtaken {
+ typecheck.ComputeAddrtaken(typecheck.Target.Decls)
+ typecheck.DirtyAddrtaken = false
+ }
+ typecheck.IncrementalAddrtaken = true
+
+ // Decide how to capture closed variables.
+ // This needs to run before escape analysis,
+ // because variables captured by value do not escape.
+ base.Timer.Start("fe", "capturevars")
+ for _, n := range typecheck.Target.Decls {
+ if n.Op() == ir.ODCLFUNC {
+ n := n.(*ir.Func)
+ if n.OClosure != nil {
+ ir.CurFunc = n
+ typecheck.CaptureVars(n)
+ }
+ }
+ }
+ typecheck.CaptureVarsComplete = true
+ ir.CurFunc = nil
+
+ if base.Debug.TypecheckInl != 0 {
+ // Typecheck imported function bodies if Debug.l > 1,
+ // otherwise lazily when used or re-exported.
+ typecheck.AllImportedBodies()
+ }
+
// Inlining
base.Timer.Start("fe", "inlining")
if base.Flag.LowerL != 0 {
@@ -285,6 +304,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
// Prepare for SSA compilation.
// This must be before peekitabs, because peekitabs
// can trigger function compilation.
+ typecheck.InitRuntime()
ssagen.InitConfig()
// Just before compilation, compile itabs found on
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 0ab3a8dad4..fbb2145e1b 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -148,8 +148,8 @@ func dumpdata() {
dumpglobls(typecheck.Target.Externs[numExterns:])
if reflectdata.ZeroSize > 0 {
- zero := ir.Pkgs.Map.Lookup("zero")
- objw.Global(zero.Linksym(), int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
+ zero := ir.Pkgs.Map.Lookup("zero").Linksym()
+ objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
}
addGCLocals()
@@ -188,7 +188,7 @@ func dumpGlobal(n *ir.Name) {
if n.Type() == nil {
base.Fatalf("external %v nil type\n", n)
}
- if n.Class_ == ir.PFUNC {
+ if n.Class == ir.PFUNC {
return
}
if n.Sym().Pkg != types.LocalPkg {
@@ -260,18 +260,18 @@ func addGCLocals() {
}
}
-func ggloblnod(nam ir.Node) {
- s := nam.Sym().Linksym()
- s.Gotype = reflectdata.TypeSym(nam.Type()).Linksym()
+func ggloblnod(nam *ir.Name) {
+ s := nam.Linksym()
+ s.Gotype = reflectdata.TypeLinksym(nam.Type())
flags := 0
- if nam.Name().Readonly() {
+ if nam.Readonly() {
flags = obj.RODATA
}
if nam.Type() != nil && !nam.Type().HasPointers() {
flags |= obj.NOPTR
}
base.Ctxt.Globl(s, nam.Type().Width, flags)
- if nam.Name().LibfuzzerExtraCounter() {
+ if nam.LibfuzzerExtraCounter() {
s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
}
if nam.Sym().Linkname != "" {
diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go
index 67162771e9..6f5f6499ce 100644
--- a/src/cmd/compile/internal/inline/inl.go
+++ b/src/cmd/compile/internal/inline/inl.go
@@ -199,8 +199,8 @@ func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) {
if n == nil {
return
}
- if n.Op() != ir.ONAME || n.Class_ != ir.PFUNC {
- base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op(), n.Class_)
+ if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
+ base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op(), n.Class)
}
fn := n.Func
if fn == nil {
@@ -227,7 +227,7 @@ func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) {
case ir.ONAME:
n := n.(*ir.Name)
- switch n.Class_ {
+ switch n.Class {
case ir.PFUNC:
Inline_Flood(n, exportsym)
exportsym(n)
@@ -265,7 +265,7 @@ var errBudget = errors.New("too expensive")
func (v *hairyVisitor) tooHairy(fn *ir.Func) bool {
v.do = v.doNode // cache closure
- err := ir.DoChildren(fn, v.do)
+ err := errChildren(fn, v.do)
if err != nil {
v.reason = err.Error()
return true
@@ -292,7 +292,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
// runtime.throw is a "cheap call" like panic in normal code.
if n.X.Op() == ir.ONAME {
name := n.X.(*ir.Name)
- if name.Class_ == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
+ if name.Class == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
fn := name.Sym().Name
if fn == "getcallerpc" || fn == "getcallersp" {
return errors.New("call to " + fn)
@@ -393,13 +393,13 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
if ir.IsConst(n.Cond, constant.Bool) {
// This if and the condition cost nothing.
// TODO(rsc): It seems strange that we visit the dead branch.
- if err := ir.DoList(n.Init(), v.do); err != nil {
+ if err := errList(n.Init(), v.do); err != nil {
return err
}
- if err := ir.DoList(n.Body, v.do); err != nil {
+ if err := errList(n.Body, v.do); err != nil {
return err
}
- if err := ir.DoList(n.Else, v.do); err != nil {
+ if err := errList(n.Else, v.do); err != nil {
return err
}
return nil
@@ -407,7 +407,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
case ir.ONAME:
n := n.(*ir.Name)
- if n.Class_ == ir.PAUTO {
+ if n.Class == ir.PAUTO {
v.usedLocals[n] = true
}
@@ -419,6 +419,9 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
case ir.OCALLPART, ir.OSLICELIT:
v.budget-- // Hack for toolstash -cmp.
+
+ case ir.OMETHEXPR:
+ v.budget++ // Hack for toolstash -cmp.
}
v.budget--
@@ -428,7 +431,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
return errBudget
}
- return ir.DoChildren(n, v.do)
+ return errChildren(n, v.do)
}
func isBigFunc(fn *ir.Func) bool {
@@ -541,7 +544,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
if as := n; as.Op() == ir.OAS2FUNC {
as := as.(*ir.AssignListStmt)
if as.Rhs[0].Op() == ir.OINLCALL {
- as.Rhs.Set(inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr)))
+ as.Rhs = inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr))
as.SetOp(ir.OAS2)
as.SetTypecheck(0)
n = typecheck.Stmt(as)
@@ -613,18 +616,18 @@ func inlCallee(fn ir.Node) *ir.Func {
fn = ir.StaticValue(fn)
switch fn.Op() {
case ir.OMETHEXPR:
- fn := fn.(*ir.MethodExpr)
+ fn := fn.(*ir.SelectorExpr)
n := ir.MethodExprName(fn)
- // Check that receiver type matches fn.Left.
+ // Check that receiver type matches fn.X.
// TODO(mdempsky): Handle implicit dereference
// of pointer receiver argument?
- if n == nil || !types.Identical(n.Type().Recv().Type, fn.T) {
+ if n == nil || !types.Identical(n.Type().Recv().Type, fn.X.Type()) {
return nil
}
return n.Func
case ir.ONAME:
fn := fn.(*ir.Name)
- if fn.Class_ == ir.PFUNC {
+ if fn.Class == ir.PFUNC {
return fn.Func
}
case ir.OCLOSURE:
@@ -636,13 +639,15 @@ func inlCallee(fn ir.Node) *ir.Func {
return nil
}
-func inlParam(t *types.Field, as ir.Node, inlvars map[*ir.Name]ir.Node) ir.Node {
- n := ir.AsNode(t.Nname)
- if n == nil || ir.IsBlank(n) {
+func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
+ if t.Nname == nil {
return ir.BlankNode
}
-
- inlvar := inlvars[n.(*ir.Name)]
+ n := t.Nname.(*ir.Name)
+ if ir.IsBlank(n) {
+ return ir.BlankNode
+ }
+ inlvar := inlvars[n]
if inlvar == nil {
base.Fatalf("missing inlvar for %v", n)
}
@@ -736,7 +741,7 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
callee := n.X
for callee.Op() == ir.OCONVNOP {
conv := callee.(*ir.ConvExpr)
- ninit.Append(conv.PtrInit().Take()...)
+ ninit.Append(ir.TakeInit(conv)...)
callee = conv.X
}
if callee.Op() != ir.ONAME && callee.Op() != ir.OCLOSURE && callee.Op() != ir.OMETHEXPR {
@@ -745,52 +750,16 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
}
// Make temp names to use instead of the originals.
- inlvars := make(map[*ir.Name]ir.Node)
+ inlvars := make(map[*ir.Name]*ir.Name)
// record formals/locals for later post-processing
- var inlfvars []ir.Node
-
- // Handle captured variables when inlining closures.
- if c := fn.OClosure; c != nil {
- for _, v := range fn.ClosureVars {
- if v.Op() == ir.OXXX {
- continue
- }
-
- o := v.Outer
- // make sure the outer param matches the inlining location
- // NB: if we enabled inlining of functions containing OCLOSURE or refined
- // the reassigned check via some sort of copy propagation this would most
- // likely need to be changed to a loop to walk up to the correct Param
- if o == nil || o.Curfn != ir.CurFunc {
- base.Fatalf("%v: unresolvable capture %v %v\n", ir.Line(n), fn, v)
- }
-
- if v.Byval() {
- iv := typecheck.Expr(inlvar(v))
- ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, iv))
- ninit.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, iv, o)))
- inlvars[v] = iv
- } else {
- addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
- addr.SetType(types.NewPtr(v.Type()))
- ia := typecheck.Expr(inlvar(addr))
- ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, ia))
- ninit.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, ia, typecheck.NodAddr(o))))
- inlvars[addr] = ia
-
- // When capturing by reference, all occurrence of the captured var
- // must be substituted with dereference of the temporary address
- inlvars[v] = typecheck.Expr(ir.NewStarExpr(base.Pos, ia))
- }
- }
- }
+ var inlfvars []*ir.Name
for _, ln := range fn.Inl.Dcl {
if ln.Op() != ir.ONAME {
continue
}
- if ln.Class_ == ir.PPARAMOUT { // return values handled below.
+ if ln.Class == ir.PPARAMOUT { // return values handled below.
continue
}
if ir.IsParamStackCopy(ln) { // ignore the on-stack copy of a parameter that moved to the heap
@@ -800,10 +769,10 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
// nothing should have moved to the heap yet.
base.Fatalf("impossible: %v", ln)
}
- inlf := typecheck.Expr(inlvar(ln))
+ inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
inlvars[ln] = inlf
if base.Flag.GenDwarfInl > 0 {
- if ln.Class_ == ir.PPARAM {
+ if ln.Class == ir.PPARAM {
inlf.Name().SetInlFormal(true)
} else {
inlf.Name().SetInlLocal(true)
@@ -828,11 +797,11 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
// temporaries for return values.
var retvars []ir.Node
for i, t := range fn.Type().Results().Fields().Slice() {
- var m ir.Node
- if n := ir.AsNode(t.Nname); n != nil && !ir.IsBlank(n) && !strings.HasPrefix(n.Sym().Name, "~r") {
- n := n.(*ir.Name)
+ var m *ir.Name
+ if nn := t.Nname; nn != nil && !ir.IsBlank(nn.(*ir.Name)) && !strings.HasPrefix(nn.Sym().Name, "~r") {
+ n := nn.(*ir.Name)
m = inlvar(n)
- m = typecheck.Expr(m)
+ m = typecheck.Expr(m).(*ir.Name)
inlvars[n] = m
delayretvars = false // found a named result parameter
} else {
@@ -897,8 +866,8 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
vas.Y = typecheck.NodNil()
vas.Y.SetType(param.Type)
} else {
- lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type).(ir.Ntype), nil)
- lit.List.Set(varargs)
+ lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type), nil)
+ lit.List = varargs
vas.Y = lit
}
}
@@ -914,7 +883,7 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
if !delayretvars {
// Zero the return parameters.
for _, n := range retvars {
- ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n))
+ ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
ras := ir.NewAssignStmt(base.Pos, n, nil)
ninit.Append(typecheck.Stmt(ras))
}
@@ -929,7 +898,7 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
parent = b.InliningIndex()
}
- sym := fn.Sym().Linksym()
+ sym := fn.Linksym()
newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
// Add an inline mark just before the inlined body.
@@ -975,9 +944,9 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
//dumplist("ninit post", ninit);
call := ir.NewInlinedCallExpr(base.Pos, nil, nil)
- call.PtrInit().Set(ninit)
- call.Body.Set(body)
- call.ReturnVars.Set(retvars)
+ *call.PtrInit() = ninit
+ call.Body = body
+ call.ReturnVars = retvars
call.SetType(n.Type())
call.SetTypecheck(1)
@@ -999,27 +968,27 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
// Every time we expand a function we generate a new set of tmpnames,
// PAUTO's in the calling functions, and link them off of the
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
-func inlvar(var_ ir.Node) ir.Node {
+func inlvar(var_ *ir.Name) *ir.Name {
if base.Flag.LowerM > 3 {
fmt.Printf("inlvar %+v\n", var_)
}
n := typecheck.NewName(var_.Sym())
n.SetType(var_.Type())
- n.Class_ = ir.PAUTO
+ n.Class = ir.PAUTO
n.SetUsed(true)
n.Curfn = ir.CurFunc // the calling function, not the called one
- n.SetAddrtaken(var_.Name().Addrtaken())
+ n.SetAddrtaken(var_.Addrtaken())
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
return n
}
// Synthesize a variable to store the inlined function's results in.
-func retvar(t *types.Field, i int) ir.Node {
+func retvar(t *types.Field, i int) *ir.Name {
n := typecheck.NewName(typecheck.LookupNum("~R", i))
n.SetType(t.Type)
- n.Class_ = ir.PAUTO
+ n.Class = ir.PAUTO
n.SetUsed(true)
n.Curfn = ir.CurFunc // the calling function, not the called one
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
@@ -1031,7 +1000,7 @@ func retvar(t *types.Field, i int) ir.Node {
func argvar(t *types.Type, i int) ir.Node {
n := typecheck.NewName(typecheck.LookupNum("~arg", i))
n.SetType(t.Elem())
- n.Class_ = ir.PAUTO
+ n.Class = ir.PAUTO
n.SetUsed(true)
n.Curfn = ir.CurFunc // the calling function, not the called one
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
@@ -1051,7 +1020,7 @@ type inlsubst struct {
// "return" statement.
delayretvars bool
- inlvars map[*ir.Name]ir.Node
+ inlvars map[*ir.Name]*ir.Name
// bases maps from original PosBase to PosBase with an extra
// inlined call frame.
@@ -1085,6 +1054,25 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
switch n.Op() {
case ir.ONAME:
n := n.(*ir.Name)
+
+ // Handle captured variables when inlining closures.
+ if n.IsClosureVar() {
+ o := n.Outer
+
+ // make sure the outer param matches the inlining location
+ // NB: if we enabled inlining of functions containing OCLOSURE or refined
+ // the reassigned check via some sort of copy propagation this would most
+ // likely need to be changed to a loop to walk up to the correct Param
+ if o == nil || o.Curfn != ir.CurFunc {
+ base.Fatalf("%v: unresolvable capture %v\n", ir.Line(n), n)
+ }
+
+ if base.Flag.LowerM > 2 {
+ fmt.Printf("substituting captured name %+v -> %+v\n", n, o)
+ }
+ return o
+ }
+
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
if base.Flag.LowerM > 2 {
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
@@ -1098,7 +1086,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
return n
case ir.OMETHEXPR:
- n := n.(*ir.MethodExpr)
+ n := n.(*ir.SelectorExpr)
return n
case ir.OLITERAL, ir.ONIL, ir.OTYPE:
@@ -1108,15 +1096,6 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
if n.Sym() != nil {
return n
}
- if n, ok := n.(*ir.Name); ok && n.Op() == ir.OLITERAL {
- // This happens for unnamed OLITERAL.
- // which should really not be a *Name, but for now it is.
- // ir.Copy(n) is not allowed generally and would panic below,
- // but it's OK in this situation.
- n = n.CloneName()
- n.SetPos(subst.updatedPos(n.Pos()))
- return n
- }
case ir.ORETURN:
// Since we don't handle bodies with closures,
@@ -1132,11 +1111,11 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
for _, n := range subst.retvars {
as.Lhs.Append(n)
}
- as.Rhs.Set(subst.list(n.Results))
+ as.Rhs = subst.list(n.Results)
if subst.delayretvars {
for _, n := range as.Lhs {
- as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
+ as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
n.Name().Defn = as
}
}
@@ -1151,7 +1130,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
n := n.(*ir.BranchStmt)
m := ir.Copy(n).(*ir.BranchStmt)
m.SetPos(subst.updatedPos(m.Pos()))
- m.PtrInit().Set(nil)
+ *m.PtrInit() = nil
p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
m.Label = typecheck.Lookup(p)
return m
@@ -1160,7 +1139,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
n := n.(*ir.LabelStmt)
m := ir.Copy(n).(*ir.LabelStmt)
m.SetPos(subst.updatedPos(m.Pos()))
- m.PtrInit().Set(nil)
+ *m.PtrInit() = nil
p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
m.Label = typecheck.Lookup(p)
return m
@@ -1191,7 +1170,7 @@ func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
s := make([]*ir.Name, 0, len(ll))
for _, n := range ll {
- if n.Class_ == ir.PAUTO {
+ if n.Class == ir.PAUTO {
if _, found := vis.usedLocals[n]; !found {
continue
}
@@ -1211,3 +1190,22 @@ func numNonClosures(list []*ir.Func) int {
}
return count
}
+
+// TODO(mdempsky): Update inl.go to use ir.DoChildren directly.
+func errChildren(n ir.Node, do func(ir.Node) error) (err error) {
+ ir.DoChildren(n, func(x ir.Node) bool {
+ err = do(x)
+ return err != nil
+ })
+ return
+}
+func errList(list []ir.Node, do func(ir.Node) error) error {
+ for _, x := range list {
+ if x != nil {
+ if err := do(x); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/src/cmd/compile/internal/ir/class_string.go b/src/cmd/compile/internal/ir/class_string.go
index 866bf1a6b5..13b9bd4812 100644
--- a/src/cmd/compile/internal/ir/class_string.go
+++ b/src/cmd/compile/internal/ir/class_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=Class"; DO NOT EDIT.
+// Code generated by "stringer -type=Class name.go"; DO NOT EDIT.
package ir
diff --git a/src/cmd/compile/internal/ir/copy.go b/src/cmd/compile/internal/ir/copy.go
index 0ab355f767..7da9b24940 100644
--- a/src/cmd/compile/internal/ir/copy.go
+++ b/src/cmd/compile/internal/ir/copy.go
@@ -25,6 +25,14 @@ type OrigNode interface {
SetOrig(Node)
}
+// origNode may be embedded into a Node to make it implement OrigNode.
+type origNode struct {
+ orig Node `mknode:"-"`
+}
+
+func (n *origNode) Orig() Node { return n.orig }
+func (n *origNode) SetOrig(o Node) { n.orig = o }
+
// Orig returns the “original” node for n.
// If n implements OrigNode, Orig returns n.Orig().
// Otherwise Orig returns n itself.
diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go
index 1337d356a1..e7aa9c6a8f 100644
--- a/src/cmd/compile/internal/ir/expr.go
+++ b/src/cmd/compile/internal/ir/expr.go
@@ -14,27 +14,6 @@ import (
"go/token"
)
-func maybeDo(x Node, err error, do func(Node) error) error {
- if x != nil && err == nil {
- err = do(x)
- }
- return err
-}
-
-func maybeDoList(x Nodes, err error, do func(Node) error) error {
- if err == nil {
- err = DoList(x, do)
- }
- return err
-}
-
-func maybeEdit(x Node, edit func(Node) Node) Node {
- if x == nil {
- return x
- }
- return edit(x)
-}
-
// An Expr is a Node that can appear as an expression.
type Expr interface {
Node
@@ -48,8 +27,7 @@ type Expr interface {
type miniExpr struct {
miniNode
typ *types.Type
- init Nodes // TODO(rsc): Don't require every Node to have an init
- opt interface{} // TODO(rsc): Don't require every Node to have an opt?
+ init Nodes // TODO(rsc): Don't require every Node to have an init
flags bitset8
}
@@ -59,14 +37,13 @@ const (
miniExprTransient
miniExprBounded
miniExprImplicit // for use by implementations; not supported by every Expr
+ miniExprCheckPtr
)
func (*miniExpr) isExpr() {}
func (n *miniExpr) Type() *types.Type { return n.typ }
func (n *miniExpr) SetType(x *types.Type) { n.typ = x }
-func (n *miniExpr) Opt() interface{} { return n.opt }
-func (n *miniExpr) SetOpt(x interface{}) { n.opt = x }
func (n *miniExpr) HasCall() bool { return n.flags&miniExprHasCall != 0 }
func (n *miniExpr) SetHasCall(b bool) { n.flags.set(miniExprHasCall, b) }
func (n *miniExpr) NonNil() bool { return n.flags&miniExprNonNil != 0 }
@@ -79,16 +56,6 @@ func (n *miniExpr) Init() Nodes { return n.init }
func (n *miniExpr) PtrInit() *Nodes { return &n.init }
func (n *miniExpr) SetInit(x Nodes) { n.init = x }
-func toNtype(x Node) Ntype {
- if x == nil {
- return nil
- }
- if _, ok := x.(Ntype); !ok {
- Dump("not Ntype", x)
- }
- return x.(Ntype)
-}
-
// An AddStringExpr is a string concatenation Expr[0] + Exprs[1] + ... + Expr[len(Expr)-1].
type AddStringExpr struct {
miniExpr
@@ -100,7 +67,7 @@ func NewAddStringExpr(pos src.XPos, list []Node) *AddStringExpr {
n := &AddStringExpr{}
n.pos = pos
n.op = OADDSTR
- n.List.Set(list)
+ n.List = list
return n
}
@@ -108,8 +75,8 @@ func NewAddStringExpr(pos src.XPos, list []Node) *AddStringExpr {
// It may end up being a normal address-of or an allocation of a composite literal.
type AddrExpr struct {
miniExpr
- X Node
- Alloc Node // preallocated storage if any
+ X Node
+ Prealloc *Name // preallocated storage if any
}
func NewAddrExpr(pos src.XPos, x Node) *AddrExpr {
@@ -191,14 +158,14 @@ const (
// A CallExpr is a function call X(Args).
type CallExpr struct {
miniExpr
- orig Node
- X Node
- Args Nodes
- Rargs Nodes // TODO(rsc): Delete.
- Body Nodes // TODO(rsc): Delete.
- IsDDD bool
- Use CallUse
- NoInline bool
+ origNode
+ X Node
+ Args Nodes
+ Rargs Nodes // TODO(rsc): Delete.
+ KeepAlive []*Name // vars to be kept alive until call returns
+ IsDDD bool
+ Use CallUse
+ NoInline bool
}
func NewCallExpr(pos src.XPos, op Op, fun Node, args []Node) *CallExpr {
@@ -206,15 +173,12 @@ func NewCallExpr(pos src.XPos, op Op, fun Node, args []Node) *CallExpr {
n.pos = pos
n.orig = n
n.SetOp(op)
- n.Args.Set(args)
+ n.Args = args
return n
}
func (*CallExpr) isStmt() {}
-func (n *CallExpr) Orig() Node { return n.orig }
-func (n *CallExpr) SetOrig(x Node) { n.orig = x }
-
func (n *CallExpr) SetOp(op Op) {
switch op {
default:
@@ -225,30 +189,10 @@ func (n *CallExpr) SetOp(op Op) {
}
}
-// A CallPartExpr is a method expression X.Method (uncalled).
-type CallPartExpr struct {
- miniExpr
- Func *Func
- X Node
- Method *types.Field
- Prealloc *Name
-}
-
-func NewCallPartExpr(pos src.XPos, x Node, method *types.Field, fn *Func) *CallPartExpr {
- n := &CallPartExpr{Func: fn, X: x, Method: method}
- n.op = OCALLPART
- n.pos = pos
- n.typ = fn.Type()
- n.Func = fn
- return n
-}
-
-func (n *CallPartExpr) Sym() *types.Sym { return n.Method.Sym }
-
// A ClosureExpr is a function literal expression.
type ClosureExpr struct {
miniExpr
- Func *Func
+ Func *Func `mknode:"-"`
Prealloc *Name
}
@@ -276,7 +220,7 @@ func NewClosureRead(typ *types.Type, offset int64) *ClosureReadExpr {
// Before type-checking, the type is Ntype.
type CompLitExpr struct {
miniExpr
- orig Node
+ origNode
Ntype Ntype
List Nodes // initialized values
Prealloc *Name
@@ -287,13 +231,11 @@ func NewCompLitExpr(pos src.XPos, op Op, typ Ntype, list []Node) *CompLitExpr {
n := &CompLitExpr{Ntype: typ}
n.pos = pos
n.SetOp(op)
- n.List.Set(list)
+ n.List = list
n.orig = n
return n
}
-func (n *CompLitExpr) Orig() Node { return n.orig }
-func (n *CompLitExpr) SetOrig(x Node) { n.orig = x }
func (n *CompLitExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }
func (n *CompLitExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
@@ -308,14 +250,15 @@ func (n *CompLitExpr) SetOp(op Op) {
type ConstExpr struct {
miniExpr
- val constant.Value
- orig Node
+ origNode
+ val constant.Value
}
func NewConstExpr(val constant.Value, orig Node) Node {
- n := &ConstExpr{orig: orig, val: val}
+ n := &ConstExpr{val: val}
n.op = OLITERAL
n.pos = orig.Pos()
+ n.orig = orig
n.SetType(orig.Type())
n.SetTypecheck(orig.Typecheck())
n.SetDiag(orig.Diag())
@@ -323,8 +266,6 @@ func NewConstExpr(val constant.Value, orig Node) Node {
}
func (n *ConstExpr) Sym() *types.Sym { return n.orig.Sym() }
-func (n *ConstExpr) Orig() Node { return n.orig }
-func (n *ConstExpr) SetOrig(orig Node) { panic(n.no("SetOrig")) }
func (n *ConstExpr) Val() constant.Value { return n.val }
// A ConvExpr is a conversion Type(X).
@@ -344,6 +285,8 @@ func NewConvExpr(pos src.XPos, op Op, typ *types.Type, x Node) *ConvExpr {
func (n *ConvExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }
func (n *ConvExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
+func (n *ConvExpr) CheckPtr() bool { return n.flags&miniExprCheckPtr != 0 }
+func (n *ConvExpr) SetCheckPtr(b bool) { n.flags.set(miniExprCheckPtr, b) }
func (n *ConvExpr) SetOp(op Op) {
switch op {
@@ -421,8 +364,8 @@ func NewInlinedCallExpr(pos src.XPos, body, retvars []Node) *InlinedCallExpr {
n := &InlinedCallExpr{}
n.pos = pos
n.op = OINLCALL
- n.Body.Set(body)
- n.ReturnVars.Set(retvars)
+ n.Body = body
+ n.ReturnVars = retvars
return n
}
@@ -476,24 +419,6 @@ func (n *MakeExpr) SetOp(op Op) {
}
}
-// A MethodExpr is a method expression T.M (where T is a type).
-type MethodExpr struct {
- miniExpr
- T *types.Type
- Method *types.Field
- FuncName_ *Name
-}
-
-func NewMethodExpr(pos src.XPos, t *types.Type, method *types.Field) *MethodExpr {
- n := &MethodExpr{T: t, Method: method}
- n.pos = pos
- n.op = OMETHEXPR
- return n
-}
-
-func (n *MethodExpr) FuncName() *Name { return n.FuncName_ }
-func (n *MethodExpr) Sym() *types.Sym { panic("MethodExpr.Sym") }
-
// A NilExpr represents the predefined untyped constant nil.
// (It may be copied and assigned a type, though.)
type NilExpr struct {
@@ -567,12 +492,13 @@ func NewNameOffsetExpr(pos src.XPos, name *Name, offset int64, typ *types.Type)
return n
}
-// A SelectorExpr is a selector expression X.Sym.
+// A SelectorExpr is a selector expression X.Sel.
type SelectorExpr struct {
miniExpr
X Node
Sel *types.Sym
Selection *types.Field
+ Prealloc *Name // preallocated storage for OCALLPART, if any
}
func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr {
@@ -586,7 +512,7 @@ func (n *SelectorExpr) SetOp(op Op) {
switch op {
default:
panic(n.no("SetOp " + op.String()))
- case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
+ case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OCALLPART, OMETHEXPR:
n.op = op
}
}
@@ -596,6 +522,16 @@ func (n *SelectorExpr) Implicit() bool { return n.flags&miniExprImplicit !=
func (n *SelectorExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
func (n *SelectorExpr) Offset() int64 { return n.Selection.Offset }
+func (n *SelectorExpr) FuncName() *Name {
+ if n.Op() != OMETHEXPR {
+ panic(n.no("FuncName"))
+ }
+ fn := NewNameAt(n.Selection.Pos, MethodSym(n.X.Type(), n.Sel))
+ fn.Class = PFUNC
+ fn.SetType(n.Type())
+ return fn
+}
+
// Before type-checking, bytes.Buffer is a SelectorExpr.
// After type-checking it becomes a Name.
func (*SelectorExpr) CanBeNtype() {}
@@ -687,8 +623,13 @@ func (n *StarExpr) SetOTYPE(t *types.Type) {
type TypeAssertExpr struct {
miniExpr
X Node
- Ntype Node // TODO: Should be Ntype, but reused as address of type structure
- Itab Nodes // Itab[0] is itab
+ Ntype Ntype
+
+ // Runtime type information provided by walkDotType.
+ // Caution: These aren't always populated; see walkDotType.
+ SrcType *AddrExpr `mknode:"-"` // *runtime._type for X's type
+ DstType *AddrExpr `mknode:"-"` // *runtime._type for Type
+ Itab *AddrExpr `mknode:"-"` // *runtime.itab for Type implementing X's type
}
func NewTypeAssertExpr(pos src.XPos, x Node, typ Ntype) *TypeAssertExpr {
@@ -795,7 +736,7 @@ func IsAddressable(n Node) bool {
case ONAME:
n := n.(*Name)
- if n.Class_ == PFUNC {
+ if n.Class == PFUNC {
return false
}
return true
@@ -830,11 +771,11 @@ func staticValue1(nn Node) Node {
return nil
}
n := nn.(*Name)
- if n.Class_ != PAUTO || n.Name().Addrtaken() {
+ if n.Class != PAUTO {
return nil
}
- defn := n.Name().Defn
+ defn := n.Defn
if defn == nil {
return nil
}
@@ -882,23 +823,46 @@ func reassigned(name *Name) bool {
if name.Curfn == nil {
return true
}
- return Any(name.Curfn, func(n Node) bool {
+
+ // TODO(mdempsky): This is inefficient and becoming increasingly
+ // unwieldy. Figure out a way to generalize escape analysis's
+ // reassignment detection for use by inlining and devirtualization.
+
+ // isName reports whether n is a reference to name.
+ isName := func(x Node) bool {
+ n, ok := x.(*Name)
+ return ok && n.Canonical() == name
+ }
+
+ var do func(n Node) bool
+ do = func(n Node) bool {
switch n.Op() {
case OAS:
n := n.(*AssignStmt)
- if n.X == name && n != name.Defn {
+ if isName(n.X) && n != name.Defn {
return true
}
case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV, OSELRECV2:
n := n.(*AssignListStmt)
for _, p := range n.Lhs {
- if p == name && n != name.Defn {
+ if isName(p) && n != name.Defn {
return true
}
}
+ case OADDR:
+ n := n.(*AddrExpr)
+ if isName(OuterValue(n.X)) {
+ return true
+ }
+ case OCLOSURE:
+ n := n.(*ClosureExpr)
+ if Any(n.Func, do) {
+ return true
+ }
}
return false
- })
+ }
+ return Any(name.Curfn, do)
}
// IsIntrinsicCall reports whether the compiler back end will treat the call as an intrinsic operation.
@@ -1089,13 +1053,8 @@ func MethodExprName(n Node) *Name {
// MethodFunc is like MethodName, but returns the types.Field instead.
func MethodExprFunc(n Node) *types.Field {
switch n.Op() {
- case ODOTMETH:
+ case ODOTMETH, OMETHEXPR, OCALLPART:
return n.(*SelectorExpr).Selection
- case OMETHEXPR:
- return n.(*MethodExpr).Method
- case OCALLPART:
- n := n.(*CallPartExpr)
- return n.Method
}
base.Fatalf("unexpected node: %v (%v)", n, n.Op())
panic("unreachable")
diff --git a/src/cmd/compile/internal/ir/fmt.go b/src/cmd/compile/internal/ir/fmt.go
index 49f451a5d8..a4e769f508 100644
--- a/src/cmd/compile/internal/ir/fmt.go
+++ b/src/cmd/compile/internal/ir/fmt.go
@@ -128,7 +128,7 @@ func (o Op) Format(s fmt.State, verb rune) {
// %L Go syntax followed by " (type T)" if type is known.
// %+v Debug syntax, as in Dump.
//
-func FmtNode(n Node, s fmt.State, verb rune) {
+func fmtNode(n Node, s fmt.State, verb rune) {
// %+v prints Dump.
// Otherwise we print Go syntax.
if s.Flag('+') && verb == 'v' {
@@ -216,6 +216,7 @@ var OpPrec = []int{
OTINTER: 8,
OTMAP: 8,
OTSTRUCT: 8,
+ OTYPE: 8,
OINDEXMAP: 8,
OINDEX: 8,
OSLICE: 8,
@@ -232,6 +233,7 @@ var OpPrec = []int{
ODOT: 8,
OXDOT: 8,
OCALLPART: 8,
+ OMETHEXPR: 8,
OPLUS: 7,
ONOT: 7,
OBITNOT: 7,
@@ -551,8 +553,8 @@ func exprFmt(n Node, s fmt.State, prec int) {
}
nprec := OpPrec[n.Op()]
- if n.Op() == OTYPE && n.Sym() != nil {
- nprec = 8
+ if n.Op() == OTYPE && n.Type().IsPtr() {
+ nprec = OpPrec[ODEREF]
}
if prec > nprec {
@@ -630,10 +632,6 @@ func exprFmt(n Node, s fmt.State, prec int) {
case OPACK, ONONAME:
fmt.Fprint(s, n.Sym())
- case OMETHEXPR:
- n := n.(*MethodExpr)
- fmt.Fprint(s, n.FuncName().Sym())
-
case ONAMEOFFSET:
n := n.(*NameOffsetExpr)
fmt.Fprintf(s, "(%v)(%v@%d)", n.Type(), n.Name_, n.Offset_)
@@ -749,16 +747,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
n := n.(*StructKeyExpr)
fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
- case OCALLPART:
- n := n.(*CallPartExpr)
- exprFmt(n.X, s, nprec)
- if n.Method.Sym == nil {
- fmt.Fprint(s, ".<nil>")
- return
- }
- fmt.Fprintf(s, ".%s", n.Method.Sym.Name)
-
- case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+ case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OCALLPART, OMETHEXPR:
n := n.(*SelectorExpr)
exprFmt(n.X, s, nprec)
if n.Sel == nil {
@@ -991,7 +980,7 @@ func (l Nodes) Format(s fmt.State, verb rune) {
// Dump prints the message s followed by a debug dump of n.
func Dump(s string, n Node) {
- fmt.Printf("%s [%p]%+v", s, n, n)
+ fmt.Printf("%s [%p]%+v\n", s, n, n)
}
// DumpList prints the message s followed by a debug dump of each node in the list.
@@ -1160,12 +1149,6 @@ func dumpNode(w io.Writer, n Node, depth int) {
}
return
- case OMETHEXPR:
- n := n.(*MethodExpr)
- fmt.Fprintf(w, "%+v-%+v", n.Op(), n.FuncName().Sym())
- dumpNodeHeader(w, n)
- return
-
case OASOP:
n := n.(*AssignOpStmt)
fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
@@ -1254,10 +1237,25 @@ func dumpNode(w io.Writer, n Node, depth int) {
fmt.Fprintf(w, "%+v-%s", n.Op(), name)
}
dumpNodes(w, val, depth+1)
+ default:
+ if vf.Kind() == reflect.Slice && vf.Type().Elem().Implements(nodeType) {
+ if vf.Len() == 0 {
+ continue
+ }
+ if name != "" {
+ indent(w, depth)
+ fmt.Fprintf(w, "%+v-%s", n.Op(), name)
+ }
+ for i, n := 0, vf.Len(); i < n; i++ {
+ dumpNode(w, vf.Index(i).Interface().(Node), depth+1)
+ }
+ }
}
}
}
+var nodeType = reflect.TypeOf((*Node)(nil)).Elem()
+
func dumpNodes(w io.Writer, list Nodes, depth int) {
if len(list) == 0 {
fmt.Fprintf(w, " <nil>")
diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go
index 16d67f6ae0..12ef083c19 100644
--- a/src/cmd/compile/internal/ir/func.go
+++ b/src/cmd/compile/internal/ir/func.go
@@ -49,7 +49,6 @@ import (
// pointer from the Func back to the OCALLPART.
type Func struct {
miniNode
- typ *types.Type
Body Nodes
Iota int64
@@ -66,9 +65,15 @@ type Func struct {
// include closurevars until transformclosure runs.
Dcl []*Name
- ClosureEnter Nodes // list of ONAME nodes (or OADDR-of-ONAME nodes, for output parameters) of captured variables
- ClosureType Node // closure representation type
- ClosureVars []*Name // closure params; each has closurevar set
+ ClosureType Ntype // closure representation type
+
+ // ClosureVars lists the free variables that are used within a
+ // function literal, but formally declared in an enclosing
+ // function. The variables in this slice are the closure function's
+ // own copy of the variables, which are used within its function
+ // body. They will also each have IsClosureVar set, and will have
+ // Byval set if they're captured by value.
+ ClosureVars []*Name
// Parents records the parent scope of each scope within a
// function. The root scope (0) has no parent, so the i'th
@@ -78,7 +83,7 @@ type Func struct {
// Marks records scope boundary changes.
Marks []Mark
- FieldTrack map[*types.Sym]struct{}
+ FieldTrack map[*obj.LSym]struct{}
DebugInfo interface{}
LSym *obj.LSym
@@ -116,15 +121,13 @@ func NewFunc(pos src.XPos) *Func {
func (f *Func) isStmt() {}
-func (f *Func) Type() *types.Type { return f.typ }
-func (f *Func) SetType(x *types.Type) { f.typ = x }
+func (n *Func) copy() Node { panic(n.no("copy")) }
+func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
+func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
-func (f *Func) Sym() *types.Sym {
- if f.Nname != nil {
- return f.Nname.Sym()
- }
- return nil
-}
+func (f *Func) Type() *types.Type { return f.Nname.Type() }
+func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
+func (f *Func) Linksym() *obj.LSym { return f.Nname.Linksym() }
// An Inline holds fields used for function bodies that can be inlined.
type Inline struct {
@@ -240,24 +243,13 @@ func FuncSymName(s *types.Sym) string {
return s.Name + "·f"
}
-// NewFuncNameAt generates a new name node for a function or method.
-func NewFuncNameAt(pos src.XPos, s *types.Sym, fn *Func) *Name {
- if fn.Nname != nil {
- base.Fatalf("newFuncName - already have name")
- }
- n := NewNameAt(pos, s)
- n.SetFunc(fn)
- fn.Nname = n
- return n
-}
-
// MarkFunc marks a node as a function.
func MarkFunc(n *Name) {
- if n.Op() != ONAME || n.Class_ != Pxxx {
+ if n.Op() != ONAME || n.Class != Pxxx {
base.Fatalf("expected ONAME/Pxxx node, got %v", n)
}
- n.Class_ = PFUNC
+ n.Class = PFUNC
n.Sym().SetFunc(true)
}
diff --git a/src/cmd/compile/internal/ir/mini.go b/src/cmd/compile/internal/ir/mini.go
index 53a63afe9b..4dd9a8807a 100644
--- a/src/cmd/compile/internal/ir/mini.go
+++ b/src/cmd/compile/internal/ir/mini.go
@@ -54,20 +54,13 @@ func (n *miniNode) Esc() uint16 { return n.esc }
func (n *miniNode) SetEsc(x uint16) { n.esc = x }
const (
- miniWalkdefShift = 0
+ miniWalkdefShift = 0 // TODO(mdempsky): Move to Name.flags.
miniTypecheckShift = 2
miniDiag = 1 << 4
miniHasCall = 1 << 5 // for miniStmt
)
-func (n *miniNode) Walkdef() uint8 { return n.bits.get2(miniWalkdefShift) }
func (n *miniNode) Typecheck() uint8 { return n.bits.get2(miniTypecheckShift) }
-func (n *miniNode) SetWalkdef(x uint8) {
- if x > 3 {
- panic(fmt.Sprintf("cannot SetWalkdef %d", x))
- }
- n.bits.set2(miniWalkdefShift, x)
-}
func (n *miniNode) SetTypecheck(x uint8) {
if x > 3 {
panic(fmt.Sprintf("cannot SetTypecheck %d", x))
@@ -80,13 +73,7 @@ func (n *miniNode) SetDiag(x bool) { n.bits.set(miniDiag, x) }
// Empty, immutable graph structure.
-func (n *miniNode) Init() Nodes { return Nodes{} }
-func (n *miniNode) PtrInit() *Nodes { return &immutableEmptyNodes }
-func (n *miniNode) SetInit(x Nodes) {
- if x != nil {
- panic(n.no("SetInit"))
- }
-}
+func (n *miniNode) Init() Nodes { return Nodes{} }
// Additional functionality unavailable.
@@ -102,5 +89,3 @@ func (n *miniNode) HasCall() bool { return false }
func (n *miniNode) SetHasCall(bool) { panic(n.no("SetHasCall")) }
func (n *miniNode) NonNil() bool { return false }
func (n *miniNode) MarkNonNil() { panic(n.no("MarkNonNil")) }
-func (n *miniNode) Opt() interface{} { return nil }
-func (n *miniNode) SetOpt(interface{}) { panic(n.no("SetOpt")) }
diff --git a/src/cmd/compile/internal/ir/mknode.go b/src/cmd/compile/internal/ir/mknode.go
index 3b5da32d8c..326f491a69 100644
--- a/src/cmd/compile/internal/ir/mknode.go
+++ b/src/cmd/compile/internal/ir/mknode.go
@@ -13,11 +13,16 @@ import (
"go/types"
"io/ioutil"
"log"
+ "reflect"
+ "sort"
"strings"
"golang.org/x/tools/go/packages"
)
+var irPkg *types.Package
+var buf bytes.Buffer
+
func main() {
cfg := &packages.Config{
Mode: packages.NeedSyntax | packages.NeedTypes,
@@ -26,116 +31,59 @@ func main() {
if err != nil {
log.Fatal(err)
}
+ irPkg = pkgs[0].Types
- pkg := pkgs[0].Types
- scope := pkg.Scope()
-
- lookup := func(name string) *types.Named {
- return scope.Lookup(name).(*types.TypeName).Type().(*types.Named)
- }
-
- nodeType := lookup("Node")
- ntypeType := lookup("Ntype")
- nodesType := lookup("Nodes")
- slicePtrCaseClauseType := types.NewSlice(types.NewPointer(lookup("CaseClause")))
- slicePtrCommClauseType := types.NewSlice(types.NewPointer(lookup("CommClause")))
- ptrFieldType := types.NewPointer(lookup("Field"))
- slicePtrFieldType := types.NewSlice(ptrFieldType)
- ptrIdentType := types.NewPointer(lookup("Ident"))
-
- var buf bytes.Buffer
fmt.Fprintln(&buf, "// Code generated by mknode.go. DO NOT EDIT.")
fmt.Fprintln(&buf)
fmt.Fprintln(&buf, "package ir")
fmt.Fprintln(&buf)
fmt.Fprintln(&buf, `import "fmt"`)
+ scope := irPkg.Scope()
for _, name := range scope.Names() {
- obj, ok := scope.Lookup(name).(*types.TypeName)
- if !ok {
+ if strings.HasPrefix(name, "mini") {
continue
}
- typName := obj.Name()
- typ, ok := obj.Type().(*types.Named).Underlying().(*types.Struct)
+ obj, ok := scope.Lookup(name).(*types.TypeName)
if !ok {
continue
}
-
- if strings.HasPrefix(typName, "mini") || !hasMiniNode(typ) {
+ typ := obj.Type().(*types.Named)
+ if !implementsNode(types.NewPointer(typ)) {
continue
}
fmt.Fprintf(&buf, "\n")
- fmt.Fprintf(&buf, "func (n *%s) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }\n", name)
+ fmt.Fprintf(&buf, "func (n *%s) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }\n", name)
switch name {
- case "Name":
- fmt.Fprintf(&buf, "func (n *%s) copy() Node {panic(\"%s.copy\")}\n", name, name)
- default:
- fmt.Fprintf(&buf, "func (n *%s) copy() Node { c := *n\n", name)
- forNodeFields(typName, typ, func(name string, is func(types.Type) bool) {
- switch {
- case is(nodesType):
- fmt.Fprintf(&buf, "c.%s = c.%s.Copy()\n", name, name)
- case is(slicePtrCaseClauseType):
- fmt.Fprintf(&buf, "c.%s = copyCases(c.%s)\n", name, name)
- case is(slicePtrCommClauseType):
- fmt.Fprintf(&buf, "c.%s = copyComms(c.%s)\n", name, name)
- case is(ptrFieldType):
- fmt.Fprintf(&buf, "if c.%s != nil { c.%s = c.%s.copy() }\n", name, name, name)
- case is(slicePtrFieldType):
- fmt.Fprintf(&buf, "c.%s = copyFields(c.%s)\n", name, name)
- }
- })
- fmt.Fprintf(&buf, "return &c }\n")
+ case "Name", "Func":
+ // Too specialized to automate.
+ continue
}
- fmt.Fprintf(&buf, "func (n *%s) doChildren(do func(Node) error) error { var err error\n", name)
- forNodeFields(typName, typ, func(name string, is func(types.Type) bool) {
- switch {
- case is(ptrIdentType):
- fmt.Fprintf(&buf, "if n.%s != nil { err = maybeDo(n.%s, err, do) }\n", name, name)
- case is(nodeType), is(ntypeType):
- fmt.Fprintf(&buf, "err = maybeDo(n.%s, err, do)\n", name)
- case is(nodesType):
- fmt.Fprintf(&buf, "err = maybeDoList(n.%s, err, do)\n", name)
- case is(slicePtrCaseClauseType):
- fmt.Fprintf(&buf, "err = maybeDoCases(n.%s, err, do)\n", name)
- case is(slicePtrCommClauseType):
- fmt.Fprintf(&buf, "err = maybeDoComms(n.%s, err, do)\n", name)
- case is(ptrFieldType):
- fmt.Fprintf(&buf, "err = maybeDoField(n.%s, err, do)\n", name)
- case is(slicePtrFieldType):
- fmt.Fprintf(&buf, "err = maybeDoFields(n.%s, err, do)\n", name)
- }
- })
- fmt.Fprintf(&buf, "return err }\n")
-
- fmt.Fprintf(&buf, "func (n *%s) editChildren(edit func(Node) Node) {\n", name)
- forNodeFields(typName, typ, func(name string, is func(types.Type) bool) {
- switch {
- case is(ptrIdentType):
- fmt.Fprintf(&buf, "if n.%s != nil { n.%s = edit(n.%s).(*Ident) }\n", name, name, name)
- case is(nodeType):
- fmt.Fprintf(&buf, "n.%s = maybeEdit(n.%s, edit)\n", name, name)
- case is(ntypeType):
- fmt.Fprintf(&buf, "n.%s = toNtype(maybeEdit(n.%s, edit))\n", name, name)
- case is(nodesType):
- fmt.Fprintf(&buf, "editList(n.%s, edit)\n", name)
- case is(slicePtrCaseClauseType):
- fmt.Fprintf(&buf, "editCases(n.%s, edit)\n", name)
- case is(slicePtrCommClauseType):
- fmt.Fprintf(&buf, "editComms(n.%s, edit)\n", name)
- case is(ptrFieldType):
- fmt.Fprintf(&buf, "editField(n.%s, edit)\n", name)
- case is(slicePtrFieldType):
- fmt.Fprintf(&buf, "editFields(n.%s, edit)\n", name)
- }
- })
- fmt.Fprintf(&buf, "}\n")
+ forNodeFields(typ,
+ "func (n *%[1]s) copy() Node { c := *n\n",
+ "",
+ "c.%[1]s = copy%[2]s(c.%[1]s)",
+ "return &c }\n")
+
+ forNodeFields(typ,
+ "func (n *%[1]s) doChildren(do func(Node) bool) bool {\n",
+ "if n.%[1]s != nil && do(n.%[1]s) { return true }",
+ "if do%[2]s(n.%[1]s, do) { return true }",
+ "return false }\n")
+
+ forNodeFields(typ,
+ "func (n *%[1]s) editChildren(edit func(Node) Node) {\n",
+ "if n.%[1]s != nil { n.%[1]s = edit(n.%[1]s).(%[2]s) }",
+ "edit%[2]s(n.%[1]s, edit)",
+ "}\n")
}
+ makeHelpers()
+
out, err := format.Source(buf.Bytes())
if err != nil {
// write out mangled source so we can see the bug.
@@ -148,40 +96,131 @@ func main() {
}
}
-func forNodeFields(typName string, typ *types.Struct, f func(name string, is func(types.Type) bool)) {
- for i, n := 0, typ.NumFields(); i < n; i++ {
- v := typ.Field(i)
- if v.Embedded() {
- if typ, ok := v.Type().Underlying().(*types.Struct); ok {
- forNodeFields(typName, typ, f)
- continue
- }
+// needHelper maps needed slice helpers from their base name to their
+// respective slice-element type.
+var needHelper = map[string]string{}
+
+func makeHelpers() {
+ var names []string
+ for name := range needHelper {
+ names = append(names, name)
+ }
+ sort.Strings(names)
+
+ for _, name := range names {
+ fmt.Fprintf(&buf, sliceHelperTmpl, name, needHelper[name])
+ }
+}
+
+const sliceHelperTmpl = `
+func copy%[1]s(list []%[2]s) []%[2]s {
+ if list == nil {
+ return nil
+ }
+ c := make([]%[2]s, len(list))
+ copy(c, list)
+ return c
+}
+func do%[1]s(list []%[2]s, do func(Node) bool) bool {
+ for _, x := range list {
+ if x != nil && do(x) {
+ return true
}
- switch typName {
- case "Func":
- if strings.ToLower(strings.TrimSuffix(v.Name(), "_")) != "body" {
- continue
+ }
+ return false
+}
+func edit%[1]s(list []%[2]s, edit func(Node) Node) {
+ for i, x := range list {
+ if x != nil {
+ list[i] = edit(x).(%[2]s)
+ }
+ }
+}
+`
+
+func forNodeFields(named *types.Named, prologue, singleTmpl, sliceTmpl, epilogue string) {
+ fmt.Fprintf(&buf, prologue, named.Obj().Name())
+
+ anyField(named.Underlying().(*types.Struct), func(f *types.Var) bool {
+ if f.Embedded() {
+ return false
+ }
+ name, typ := f.Name(), f.Type()
+
+ slice, _ := typ.Underlying().(*types.Slice)
+ if slice != nil {
+ typ = slice.Elem()
+ }
+
+ tmpl, what := singleTmpl, types.TypeString(typ, types.RelativeTo(irPkg))
+ if implementsNode(typ) {
+ if slice != nil {
+ helper := strings.TrimPrefix(what, "*") + "s"
+ needHelper[helper] = what
+ tmpl, what = sliceTmpl, helper
}
- case "Name":
- continue
+ } else if what == "*Field" {
+ // Special case for *Field.
+ tmpl = sliceTmpl
+ if slice != nil {
+ what = "Fields"
+ } else {
+ what = "Field"
+ }
+ } else {
+ return false
}
- switch v.Name() {
- case "orig":
- continue
+
+ if tmpl == "" {
+ return false
+ }
+
+ // Allow template to not use all arguments without
+ // upsetting fmt.Printf.
+ s := fmt.Sprintf(tmpl+"\x00 %[1]s %[2]s", name, what)
+ fmt.Fprintln(&buf, s[:strings.LastIndex(s, "\x00")])
+ return false
+ })
+
+ fmt.Fprintf(&buf, epilogue)
+}
+
+func implementsNode(typ types.Type) bool {
+ if _, ok := typ.Underlying().(*types.Interface); ok {
+ // TODO(mdempsky): Check the interface implements Node.
+ // Worst case, node_gen.go will fail to compile if we're wrong.
+ return true
+ }
+
+ if ptr, ok := typ.(*types.Pointer); ok {
+ if str, ok := ptr.Elem().Underlying().(*types.Struct); ok {
+ return anyField(str, func(f *types.Var) bool {
+ return f.Embedded() && f.Name() == "miniNode"
+ })
}
- f(v.Name(), func(t types.Type) bool { return types.Identical(t, v.Type()) })
}
+
+ return false
}
-func hasMiniNode(typ *types.Struct) bool {
+func anyField(typ *types.Struct, pred func(f *types.Var) bool) bool {
for i, n := 0, typ.NumFields(); i < n; i++ {
- v := typ.Field(i)
- if v.Name() == "miniNode" {
+ if value, ok := reflect.StructTag(typ.Tag(i)).Lookup("mknode"); ok {
+ if value != "-" {
+ panic(fmt.Sprintf("unexpected tag value: %q", value))
+ }
+ continue
+ }
+
+ f := typ.Field(i)
+ if pred(f) {
return true
}
- if v.Embedded() {
- if typ, ok := v.Type().Underlying().(*types.Struct); ok && hasMiniNode(typ) {
- return true
+ if f.Embedded() {
+ if typ, ok := f.Type().Underlying().(*types.Struct); ok {
+ if anyField(typ, pred) {
+ return true
+ }
}
}
}
diff --git a/src/cmd/compile/internal/ir/name.go b/src/cmd/compile/internal/ir/name.go
index cc8e1b4cd1..9d7d376ba5 100644
--- a/src/cmd/compile/internal/ir/name.go
+++ b/src/cmd/compile/internal/ir/name.go
@@ -7,8 +7,10 @@ package ir
import (
"cmd/compile/internal/base"
"cmd/compile/internal/types"
+ "cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/src"
+ "fmt"
"go/constant"
)
@@ -34,16 +36,16 @@ func (*Ident) CanBeNtype() {}
// Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL).
type Name struct {
miniExpr
- BuiltinOp Op // uint8
- Class_ Class // uint8
- flags bitset16
+ BuiltinOp Op // uint8
+ Class Class // uint8
pragma PragmaFlag // int16
+ flags bitset16
sym *types.Sym
Func *Func
Offset_ int64
val constant.Value
- orig Node
- Embed *[]Embed // list of embedded files, for ONAME var
+ Opt interface{} // for use by escape analysis
+ Embed *[]Embed // list of embedded files, for ONAME var
PkgName *PkgName // real package for import . names
// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
@@ -141,11 +143,9 @@ type Name struct {
func (n *Name) isExpr() {}
-// CloneName makes a cloned copy of the name.
-// It's not ir.Copy(n) because in general that operation is a mistake on names,
-// which uniquely identify variables.
-// Callers must use n.CloneName to make clear they intend to create a separate name.
-func (n *Name) CloneName() *Name { c := *n; return &c }
+func (n *Name) copy() Node { panic(n.no("copy")) }
+func (n *Name) doChildren(do func(Node) bool) bool { return false }
+func (n *Name) editChildren(edit func(Node) Node) {}
// TypeDefn returns the type definition for a named OTYPE.
// That is, given "type T Defn", it returns Defn.
@@ -213,7 +213,6 @@ func newNameAt(pos src.XPos, op Op, sym *types.Sym) *Name {
n := new(Name)
n.op = op
n.pos = pos
- n.orig = n
n.sym = sym
return n
}
@@ -223,8 +222,6 @@ func (n *Name) Sym() *types.Sym { return n.sym }
func (n *Name) SetSym(x *types.Sym) { n.sym = x }
func (n *Name) SubOp() Op { return n.BuiltinOp }
func (n *Name) SetSubOp(x Op) { n.BuiltinOp = x }
-func (n *Name) Class() Class { return n.Class_ }
-func (n *Name) SetClass(x Class) { n.Class_ = x }
func (n *Name) SetFunc(x *Func) { n.Func = x }
func (n *Name) Offset() int64 { panic("Name.Offset") }
func (n *Name) SetOffset(x int64) {
@@ -236,6 +233,15 @@ func (n *Name) FrameOffset() int64 { return n.Offset_ }
func (n *Name) SetFrameOffset(x int64) { n.Offset_ = x }
func (n *Name) Iota() int64 { return n.Offset_ }
func (n *Name) SetIota(x int64) { n.Offset_ = x }
+func (n *Name) Walkdef() uint8 { return n.bits.get2(miniWalkdefShift) }
+func (n *Name) SetWalkdef(x uint8) {
+ if x > 3 {
+ panic(fmt.Sprintf("cannot SetWalkdef %d", x))
+ }
+ n.bits.set2(miniWalkdefShift, x)
+}
+
+func (n *Name) Linksym() *obj.LSym { return n.sym.Linksym() }
func (*Name) CanBeNtype() {}
func (*Name) CanBeAnSSASym() {}
@@ -273,7 +279,6 @@ const (
func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 }
func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 }
-func (n *Name) Byval() bool { return n.flags&nameByval != 0 }
func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 }
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
func (n *Name) Used() bool { return n.flags&nameUsed != 0 }
@@ -288,7 +293,6 @@ func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraC
func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) }
func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) }
-func (n *Name) SetByval(b bool) { n.flags.set(nameByval, b) }
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
@@ -306,11 +310,11 @@ func (n *Name) MarkReadonly() {
if n.Op() != ONAME {
base.Fatalf("Node.MarkReadonly %v", n.Op())
}
- n.Name().setReadonly(true)
+ n.setReadonly(true)
// Mark the linksym as readonly immediately
// so that the SSA backend can use this information.
// It will be overridden later during dumpglobls.
- n.Sym().Linksym().Type = objabi.SRODATA
+ n.Linksym().Type = objabi.SRODATA
}
// Val returns the constant.Value for the node.
@@ -321,8 +325,7 @@ func (n *Name) Val() constant.Value {
return n.val
}
-// SetVal sets the constant.Value for the node,
-// which must not have been used with SetOpt.
+// SetVal sets the constant.Value for the node.
func (n *Name) SetVal(v constant.Value) {
if n.op != OLITERAL {
panic(n.no("SetVal"))
@@ -331,6 +334,33 @@ func (n *Name) SetVal(v constant.Value) {
n.val = v
}
+// Canonical returns the logical declaration that n represents. If n
+// is a closure variable, then Canonical returns the original Name as
+// it appears in the function that immediately contains the
+// declaration. Otherwise, Canonical simply returns n itself.
+func (n *Name) Canonical() *Name {
+ if n.IsClosureVar() {
+ n = n.Defn.(*Name)
+ if n.IsClosureVar() {
+ base.Fatalf("recursive closure variable: %v", n)
+ }
+ }
+ return n
+}
+
+func (n *Name) SetByval(b bool) {
+ if n.Canonical() != n {
+ base.Fatalf("SetByval called on non-canonical variable: %v", n)
+ }
+ n.flags.set(nameByval, b)
+}
+
+func (n *Name) Byval() bool {
+ // We require byval to be set on the canonical variable, but we
+ // allow it to be accessed from any instance.
+ return n.Canonical().flags&nameByval != 0
+}
+
// SameSource reports whether two nodes refer to the same source
// element.
//
@@ -373,7 +403,7 @@ func DeclaredBy(x, stmt Node) bool {
// called declaration contexts.
type Class uint8
-//go:generate stringer -type=Class
+//go:generate stringer -type=Class name.go
const (
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
PEXTERN // global variables
@@ -418,7 +448,7 @@ func IsParamStackCopy(n Node) bool {
return false
}
name := n.(*Name)
- return (name.Class_ == PPARAM || name.Class_ == PPARAMOUT) && name.Heapaddr != nil
+ return (name.Class == PPARAM || name.Class == PPARAMOUT) && name.Heapaddr != nil
}
// IsParamHeapCopy reports whether this is the on-heap copy of
@@ -428,7 +458,7 @@ func IsParamHeapCopy(n Node) bool {
return false
}
name := n.(*Name)
- return name.Class_ == PAUTOHEAP && name.Name().Stackcopy != nil
+ return name.Class == PAUTOHEAP && name.Stackcopy != nil
}
var RegFP *Name
diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go
index b4a557f290..850d7343aa 100644
--- a/src/cmd/compile/internal/ir/node.go
+++ b/src/cmd/compile/internal/ir/node.go
@@ -28,14 +28,12 @@ type Node interface {
// For making copies. For Copy and SepCopy.
copy() Node
- doChildren(func(Node) error) error
+ doChildren(func(Node) bool) bool
editChildren(func(Node) Node)
// Abstract graph structure, for generic traversals.
Op() Op
Init() Nodes
- PtrInit() *Nodes
- SetInit(x Nodes)
// Fields specific to certain Ops only.
Type() *types.Type
@@ -48,10 +46,6 @@ type Node interface {
// Storage for analysis passes.
Esc() uint16
SetEsc(x uint16)
- Walkdef() uint8
- SetWalkdef(x uint8)
- Opt() interface{}
- SetOpt(x interface{})
Diag() bool
SetDiag(x bool)
Typecheck() uint8
@@ -92,7 +86,21 @@ func MayBeShared(n Node) bool {
return false
}
-//go:generate stringer -type=Op -trimprefix=O
+type InitNode interface {
+ Node
+ PtrInit() *Nodes
+ SetInit(x Nodes)
+}
+
+func TakeInit(n Node) Nodes {
+ init := n.Init()
+ if len(init) != 0 {
+ n.(InitNode).SetInit(nil)
+ }
+ return init
+}
+
+//go:generate stringer -type=Op -trimprefix=O node.go
type Op uint8
@@ -220,10 +228,10 @@ const (
OPAREN // (Left)
OSEND // Left <- Right
OSLICE // Left[List[0] : List[1]] (Left is untypechecked or slice)
- OSLICEARR // Left[List[0] : List[1]] (Left is array)
+ OSLICEARR // Left[List[0] : List[1]] (Left is pointer to array)
OSLICESTR // Left[List[0] : List[1]] (Left is string)
OSLICE3 // Left[List[0] : List[1] : List[2]] (Left is untypedchecked or slice)
- OSLICE3ARR // Left[List[0] : List[1] : List[2]] (Left is array)
+ OSLICE3ARR // Left[List[0] : List[1] : List[2]] (Left is pointer to array)
OSLICEHEADER // sliceheader{Left, List[0], List[1]} (Left is unsafe.Pointer, List[0] is length, List[1] is capacity)
ORECOVER // recover()
ORECV // <-Left
@@ -313,35 +321,11 @@ const (
// a slice to save space.
type Nodes []Node
-// immutableEmptyNodes is an immutable, empty Nodes list.
-// The methods that would modify it panic instead.
-var immutableEmptyNodes = Nodes{}
-
-func (n *Nodes) mutate() {
- if n == &immutableEmptyNodes {
- panic("immutable Nodes.Set")
- }
-}
-
-// Set sets n to a slice.
-// This takes ownership of the slice.
-func (n *Nodes) Set(s []Node) {
- if n == &immutableEmptyNodes {
- if len(s) == 0 {
- // Allow immutableEmptyNodes.Set(nil) (a no-op).
- return
- }
- n.mutate()
- }
- *n = s
-}
-
// Append appends entries to Nodes.
func (n *Nodes) Append(a ...Node) {
if len(a) == 0 {
return
}
- n.mutate()
*n = append(*n, a...)
}
@@ -351,7 +335,6 @@ func (n *Nodes) Prepend(a ...Node) {
if len(a) == 0 {
return
}
- n.mutate()
*n = append(a, *n...)
}
@@ -546,15 +529,16 @@ func SetPos(n Node) src.XPos {
// The result of InitExpr MUST be assigned back to n, e.g.
// n.Left = InitExpr(init, n.Left)
-func InitExpr(init []Node, n Node) Node {
+func InitExpr(init []Node, expr Node) Node {
if len(init) == 0 {
- return n
+ return expr
}
- if MayBeShared(n) {
+
+ n, ok := expr.(InitNode)
+ if !ok || MayBeShared(n) {
// Introduce OCONVNOP to hold init list.
- old := n
- n = NewConvExpr(base.Pos, OCONVNOP, nil, old)
- n.SetType(old.Type())
+ n = NewConvExpr(base.Pos, OCONVNOP, nil, expr)
+ n.SetType(expr.Type())
n.SetTypecheck(1)
}
@@ -584,7 +568,10 @@ func OuterValue(n Node) Node {
continue
case OINDEX:
nn := nn.(*IndexExpr)
- if nn.X.Type() != nil && nn.X.Type().IsArray() {
+ if nn.X.Type() == nil {
+ base.Fatalf("OuterValue needs type for %v", nn.X)
+ }
+ if nn.X.Type().IsArray() {
n = nn.X
continue
}
diff --git a/src/cmd/compile/internal/ir/node_gen.go b/src/cmd/compile/internal/ir/node_gen.go
index 27a5311748..7f494b16cd 100644
--- a/src/cmd/compile/internal/ir/node_gen.go
+++ b/src/cmd/compile/internal/ir/node_gen.go
@@ -4,437 +4,545 @@ package ir
import "fmt"
-func (n *AddStringExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *AddStringExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *AddStringExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.List = c.List.Copy()
+ c.init = copyNodes(c.init)
+ c.List = copyNodes(c.List)
return &c
}
-func (n *AddStringExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDoList(n.List, err, do)
- return err
+func (n *AddStringExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if doNodes(n.List, do) {
+ return true
+ }
+ if n.Prealloc != nil && do(n.Prealloc) {
+ return true
+ }
+ return false
}
func (n *AddStringExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- editList(n.List, edit)
+ editNodes(n.init, edit)
+ editNodes(n.List, edit)
+ if n.Prealloc != nil {
+ n.Prealloc = edit(n.Prealloc).(*Name)
+ }
}
-func (n *AddrExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *AddrExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *AddrExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *AddrExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Alloc, err, do)
- return err
+func (n *AddrExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Prealloc != nil && do(n.Prealloc) {
+ return true
+ }
+ return false
}
func (n *AddrExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Alloc = maybeEdit(n.Alloc, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Prealloc != nil {
+ n.Prealloc = edit(n.Prealloc).(*Name)
+ }
}
-func (n *ArrayType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ArrayType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ArrayType) copy() Node {
c := *n
return &c
}
-func (n *ArrayType) doChildren(do func(Node) error) error {
- var err error
- err = maybeDo(n.Len, err, do)
- err = maybeDo(n.Elem, err, do)
- return err
+func (n *ArrayType) doChildren(do func(Node) bool) bool {
+ if n.Len != nil && do(n.Len) {
+ return true
+ }
+ if n.Elem != nil && do(n.Elem) {
+ return true
+ }
+ return false
}
func (n *ArrayType) editChildren(edit func(Node) Node) {
- n.Len = maybeEdit(n.Len, edit)
- n.Elem = maybeEdit(n.Elem, edit)
+ if n.Len != nil {
+ n.Len = edit(n.Len).(Node)
+ }
+ if n.Elem != nil {
+ n.Elem = edit(n.Elem).(Ntype)
+ }
}
-func (n *AssignListStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *AssignListStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *AssignListStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Lhs = c.Lhs.Copy()
- c.Rhs = c.Rhs.Copy()
+ c.init = copyNodes(c.init)
+ c.Lhs = copyNodes(c.Lhs)
+ c.Rhs = copyNodes(c.Rhs)
return &c
}
-func (n *AssignListStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDoList(n.Lhs, err, do)
- err = maybeDoList(n.Rhs, err, do)
- return err
+func (n *AssignListStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if doNodes(n.Lhs, do) {
+ return true
+ }
+ if doNodes(n.Rhs, do) {
+ return true
+ }
+ return false
}
func (n *AssignListStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- editList(n.Lhs, edit)
- editList(n.Rhs, edit)
+ editNodes(n.init, edit)
+ editNodes(n.Lhs, edit)
+ editNodes(n.Rhs, edit)
}
-func (n *AssignOpStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *AssignOpStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *AssignOpStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *AssignOpStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Y, err, do)
- return err
+func (n *AssignOpStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Y != nil && do(n.Y) {
+ return true
+ }
+ return false
}
func (n *AssignOpStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Y = maybeEdit(n.Y, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Y != nil {
+ n.Y = edit(n.Y).(Node)
+ }
}
-func (n *AssignStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *AssignStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *AssignStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *AssignStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Y, err, do)
- return err
+func (n *AssignStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Y != nil && do(n.Y) {
+ return true
+ }
+ return false
}
func (n *AssignStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Y = maybeEdit(n.Y, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Y != nil {
+ n.Y = edit(n.Y).(Node)
+ }
}
-func (n *BasicLit) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *BasicLit) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *BasicLit) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *BasicLit) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *BasicLit) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *BasicLit) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *BinaryExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *BinaryExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *BinaryExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *BinaryExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Y, err, do)
- return err
+func (n *BinaryExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Y != nil && do(n.Y) {
+ return true
+ }
+ return false
}
func (n *BinaryExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Y = maybeEdit(n.Y, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Y != nil {
+ n.Y = edit(n.Y).(Node)
+ }
}
-func (n *BlockStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *BlockStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *BlockStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.List = c.List.Copy()
+ c.init = copyNodes(c.init)
+ c.List = copyNodes(c.List)
return &c
}
-func (n *BlockStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDoList(n.List, err, do)
- return err
+func (n *BlockStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if doNodes(n.List, do) {
+ return true
+ }
+ return false
}
func (n *BlockStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- editList(n.List, edit)
+ editNodes(n.init, edit)
+ editNodes(n.List, edit)
}
-func (n *BranchStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *BranchStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *BranchStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *BranchStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *BranchStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *BranchStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *CallExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *CallExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *CallExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Args = c.Args.Copy()
- c.Rargs = c.Rargs.Copy()
- c.Body = c.Body.Copy()
+ c.init = copyNodes(c.init)
+ c.Args = copyNodes(c.Args)
+ c.Rargs = copyNodes(c.Rargs)
+ c.KeepAlive = copyNames(c.KeepAlive)
return &c
}
-func (n *CallExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDoList(n.Args, err, do)
- err = maybeDoList(n.Rargs, err, do)
- err = maybeDoList(n.Body, err, do)
- return err
+func (n *CallExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if doNodes(n.Args, do) {
+ return true
+ }
+ if doNodes(n.Rargs, do) {
+ return true
+ }
+ if doNames(n.KeepAlive, do) {
+ return true
+ }
+ return false
}
func (n *CallExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- editList(n.Args, edit)
- editList(n.Rargs, edit)
- editList(n.Body, edit)
-}
-
-func (n *CallPartExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
-func (n *CallPartExpr) copy() Node {
- c := *n
- c.init = c.init.Copy()
- return &c
-}
-func (n *CallPartExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- return err
-}
-func (n *CallPartExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ editNodes(n.Args, edit)
+ editNodes(n.Rargs, edit)
+ editNames(n.KeepAlive, edit)
}
-func (n *CaseClause) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *CaseClause) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *CaseClause) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.List = c.List.Copy()
- c.Body = c.Body.Copy()
+ c.init = copyNodes(c.init)
+ c.List = copyNodes(c.List)
+ c.Body = copyNodes(c.Body)
return &c
}
-func (n *CaseClause) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Var, err, do)
- err = maybeDoList(n.List, err, do)
- err = maybeDoList(n.Body, err, do)
- return err
+func (n *CaseClause) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Var != nil && do(n.Var) {
+ return true
+ }
+ if doNodes(n.List, do) {
+ return true
+ }
+ if doNodes(n.Body, do) {
+ return true
+ }
+ return false
}
func (n *CaseClause) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Var = maybeEdit(n.Var, edit)
- editList(n.List, edit)
- editList(n.Body, edit)
+ editNodes(n.init, edit)
+ if n.Var != nil {
+ n.Var = edit(n.Var).(*Name)
+ }
+ editNodes(n.List, edit)
+ editNodes(n.Body, edit)
}
-func (n *ChanType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ChanType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ChanType) copy() Node {
c := *n
return &c
}
-func (n *ChanType) doChildren(do func(Node) error) error {
- var err error
- err = maybeDo(n.Elem, err, do)
- return err
+func (n *ChanType) doChildren(do func(Node) bool) bool {
+ if n.Elem != nil && do(n.Elem) {
+ return true
+ }
+ return false
}
func (n *ChanType) editChildren(edit func(Node) Node) {
- n.Elem = maybeEdit(n.Elem, edit)
+ if n.Elem != nil {
+ n.Elem = edit(n.Elem).(Ntype)
+ }
}
-func (n *ClosureExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ClosureExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ClosureExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *ClosureExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *ClosureExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Prealloc != nil && do(n.Prealloc) {
+ return true
+ }
+ return false
}
func (n *ClosureExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
+ if n.Prealloc != nil {
+ n.Prealloc = edit(n.Prealloc).(*Name)
+ }
}
-func (n *ClosureReadExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ClosureReadExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ClosureReadExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *ClosureReadExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *ClosureReadExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *ClosureReadExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *CommClause) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *CommClause) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *CommClause) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Body = c.Body.Copy()
+ c.init = copyNodes(c.init)
+ c.Body = copyNodes(c.Body)
return &c
}
-func (n *CommClause) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Comm, err, do)
- err = maybeDoList(n.Body, err, do)
- return err
+func (n *CommClause) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Comm != nil && do(n.Comm) {
+ return true
+ }
+ if doNodes(n.Body, do) {
+ return true
+ }
+ return false
}
func (n *CommClause) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Comm = maybeEdit(n.Comm, edit)
- editList(n.Body, edit)
+ editNodes(n.init, edit)
+ if n.Comm != nil {
+ n.Comm = edit(n.Comm).(Node)
+ }
+ editNodes(n.Body, edit)
}
-func (n *CompLitExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *CompLitExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *CompLitExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.List = c.List.Copy()
+ c.init = copyNodes(c.init)
+ c.List = copyNodes(c.List)
return &c
}
-func (n *CompLitExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Ntype, err, do)
- err = maybeDoList(n.List, err, do)
- return err
+func (n *CompLitExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Ntype != nil && do(n.Ntype) {
+ return true
+ }
+ if doNodes(n.List, do) {
+ return true
+ }
+ if n.Prealloc != nil && do(n.Prealloc) {
+ return true
+ }
+ return false
}
func (n *CompLitExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Ntype = toNtype(maybeEdit(n.Ntype, edit))
- editList(n.List, edit)
+ editNodes(n.init, edit)
+ if n.Ntype != nil {
+ n.Ntype = edit(n.Ntype).(Ntype)
+ }
+ editNodes(n.List, edit)
+ if n.Prealloc != nil {
+ n.Prealloc = edit(n.Prealloc).(*Name)
+ }
}
-func (n *ConstExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ConstExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ConstExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *ConstExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *ConstExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *ConstExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *ConvExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ConvExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ConvExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *ConvExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- return err
+func (n *ConvExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ return false
}
func (n *ConvExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
}
-func (n *Decl) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *Decl) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *Decl) copy() Node {
c := *n
return &c
}
-func (n *Decl) doChildren(do func(Node) error) error {
- var err error
- err = maybeDo(n.X, err, do)
- return err
+func (n *Decl) doChildren(do func(Node) bool) bool {
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ return false
}
func (n *Decl) editChildren(edit func(Node) Node) {
- n.X = maybeEdit(n.X, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(*Name)
+ }
}
-func (n *ForStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ForStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ForStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Late = c.Late.Copy()
- c.Body = c.Body.Copy()
+ c.init = copyNodes(c.init)
+ c.Late = copyNodes(c.Late)
+ c.Body = copyNodes(c.Body)
return &c
}
-func (n *ForStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Cond, err, do)
- err = maybeDoList(n.Late, err, do)
- err = maybeDo(n.Post, err, do)
- err = maybeDoList(n.Body, err, do)
- return err
+func (n *ForStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Cond != nil && do(n.Cond) {
+ return true
+ }
+ if doNodes(n.Late, do) {
+ return true
+ }
+ if n.Post != nil && do(n.Post) {
+ return true
+ }
+ if doNodes(n.Body, do) {
+ return true
+ }
+ return false
}
func (n *ForStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Cond = maybeEdit(n.Cond, edit)
- editList(n.Late, edit)
- n.Post = maybeEdit(n.Post, edit)
- editList(n.Body, edit)
+ editNodes(n.init, edit)
+ if n.Cond != nil {
+ n.Cond = edit(n.Cond).(Node)
+ }
+ editNodes(n.Late, edit)
+ if n.Post != nil {
+ n.Post = edit(n.Post).(Node)
+ }
+ editNodes(n.Body, edit)
}
-func (n *Func) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
-func (n *Func) copy() Node {
- c := *n
- c.Body = c.Body.Copy()
- return &c
-}
-func (n *Func) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.Body, err, do)
- return err
-}
-func (n *Func) editChildren(edit func(Node) Node) {
- editList(n.Body, edit)
-}
+func (n *Func) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
-func (n *FuncType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *FuncType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *FuncType) copy() Node {
c := *n
- if c.Recv != nil {
- c.Recv = c.Recv.copy()
- }
+ c.Recv = copyField(c.Recv)
c.Params = copyFields(c.Params)
c.Results = copyFields(c.Results)
return &c
}
-func (n *FuncType) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoField(n.Recv, err, do)
- err = maybeDoFields(n.Params, err, do)
- err = maybeDoFields(n.Results, err, do)
- return err
+func (n *FuncType) doChildren(do func(Node) bool) bool {
+ if doField(n.Recv, do) {
+ return true
+ }
+ if doFields(n.Params, do) {
+ return true
+ }
+ if doFields(n.Results, do) {
+ return true
+ }
+ return false
}
func (n *FuncType) editChildren(edit func(Node) Node) {
editField(n.Recv, edit)
@@ -442,613 +550,881 @@ func (n *FuncType) editChildren(edit func(Node) Node) {
editFields(n.Results, edit)
}
-func (n *GoDeferStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *GoDeferStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *GoDeferStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *GoDeferStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Call, err, do)
- return err
+func (n *GoDeferStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Call != nil && do(n.Call) {
+ return true
+ }
+ return false
}
func (n *GoDeferStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Call = maybeEdit(n.Call, edit)
+ editNodes(n.init, edit)
+ if n.Call != nil {
+ n.Call = edit(n.Call).(Node)
+ }
}
-func (n *Ident) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *Ident) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *Ident) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *Ident) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *Ident) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *Ident) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *IfStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *IfStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *IfStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Body = c.Body.Copy()
- c.Else = c.Else.Copy()
+ c.init = copyNodes(c.init)
+ c.Body = copyNodes(c.Body)
+ c.Else = copyNodes(c.Else)
return &c
}
-func (n *IfStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Cond, err, do)
- err = maybeDoList(n.Body, err, do)
- err = maybeDoList(n.Else, err, do)
- return err
+func (n *IfStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Cond != nil && do(n.Cond) {
+ return true
+ }
+ if doNodes(n.Body, do) {
+ return true
+ }
+ if doNodes(n.Else, do) {
+ return true
+ }
+ return false
}
func (n *IfStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Cond = maybeEdit(n.Cond, edit)
- editList(n.Body, edit)
- editList(n.Else, edit)
+ editNodes(n.init, edit)
+ if n.Cond != nil {
+ n.Cond = edit(n.Cond).(Node)
+ }
+ editNodes(n.Body, edit)
+ editNodes(n.Else, edit)
}
-func (n *IndexExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *IndexExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *IndexExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *IndexExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Index, err, do)
- return err
+func (n *IndexExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Index != nil && do(n.Index) {
+ return true
+ }
+ return false
}
func (n *IndexExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Index = maybeEdit(n.Index, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Index != nil {
+ n.Index = edit(n.Index).(Node)
+ }
}
-func (n *InlineMarkStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *InlineMarkStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *InlineMarkStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *InlineMarkStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *InlineMarkStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *InlineMarkStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *InlinedCallExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *InlinedCallExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *InlinedCallExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Body = c.Body.Copy()
- c.ReturnVars = c.ReturnVars.Copy()
+ c.init = copyNodes(c.init)
+ c.Body = copyNodes(c.Body)
+ c.ReturnVars = copyNodes(c.ReturnVars)
return &c
}
-func (n *InlinedCallExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDoList(n.Body, err, do)
- err = maybeDoList(n.ReturnVars, err, do)
- return err
+func (n *InlinedCallExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if doNodes(n.Body, do) {
+ return true
+ }
+ if doNodes(n.ReturnVars, do) {
+ return true
+ }
+ return false
}
func (n *InlinedCallExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- editList(n.Body, edit)
- editList(n.ReturnVars, edit)
+ editNodes(n.init, edit)
+ editNodes(n.Body, edit)
+ editNodes(n.ReturnVars, edit)
}
-func (n *InterfaceType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *InterfaceType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *InterfaceType) copy() Node {
c := *n
c.Methods = copyFields(c.Methods)
return &c
}
-func (n *InterfaceType) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoFields(n.Methods, err, do)
- return err
+func (n *InterfaceType) doChildren(do func(Node) bool) bool {
+ if doFields(n.Methods, do) {
+ return true
+ }
+ return false
}
func (n *InterfaceType) editChildren(edit func(Node) Node) {
editFields(n.Methods, edit)
}
-func (n *KeyExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *KeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *KeyExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *KeyExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Key, err, do)
- err = maybeDo(n.Value, err, do)
- return err
+func (n *KeyExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Key != nil && do(n.Key) {
+ return true
+ }
+ if n.Value != nil && do(n.Value) {
+ return true
+ }
+ return false
}
func (n *KeyExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Key = maybeEdit(n.Key, edit)
- n.Value = maybeEdit(n.Value, edit)
+ editNodes(n.init, edit)
+ if n.Key != nil {
+ n.Key = edit(n.Key).(Node)
+ }
+ if n.Value != nil {
+ n.Value = edit(n.Value).(Node)
+ }
}
-func (n *LabelStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *LabelStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *LabelStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *LabelStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *LabelStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *LabelStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *LogicalExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *LogicalExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *LogicalExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *LogicalExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Y, err, do)
- return err
+func (n *LogicalExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Y != nil && do(n.Y) {
+ return true
+ }
+ return false
}
func (n *LogicalExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Y = maybeEdit(n.Y, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Y != nil {
+ n.Y = edit(n.Y).(Node)
+ }
}
-func (n *MakeExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *MakeExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *MakeExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *MakeExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Len, err, do)
- err = maybeDo(n.Cap, err, do)
- return err
+func (n *MakeExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Len != nil && do(n.Len) {
+ return true
+ }
+ if n.Cap != nil && do(n.Cap) {
+ return true
+ }
+ return false
}
func (n *MakeExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Len = maybeEdit(n.Len, edit)
- n.Cap = maybeEdit(n.Cap, edit)
+ editNodes(n.init, edit)
+ if n.Len != nil {
+ n.Len = edit(n.Len).(Node)
+ }
+ if n.Cap != nil {
+ n.Cap = edit(n.Cap).(Node)
+ }
}
-func (n *MapType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *MapType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *MapType) copy() Node {
c := *n
return &c
}
-func (n *MapType) doChildren(do func(Node) error) error {
- var err error
- err = maybeDo(n.Key, err, do)
- err = maybeDo(n.Elem, err, do)
- return err
+func (n *MapType) doChildren(do func(Node) bool) bool {
+ if n.Key != nil && do(n.Key) {
+ return true
+ }
+ if n.Elem != nil && do(n.Elem) {
+ return true
+ }
+ return false
}
func (n *MapType) editChildren(edit func(Node) Node) {
- n.Key = maybeEdit(n.Key, edit)
- n.Elem = maybeEdit(n.Elem, edit)
-}
-
-func (n *MethodExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
-func (n *MethodExpr) copy() Node {
- c := *n
- c.init = c.init.Copy()
- return &c
-}
-func (n *MethodExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
-}
-func (n *MethodExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ if n.Key != nil {
+ n.Key = edit(n.Key).(Ntype)
+ }
+ if n.Elem != nil {
+ n.Elem = edit(n.Elem).(Ntype)
+ }
}
-func (n *Name) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
-func (n *Name) copy() Node { panic("Name.copy") }
-func (n *Name) doChildren(do func(Node) error) error {
- var err error
- return err
-}
-func (n *Name) editChildren(edit func(Node) Node) {
-}
+func (n *Name) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
-func (n *NameOffsetExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *NameOffsetExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *NameOffsetExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *NameOffsetExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *NameOffsetExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Name_ != nil && do(n.Name_) {
+ return true
+ }
+ return false
}
func (n *NameOffsetExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
+ if n.Name_ != nil {
+ n.Name_ = edit(n.Name_).(*Name)
+ }
}
-func (n *NilExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *NilExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *NilExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *NilExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *NilExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *NilExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *ParenExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ParenExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ParenExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *ParenExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- return err
+func (n *ParenExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ return false
}
func (n *ParenExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
}
-func (n *PkgName) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *PkgName) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *PkgName) copy() Node {
c := *n
return &c
}
-func (n *PkgName) doChildren(do func(Node) error) error {
- var err error
- return err
+func (n *PkgName) doChildren(do func(Node) bool) bool {
+ return false
}
func (n *PkgName) editChildren(edit func(Node) Node) {
}
-func (n *RangeStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *RangeStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *RangeStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Body = c.Body.Copy()
+ c.init = copyNodes(c.init)
+ c.Body = copyNodes(c.Body)
return &c
}
-func (n *RangeStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Key, err, do)
- err = maybeDo(n.Value, err, do)
- err = maybeDoList(n.Body, err, do)
- return err
+func (n *RangeStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Key != nil && do(n.Key) {
+ return true
+ }
+ if n.Value != nil && do(n.Value) {
+ return true
+ }
+ if doNodes(n.Body, do) {
+ return true
+ }
+ if n.Prealloc != nil && do(n.Prealloc) {
+ return true
+ }
+ return false
}
func (n *RangeStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Key = maybeEdit(n.Key, edit)
- n.Value = maybeEdit(n.Value, edit)
- editList(n.Body, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Key != nil {
+ n.Key = edit(n.Key).(Node)
+ }
+ if n.Value != nil {
+ n.Value = edit(n.Value).(Node)
+ }
+ editNodes(n.Body, edit)
+ if n.Prealloc != nil {
+ n.Prealloc = edit(n.Prealloc).(*Name)
+ }
}
-func (n *ResultExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ResultExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ResultExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *ResultExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- return err
+func (n *ResultExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ return false
}
func (n *ResultExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
+ editNodes(n.init, edit)
}
-func (n *ReturnStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *ReturnStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *ReturnStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Results = c.Results.Copy()
+ c.init = copyNodes(c.init)
+ c.Results = copyNodes(c.Results)
return &c
}
-func (n *ReturnStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDoList(n.Results, err, do)
- return err
+func (n *ReturnStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if doNodes(n.Results, do) {
+ return true
+ }
+ return false
}
func (n *ReturnStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- editList(n.Results, edit)
+ editNodes(n.init, edit)
+ editNodes(n.Results, edit)
}
-func (n *SelectStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SelectStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *SelectStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Cases = copyComms(c.Cases)
- c.Compiled = c.Compiled.Copy()
+ c.init = copyNodes(c.init)
+ c.Cases = copyCommClauses(c.Cases)
+ c.Compiled = copyNodes(c.Compiled)
return &c
}
-func (n *SelectStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDoComms(n.Cases, err, do)
- err = maybeDoList(n.Compiled, err, do)
- return err
+func (n *SelectStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if doCommClauses(n.Cases, do) {
+ return true
+ }
+ if doNodes(n.Compiled, do) {
+ return true
+ }
+ return false
}
func (n *SelectStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- editComms(n.Cases, edit)
- editList(n.Compiled, edit)
+ editNodes(n.init, edit)
+ editCommClauses(n.Cases, edit)
+ editNodes(n.Compiled, edit)
}
-func (n *SelectorExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SelectorExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *SelectorExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *SelectorExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- return err
+func (n *SelectorExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Prealloc != nil && do(n.Prealloc) {
+ return true
+ }
+ return false
}
func (n *SelectorExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Prealloc != nil {
+ n.Prealloc = edit(n.Prealloc).(*Name)
+ }
}
-func (n *SendStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SendStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *SendStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *SendStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Chan, err, do)
- err = maybeDo(n.Value, err, do)
- return err
+func (n *SendStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Chan != nil && do(n.Chan) {
+ return true
+ }
+ if n.Value != nil && do(n.Value) {
+ return true
+ }
+ return false
}
func (n *SendStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Chan = maybeEdit(n.Chan, edit)
- n.Value = maybeEdit(n.Value, edit)
+ editNodes(n.init, edit)
+ if n.Chan != nil {
+ n.Chan = edit(n.Chan).(Node)
+ }
+ if n.Value != nil {
+ n.Value = edit(n.Value).(Node)
+ }
}
-func (n *SliceExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SliceExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *SliceExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *SliceExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Low, err, do)
- err = maybeDo(n.High, err, do)
- err = maybeDo(n.Max, err, do)
- return err
+func (n *SliceExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Low != nil && do(n.Low) {
+ return true
+ }
+ if n.High != nil && do(n.High) {
+ return true
+ }
+ if n.Max != nil && do(n.Max) {
+ return true
+ }
+ return false
}
func (n *SliceExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Low = maybeEdit(n.Low, edit)
- n.High = maybeEdit(n.High, edit)
- n.Max = maybeEdit(n.Max, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Low != nil {
+ n.Low = edit(n.Low).(Node)
+ }
+ if n.High != nil {
+ n.High = edit(n.High).(Node)
+ }
+ if n.Max != nil {
+ n.Max = edit(n.Max).(Node)
+ }
}
-func (n *SliceHeaderExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SliceHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *SliceHeaderExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *SliceHeaderExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Ptr, err, do)
- err = maybeDo(n.Len, err, do)
- err = maybeDo(n.Cap, err, do)
- return err
+func (n *SliceHeaderExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Ptr != nil && do(n.Ptr) {
+ return true
+ }
+ if n.Len != nil && do(n.Len) {
+ return true
+ }
+ if n.Cap != nil && do(n.Cap) {
+ return true
+ }
+ return false
}
func (n *SliceHeaderExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Ptr = maybeEdit(n.Ptr, edit)
- n.Len = maybeEdit(n.Len, edit)
- n.Cap = maybeEdit(n.Cap, edit)
+ editNodes(n.init, edit)
+ if n.Ptr != nil {
+ n.Ptr = edit(n.Ptr).(Node)
+ }
+ if n.Len != nil {
+ n.Len = edit(n.Len).(Node)
+ }
+ if n.Cap != nil {
+ n.Cap = edit(n.Cap).(Node)
+ }
}
-func (n *SliceType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SliceType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *SliceType) copy() Node {
c := *n
return &c
}
-func (n *SliceType) doChildren(do func(Node) error) error {
- var err error
- err = maybeDo(n.Elem, err, do)
- return err
+func (n *SliceType) doChildren(do func(Node) bool) bool {
+ if n.Elem != nil && do(n.Elem) {
+ return true
+ }
+ return false
}
func (n *SliceType) editChildren(edit func(Node) Node) {
- n.Elem = maybeEdit(n.Elem, edit)
+ if n.Elem != nil {
+ n.Elem = edit(n.Elem).(Ntype)
+ }
}
-func (n *StarExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *StarExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *StarExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *StarExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- return err
+func (n *StarExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ return false
}
func (n *StarExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
}
-func (n *StructKeyExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *StructKeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *StructKeyExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *StructKeyExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Value, err, do)
- return err
+func (n *StructKeyExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Value != nil && do(n.Value) {
+ return true
+ }
+ return false
}
func (n *StructKeyExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Value = maybeEdit(n.Value, edit)
+ editNodes(n.init, edit)
+ if n.Value != nil {
+ n.Value = edit(n.Value).(Node)
+ }
}
-func (n *StructType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *StructType) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *StructType) copy() Node {
c := *n
c.Fields = copyFields(c.Fields)
return &c
}
-func (n *StructType) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoFields(n.Fields, err, do)
- return err
+func (n *StructType) doChildren(do func(Node) bool) bool {
+ if doFields(n.Fields, do) {
+ return true
+ }
+ return false
}
func (n *StructType) editChildren(edit func(Node) Node) {
editFields(n.Fields, edit)
}
-func (n *SwitchStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *SwitchStmt) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *SwitchStmt) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Cases = copyCases(c.Cases)
- c.Compiled = c.Compiled.Copy()
+ c.init = copyNodes(c.init)
+ c.Cases = copyCaseClauses(c.Cases)
+ c.Compiled = copyNodes(c.Compiled)
return &c
}
-func (n *SwitchStmt) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.Tag, err, do)
- err = maybeDoCases(n.Cases, err, do)
- err = maybeDoList(n.Compiled, err, do)
- return err
+func (n *SwitchStmt) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Tag != nil && do(n.Tag) {
+ return true
+ }
+ if doCaseClauses(n.Cases, do) {
+ return true
+ }
+ if doNodes(n.Compiled, do) {
+ return true
+ }
+ return false
}
func (n *SwitchStmt) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.Tag = maybeEdit(n.Tag, edit)
- editCases(n.Cases, edit)
- editList(n.Compiled, edit)
+ editNodes(n.init, edit)
+ if n.Tag != nil {
+ n.Tag = edit(n.Tag).(Node)
+ }
+ editCaseClauses(n.Cases, edit)
+ editNodes(n.Compiled, edit)
}
-func (n *TypeAssertExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *TypeAssertExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *TypeAssertExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
- c.Itab = c.Itab.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *TypeAssertExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- err = maybeDo(n.Ntype, err, do)
- err = maybeDoList(n.Itab, err, do)
- return err
+func (n *TypeAssertExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ if n.Ntype != nil && do(n.Ntype) {
+ return true
+ }
+ return false
}
func (n *TypeAssertExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
- n.Ntype = maybeEdit(n.Ntype, edit)
- editList(n.Itab, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
+ if n.Ntype != nil {
+ n.Ntype = edit(n.Ntype).(Ntype)
+ }
}
-func (n *TypeSwitchGuard) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *TypeSwitchGuard) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *TypeSwitchGuard) copy() Node {
c := *n
return &c
}
-func (n *TypeSwitchGuard) doChildren(do func(Node) error) error {
- var err error
- if n.Tag != nil {
- err = maybeDo(n.Tag, err, do)
+func (n *TypeSwitchGuard) doChildren(do func(Node) bool) bool {
+ if n.Tag != nil && do(n.Tag) {
+ return true
}
- err = maybeDo(n.X, err, do)
- return err
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ return false
}
func (n *TypeSwitchGuard) editChildren(edit func(Node) Node) {
if n.Tag != nil {
n.Tag = edit(n.Tag).(*Ident)
}
- n.X = maybeEdit(n.X, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
}
-func (n *UnaryExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *UnaryExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *UnaryExpr) copy() Node {
c := *n
- c.init = c.init.Copy()
+ c.init = copyNodes(c.init)
return &c
}
-func (n *UnaryExpr) doChildren(do func(Node) error) error {
- var err error
- err = maybeDoList(n.init, err, do)
- err = maybeDo(n.X, err, do)
- return err
+func (n *UnaryExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.X != nil && do(n.X) {
+ return true
+ }
+ return false
}
func (n *UnaryExpr) editChildren(edit func(Node) Node) {
- editList(n.init, edit)
- n.X = maybeEdit(n.X, edit)
+ editNodes(n.init, edit)
+ if n.X != nil {
+ n.X = edit(n.X).(Node)
+ }
}
-func (n *typeNode) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
+func (n *typeNode) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *typeNode) copy() Node {
c := *n
return &c
}
-func (n *typeNode) doChildren(do func(Node) error) error {
- var err error
- return err
+func (n *typeNode) doChildren(do func(Node) bool) bool {
+ return false
}
func (n *typeNode) editChildren(edit func(Node) Node) {
}
+
+func copyCaseClauses(list []*CaseClause) []*CaseClause {
+ if list == nil {
+ return nil
+ }
+ c := make([]*CaseClause, len(list))
+ copy(c, list)
+ return c
+}
+func doCaseClauses(list []*CaseClause, do func(Node) bool) bool {
+ for _, x := range list {
+ if x != nil && do(x) {
+ return true
+ }
+ }
+ return false
+}
+func editCaseClauses(list []*CaseClause, edit func(Node) Node) {
+ for i, x := range list {
+ if x != nil {
+ list[i] = edit(x).(*CaseClause)
+ }
+ }
+}
+
+func copyCommClauses(list []*CommClause) []*CommClause {
+ if list == nil {
+ return nil
+ }
+ c := make([]*CommClause, len(list))
+ copy(c, list)
+ return c
+}
+func doCommClauses(list []*CommClause, do func(Node) bool) bool {
+ for _, x := range list {
+ if x != nil && do(x) {
+ return true
+ }
+ }
+ return false
+}
+func editCommClauses(list []*CommClause, edit func(Node) Node) {
+ for i, x := range list {
+ if x != nil {
+ list[i] = edit(x).(*CommClause)
+ }
+ }
+}
+
+func copyNames(list []*Name) []*Name {
+ if list == nil {
+ return nil
+ }
+ c := make([]*Name, len(list))
+ copy(c, list)
+ return c
+}
+func doNames(list []*Name, do func(Node) bool) bool {
+ for _, x := range list {
+ if x != nil && do(x) {
+ return true
+ }
+ }
+ return false
+}
+func editNames(list []*Name, edit func(Node) Node) {
+ for i, x := range list {
+ if x != nil {
+ list[i] = edit(x).(*Name)
+ }
+ }
+}
+
+func copyNodes(list []Node) []Node {
+ if list == nil {
+ return nil
+ }
+ c := make([]Node, len(list))
+ copy(c, list)
+ return c
+}
+func doNodes(list []Node, do func(Node) bool) bool {
+ for _, x := range list {
+ if x != nil && do(x) {
+ return true
+ }
+ }
+ return false
+}
+func editNodes(list []Node, edit func(Node) Node) {
+ for i, x := range list {
+ if x != nil {
+ list[i] = edit(x).(Node)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go
index f23e08c47c..0339444132 100644
--- a/src/cmd/compile/internal/ir/op_string.go
+++ b/src/cmd/compile/internal/ir/op_string.go
@@ -1,4 +1,4 @@
-// Code generated by "stringer -type=Op -trimprefix=O"; DO NOT EDIT.
+// Code generated by "stringer -type=Op -trimprefix=O node.go"; DO NOT EDIT.
package ir
diff --git a/src/cmd/compile/internal/ir/scc.go b/src/cmd/compile/internal/ir/scc.go
index f35c4d44e9..83c6074170 100644
--- a/src/cmd/compile/internal/ir/scc.go
+++ b/src/cmd/compile/internal/ir/scc.go
@@ -87,7 +87,7 @@ func (v *bottomUpVisitor) visit(n *Func) uint32 {
Visit(n, func(n Node) {
switch n.Op() {
case ONAME:
- if n := n.(*Name); n.Class_ == PFUNC {
+ if n := n.(*Name); n.Class == PFUNC {
do(n.Defn)
}
case ODOTMETH, OCALLPART, OMETHEXPR:
diff --git a/src/cmd/compile/internal/ir/sizeof_test.go b/src/cmd/compile/internal/ir/sizeof_test.go
index 2a618f85ed..60120f2998 100644
--- a/src/cmd/compile/internal/ir/sizeof_test.go
+++ b/src/cmd/compile/internal/ir/sizeof_test.go
@@ -20,8 +20,8 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Func{}, 200, 352},
- {Name{}, 132, 232},
+ {Func{}, 184, 320},
+ {Name{}, 124, 216},
}
for _, tt := range tests {
diff --git a/src/cmd/compile/internal/ir/stmt.go b/src/cmd/compile/internal/ir/stmt.go
index de152fec72..b13c6b7795 100644
--- a/src/cmd/compile/internal/ir/stmt.go
+++ b/src/cmd/compile/internal/ir/stmt.go
@@ -13,10 +13,10 @@ import (
// A Decl is a declaration of a const, type, or var. (A declared func is a Func.)
type Decl struct {
miniNode
- X Node // the thing being declared
+ X *Name // the thing being declared
}
-func NewDecl(pos src.XPos, op Op, x Node) *Decl {
+func NewDecl(pos src.XPos, op Op, x *Name) *Decl {
n := &Decl{X: x}
n.pos = pos
switch op {
@@ -70,8 +70,8 @@ func NewAssignListStmt(pos src.XPos, op Op, lhs, rhs []Node) *AssignListStmt {
n := &AssignListStmt{}
n.pos = pos
n.SetOp(op)
- n.Lhs.Set(lhs)
- n.Rhs.Set(rhs)
+ n.Lhs = lhs
+ n.Rhs = rhs
return n
}
@@ -112,7 +112,6 @@ func (n *AssignStmt) SetOp(op Op) {
// An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y.
type AssignOpStmt struct {
miniStmt
- typ *types.Type
X Node
AsOp Op // OADD etc
Y Node
@@ -126,9 +125,6 @@ func NewAssignOpStmt(pos src.XPos, asOp Op, x, y Node) *AssignOpStmt {
return n
}
-func (n *AssignOpStmt) Type() *types.Type { return n.typ }
-func (n *AssignOpStmt) SetType(x *types.Type) { n.typ = x }
-
// A BlockStmt is a block: { List }.
type BlockStmt struct {
miniStmt
@@ -145,7 +141,7 @@ func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt {
}
}
n.op = OBLOCK
- n.List.Set(list)
+ n.List = list
return n
}
@@ -176,7 +172,7 @@ func (n *BranchStmt) Sym() *types.Sym { return n.Label }
// A CaseClause is a case statement in a switch or select: case List: Body.
type CaseClause struct {
miniStmt
- Var Node // declared variable for this case in type switch
+ Var *Name // declared variable for this case in type switch
List Nodes // list of expressions for switch, early select
Body Nodes
}
@@ -188,36 +184,6 @@ func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause {
return n
}
-// TODO(mdempsky): Generate these with mknode.go.
-func copyCases(list []*CaseClause) []*CaseClause {
- if list == nil {
- return nil
- }
- c := make([]*CaseClause, len(list))
- copy(c, list)
- return c
-}
-func maybeDoCases(list []*CaseClause, err error, do func(Node) error) error {
- if err != nil {
- return err
- }
- for _, x := range list {
- if x != nil {
- if err := do(x); err != nil {
- return err
- }
- }
- }
- return nil
-}
-func editCases(list []*CaseClause, edit func(Node) Node) {
- for i, x := range list {
- if x != nil {
- list[i] = edit(x).(*CaseClause)
- }
- }
-}
-
type CommClause struct {
miniStmt
Comm Node // communication case
@@ -231,36 +197,6 @@ func NewCommStmt(pos src.XPos, comm Node, body []Node) *CommClause {
return n
}
-// TODO(mdempsky): Generate these with mknode.go.
-func copyComms(list []*CommClause) []*CommClause {
- if list == nil {
- return nil
- }
- c := make([]*CommClause, len(list))
- copy(c, list)
- return c
-}
-func maybeDoComms(list []*CommClause, err error, do func(Node) error) error {
- if err != nil {
- return err
- }
- for _, x := range list {
- if x != nil {
- if err := do(x); err != nil {
- return err
- }
- }
- }
- return nil
-}
-func editComms(list []*CommClause, edit func(Node) Node) {
- for i, x := range list {
- if x != nil {
- list[i] = edit(x).(*CommClause)
- }
- }
-}
-
// A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
// Op can be OFOR or OFORUNTIL (!Cond).
type ForStmt struct {
@@ -280,7 +216,7 @@ func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node) *ForStmt
if init != nil {
n.init = []Node{init}
}
- n.Body.Set(body)
+ n.Body = body
return n
}
@@ -326,8 +262,8 @@ func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt {
n := &IfStmt{Cond: cond}
n.pos = pos
n.op = OIF
- n.Body.Set(body)
- n.Else.Set(els)
+ n.Body = body
+ n.Else = els
return n
}
@@ -379,15 +315,15 @@ func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node) *RangeStmt {
n := &RangeStmt{X: x, Key: key, Value: value}
n.pos = pos
n.op = ORANGE
- n.Body.Set(body)
+ n.Body = body
return n
}
// A ReturnStmt is a return statement.
type ReturnStmt struct {
miniStmt
- orig Node // for typecheckargs rewrite
- Results Nodes // return list
+ origNode // for typecheckargs rewrite
+ Results Nodes // return list
}
func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
@@ -395,13 +331,10 @@ func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
n.pos = pos
n.op = ORETURN
n.orig = n
- n.Results.Set(results)
+ n.Results = results
return n
}
-func (n *ReturnStmt) Orig() Node { return n.orig }
-func (n *ReturnStmt) SetOrig(x Node) { n.orig = x }
-
// A SelectStmt is a block: { Cases }.
type SelectStmt struct {
miniStmt
diff --git a/src/cmd/compile/internal/ir/type.go b/src/cmd/compile/internal/ir/type.go
index bd3a05d06e..a903ea8cd4 100644
--- a/src/cmd/compile/internal/ir/type.go
+++ b/src/cmd/compile/internal/ir/type.go
@@ -46,7 +46,7 @@ func (n *miniType) Type() *types.Type { return n.typ }
// setOTYPE also records t.Nod = self if t.Nod is not already set.
// (Some types are shared by multiple OTYPE nodes, so only
// the first such node is used as t.Nod.)
-func (n *miniType) setOTYPE(t *types.Type, self Node) {
+func (n *miniType) setOTYPE(t *types.Type, self Ntype) {
if n.typ != nil {
panic(n.op.String() + " SetType: type already set")
}
@@ -61,11 +61,11 @@ func (n *miniType) Implicit() bool { return false } // for Format OTYPE
// A ChanType represents a chan Elem syntax with the direction Dir.
type ChanType struct {
miniType
- Elem Node
+ Elem Ntype
Dir types.ChanDir
}
-func NewChanType(pos src.XPos, elem Node, dir types.ChanDir) *ChanType {
+func NewChanType(pos src.XPos, elem Ntype, dir types.ChanDir) *ChanType {
n := &ChanType{Elem: elem, Dir: dir}
n.op = OTCHAN
n.pos = pos
@@ -80,11 +80,11 @@ func (n *ChanType) SetOTYPE(t *types.Type) {
// A MapType represents a map[Key]Value type syntax.
type MapType struct {
miniType
- Key Node
- Elem Node
+ Key Ntype
+ Elem Ntype
}
-func NewMapType(pos src.XPos, key, elem Node) *MapType {
+func NewMapType(pos src.XPos, key, elem Ntype) *MapType {
n := &MapType{Key: key, Elem: elem}
n.op = OTMAP
n.pos = pos
@@ -185,45 +185,28 @@ func (f *Field) String() string {
return typ
}
-func (f *Field) copy() *Field {
- c := *f
- return &c
-}
+// TODO(mdempsky): Make Field a Node again so these can be generated?
+// Fields are Nodes in go/ast and cmd/compile/internal/syntax.
-func copyFields(list []*Field) []*Field {
- out := make([]*Field, len(list))
- copy(out, list)
- for i, f := range out {
- out[i] = f.copy()
+func copyField(f *Field) *Field {
+ if f == nil {
+ return nil
}
- return out
+ c := *f
+ return &c
}
-
-func maybeDoField(f *Field, err error, do func(Node) error) error {
- if f != nil {
- if err == nil && f.Decl != nil {
- err = do(f.Decl)
- }
- if err == nil && f.Ntype != nil {
- err = do(f.Ntype)
- }
+func doField(f *Field, do func(Node) bool) bool {
+ if f == nil {
+ return false
}
- return err
-}
-
-func maybeDoFields(list []*Field, err error, do func(Node) error) error {
- if err != nil {
- return err
+ if f.Decl != nil && do(f.Decl) {
+ return true
}
- for _, f := range list {
- err = maybeDoField(f, err, do)
- if err != nil {
- return err
- }
+ if f.Ntype != nil && do(f.Ntype) {
+ return true
}
- return err
+ return false
}
-
func editField(f *Field, edit func(Node) Node) {
if f == nil {
return
@@ -232,10 +215,25 @@ func editField(f *Field, edit func(Node) Node) {
f.Decl = edit(f.Decl).(*Name)
}
if f.Ntype != nil {
- f.Ntype = toNtype(edit(f.Ntype))
+ f.Ntype = edit(f.Ntype).(Ntype)
}
}
+func copyFields(list []*Field) []*Field {
+ out := make([]*Field, len(list))
+ for i, f := range list {
+ out[i] = copyField(f)
+ }
+ return out
+}
+func doFields(list []*Field, do func(Node) bool) bool {
+ for _, x := range list {
+ if doField(x, do) {
+ return true
+ }
+ }
+ return false
+}
func editFields(list []*Field, edit func(Node) Node) {
for _, f := range list {
editField(f, edit)
@@ -246,11 +244,11 @@ func editFields(list []*Field, edit func(Node) Node) {
// If DDD is true, it's the ...Elem at the end of a function list.
type SliceType struct {
miniType
- Elem Node
+ Elem Ntype
DDD bool
}
-func NewSliceType(pos src.XPos, elem Node) *SliceType {
+func NewSliceType(pos src.XPos, elem Ntype) *SliceType {
n := &SliceType{Elem: elem}
n.op = OTSLICE
n.pos = pos
@@ -267,11 +265,11 @@ func (n *SliceType) SetOTYPE(t *types.Type) {
type ArrayType struct {
miniType
Len Node
- Elem Node
+ Elem Ntype
}
-func NewArrayType(pos src.XPos, size Node, elem Node) *ArrayType {
- n := &ArrayType{Len: size, Elem: elem}
+func NewArrayType(pos src.XPos, len Node, elem Ntype) *ArrayType {
+ n := &ArrayType{Len: len, Elem: elem}
n.op = OTARRAY
n.pos = pos
return n
diff --git a/src/cmd/compile/internal/ir/visit.go b/src/cmd/compile/internal/ir/visit.go
index 8839e1664d..c1b3d4ed95 100644
--- a/src/cmd/compile/internal/ir/visit.go
+++ b/src/cmd/compile/internal/ir/visit.go
@@ -4,23 +4,18 @@
// IR visitors for walking the IR tree.
//
-// The lowest level helpers are DoChildren and EditChildren,
-// which nodes help implement (TODO(rsc): eventually) and
-// provide control over whether and when recursion happens
-// during the walk of the IR.
+// The lowest level helpers are DoChildren and EditChildren, which
+// nodes help implement and provide control over whether and when
+// recursion happens during the walk of the IR.
//
// Although these are both useful directly, two simpler patterns
-// are fairly common and also provided: Inspect and Scan.
+// are fairly common and also provided: Visit and Any.
package ir
-import (
- "errors"
-)
-
// DoChildren calls do(x) on each of n's non-nil child nodes x.
-// If any call returns a non-nil error, DoChildren stops and returns that error.
-// Otherwise, DoChildren returns nil.
+// If any call returns true, DoChildren stops and returns true.
+// Otherwise, DoChildren returns false.
//
// Note that DoChildren(n, do) only calls do(x) for n's immediate children.
// If x's children should be processed, then do(x) must call DoChildren(x, do).
@@ -28,32 +23,32 @@ import (
// DoChildren allows constructing general traversals of the IR graph
// that can stop early if needed. The most general usage is:
//
-// var do func(ir.Node) error
-// do = func(x ir.Node) error {
+// var do func(ir.Node) bool
+// do = func(x ir.Node) bool {
// ... processing BEFORE visting children ...
// if ... should visit children ... {
// ir.DoChildren(x, do)
// ... processing AFTER visting children ...
// }
// if ... should stop parent DoChildren call from visiting siblings ... {
-// return non-nil error
+// return true
// }
-// return nil
+// return false
// }
// do(root)
//
-// Since DoChildren does not generate any errors itself, if the do function
-// never wants to stop the traversal, it can assume that DoChildren itself
-// will always return nil, simplifying to:
+// Since DoChildren does not return true itself, if the do function
+// never wants to stop the traversal, it can assume that DoChildren
+// itself will always return false, simplifying to:
//
-// var do func(ir.Node) error
-// do = func(x ir.Node) error {
+// var do func(ir.Node) bool
+// do = func(x ir.Node) bool {
// ... processing BEFORE visting children ...
// if ... should visit children ... {
// ir.DoChildren(x, do)
// }
// ... processing AFTER visting children ...
-// return nil
+// return false
// }
// do(root)
//
@@ -61,14 +56,15 @@ import (
// only processing before visiting children and never stopping:
//
// func Visit(n ir.Node, visit func(ir.Node)) {
-// var do func(ir.Node) error
-// do = func(x ir.Node) error {
+// if n == nil {
+// return
+// }
+// var do func(ir.Node) bool
+// do = func(x ir.Node) bool {
// visit(x)
// return ir.DoChildren(x, do)
// }
-// if n != nil {
-// visit(n)
-// }
+// do(n)
// }
//
// The Any function illustrates a different simplification of the pattern,
@@ -76,57 +72,40 @@ import (
// a node x for which cond(x) returns true, at which point the entire
// traversal stops and returns true.
//
-// func Any(n ir.Node, find cond(ir.Node)) bool {
-// stop := errors.New("stop")
-// var do func(ir.Node) error
-// do = func(x ir.Node) error {
-// if cond(x) {
-// return stop
-// }
-// return ir.DoChildren(x, do)
+// func Any(n ir.Node, cond(ir.Node) bool) bool {
+// if n == nil {
+// return false
+// }
+// var do func(ir.Node) bool
+// do = func(x ir.Node) bool {
+// return cond(x) || ir.DoChildren(x, do)
// }
-// return do(n) == stop
+// return do(n)
// }
//
// Visit and Any are presented above as examples of how to use
// DoChildren effectively, but of course, usage that fits within the
// simplifications captured by Visit or Any will be best served
// by directly calling the ones provided by this package.
-func DoChildren(n Node, do func(Node) error) error {
+func DoChildren(n Node, do func(Node) bool) bool {
if n == nil {
- return nil
+ return false
}
return n.doChildren(do)
}
-// DoList calls f on each non-nil node x in the list, in list order.
-// If any call returns a non-nil error, DoList stops and returns that error.
-// Otherwise DoList returns nil.
-//
-// Note that DoList only calls do on the nodes in the list, not their children.
-// If x's children should be processed, do(x) must call DoChildren(x, do) itself.
-func DoList(list Nodes, do func(Node) error) error {
- for _, x := range list {
- if x != nil {
- if err := do(x); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
// Visit visits each non-nil node x in the IR tree rooted at n
// in a depth-first preorder traversal, calling visit on each node visited.
func Visit(n Node, visit func(Node)) {
- var do func(Node) error
- do = func(x Node) error {
+ if n == nil {
+ return
+ }
+ var do func(Node) bool
+ do = func(x Node) bool {
visit(x)
return DoChildren(x, do)
}
- if n != nil {
- do(n)
- }
+ do(n)
}
// VisitList calls Visit(x, visit) for each node x in the list.
@@ -136,8 +115,6 @@ func VisitList(list Nodes, visit func(Node)) {
}
}
-var stop = errors.New("stop")
-
// Any looks for a non-nil node x in the IR tree rooted at n
// for which cond(x) returns true.
// Any considers nodes in a depth-first, preorder traversal.
@@ -148,14 +125,11 @@ func Any(n Node, cond func(Node) bool) bool {
if n == nil {
return false
}
- var do func(Node) error
- do = func(x Node) error {
- if cond(x) {
- return stop
- }
- return DoChildren(x, do)
+ var do func(Node) bool
+ do = func(x Node) bool {
+ return cond(x) || DoChildren(x, do)
}
- return do(n) == stop
+ return do(n)
}
// AnyList calls Any(x, cond) for each node x in the list, in order.
@@ -210,16 +184,3 @@ func EditChildren(n Node, edit func(Node) Node) {
}
n.editChildren(edit)
}
-
-// editList calls edit on each non-nil node x in the list,
-// saving the result of edit back into the list.
-//
-// Note that editList only calls edit on the nodes in the list, not their children.
-// If x's children should be processed, edit(x) must call EditChildren(x, edit) itself.
-func editList(list Nodes, edit func(Node) Node) {
- for i, x := range list {
- if x != nil {
- list[i] = edit(x)
- }
- }
-}
diff --git a/src/cmd/compile/internal/liveness/plive.go b/src/cmd/compile/internal/liveness/plive.go
index 89c70df65a..26d90824b2 100644
--- a/src/cmd/compile/internal/liveness/plive.go
+++ b/src/cmd/compile/internal/liveness/plive.go
@@ -181,7 +181,7 @@ type progeffectscache struct {
// nor do we care about empty structs (handled by the pointer check),
// nor do we care about the fake PAUTOHEAP variables.
func ShouldTrack(n *ir.Name) bool {
- return (n.Class_ == ir.PAUTO || n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT) && n.Type().HasPointers()
+ return (n.Class == ir.PAUTO || n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT) && n.Type().HasPointers()
}
// getvariables returns the list of on-stack variables that we need to track
@@ -208,7 +208,7 @@ func (lv *liveness) initcache() {
lv.cache.initialized = true
for i, node := range lv.vars {
- switch node.Class_ {
+ switch node.Class {
case ir.PPARAM:
// A return instruction with a p.to is a tail return, which brings
// the stack pointer back up (if it ever went down) and then jumps
@@ -255,7 +255,7 @@ func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
// variable" ICEs (issue 19632).
switch v.Op {
case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
- if !n.Name().Used() {
+ if !n.Used() {
return -1, 0
}
}
@@ -386,7 +386,7 @@ func (lv *liveness) pointerMap(liveout bitvec.BitVec, vars []*ir.Name, args, loc
break
}
node := vars[i]
- switch node.Class_ {
+ switch node.Class {
case ir.PAUTO:
typebits.Set(node.Type(), node.FrameOffset()+lv.stkptrsize, locals)
@@ -687,12 +687,12 @@ func (lv *liveness) epilogue() {
// don't need to keep the stack copy live?
if lv.fn.HasDefer() {
for i, n := range lv.vars {
- if n.Class_ == ir.PPARAMOUT {
- if n.Name().IsOutputParamHeapAddr() {
+ if n.Class == ir.PPARAMOUT {
+ if n.IsOutputParamHeapAddr() {
// Just to be paranoid. Heap addresses are PAUTOs.
base.Fatalf("variable %v both output param and heap output param", n)
}
- if n.Name().Heapaddr != nil {
+ if n.Heapaddr != nil {
// If this variable moved to the heap, then
// its stack copy is not live.
continue
@@ -700,21 +700,21 @@ func (lv *liveness) epilogue() {
// Note: zeroing is handled by zeroResults in walk.go.
livedefer.Set(int32(i))
}
- if n.Name().IsOutputParamHeapAddr() {
+ if n.IsOutputParamHeapAddr() {
// This variable will be overwritten early in the function
// prologue (from the result of a mallocgc) but we need to
// zero it in case that malloc causes a stack scan.
- n.Name().SetNeedzero(true)
+ n.SetNeedzero(true)
livedefer.Set(int32(i))
}
- if n.Name().OpenDeferSlot() {
+ if n.OpenDeferSlot() {
// Open-coded defer args slots must be live
// everywhere in a function, since a panic can
// occur (almost) anywhere. Because it is live
// everywhere, it must be zeroed on entry.
livedefer.Set(int32(i))
// It was already marked as Needzero when created.
- if !n.Name().Needzero() {
+ if !n.Needzero() {
base.Fatalf("all pointer-containing defer arg slots should have Needzero set")
}
}
@@ -785,7 +785,7 @@ func (lv *liveness) epilogue() {
if !liveout.Get(int32(i)) {
continue
}
- if n.Class_ == ir.PPARAM {
+ if n.Class == ir.PPARAM {
continue // ok
}
base.Fatalf("bad live variable at entry of %v: %L", lv.fn.Nname, n)
@@ -818,7 +818,7 @@ func (lv *liveness) epilogue() {
// the only things that can possibly be live are the
// input parameters.
for j, n := range lv.vars {
- if n.Class_ != ir.PPARAM && lv.stackMaps[0].Get(int32(j)) {
+ if n.Class != ir.PPARAM && lv.stackMaps[0].Get(int32(j)) {
lv.f.Fatalf("%v %L recorded as live on entry", lv.fn.Nname, n)
}
}
@@ -1063,7 +1063,7 @@ func (lv *liveness) emit() (argsSym, liveSym *obj.LSym) {
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
var maxArgNode *ir.Name
for _, n := range lv.vars {
- switch n.Class_ {
+ switch n.Class {
case ir.PPARAM, ir.PPARAMOUT:
if maxArgNode == nil || n.FrameOffset() > maxArgNode.FrameOffset() {
maxArgNode = n
diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go
index a39be9864b..08f19a4028 100644
--- a/src/cmd/compile/internal/noder/import.go
+++ b/src/cmd/compile/internal/noder/import.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:generate go run mkbuiltin.go
-
package noder
import (
diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go
index c1356be52f..938ffe05ce 100644
--- a/src/cmd/compile/internal/noder/noder.go
+++ b/src/cmd/compile/internal/noder/noder.go
@@ -28,6 +28,26 @@ import (
"cmd/internal/src"
)
+func LoadPackage(filenames []string) {
+ base.Timer.Start("fe", "parse")
+ lines := ParseFiles(filenames)
+ base.Timer.Stop()
+ base.Timer.AddEvent(int64(lines), "lines")
+
+ if base.Flag.G != 0 && base.Flag.G < 3 {
+ // can only parse generic code for now
+ base.ExitIfErrors()
+ return
+ }
+
+ // Typecheck.
+ Package()
+
+ // With all user code typechecked, it's now safe to verify unused dot imports.
+ CheckDotImports()
+ base.ExitIfErrors()
+}
+
// ParseFiles concurrently parses files into *syntax.File structures.
// Each declaration in every *syntax.File is converted to a syntax tree
// and its root represented by *Node is appended to Target.Decls.
@@ -170,6 +190,69 @@ func ParseFiles(filenames []string) (lines uint) {
return
}
+func Package() {
+ typecheck.DeclareUniverse()
+
+ typecheck.TypecheckAllowed = true
+
+ // Process top-level declarations in phases.
+
+ // Phase 1: const, type, and names and types of funcs.
+ // This will gather all the information about types
+ // and methods but doesn't depend on any of it.
+ //
+ // We also defer type alias declarations until phase 2
+ // to avoid cycles like #18640.
+ // TODO(gri) Remove this again once we have a fix for #25838.
+
+ // Don't use range--typecheck can add closures to Target.Decls.
+ base.Timer.Start("fe", "typecheck", "top1")
+ for i := 0; i < len(typecheck.Target.Decls); i++ {
+ n := typecheck.Target.Decls[i]
+ if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).X.Alias()) {
+ typecheck.Target.Decls[i] = typecheck.Stmt(n)
+ }
+ }
+
+ // Phase 2: Variable assignments.
+ // To check interface assignments, depends on phase 1.
+
+ // Don't use range--typecheck can add closures to Target.Decls.
+ base.Timer.Start("fe", "typecheck", "top2")
+ for i := 0; i < len(typecheck.Target.Decls); i++ {
+ n := typecheck.Target.Decls[i]
+ if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).X.Alias() {
+ typecheck.Target.Decls[i] = typecheck.Stmt(n)
+ }
+ }
+
+ // Phase 3: Type check function bodies.
+ // Don't use range--typecheck can add closures to Target.Decls.
+ base.Timer.Start("fe", "typecheck", "func")
+ var fcount int64
+ for i := 0; i < len(typecheck.Target.Decls); i++ {
+ n := typecheck.Target.Decls[i]
+ if n.Op() == ir.ODCLFUNC {
+ typecheck.FuncBody(n.(*ir.Func))
+ fcount++
+ }
+ }
+
+ // Phase 4: Check external declarations.
+ // TODO(mdempsky): This should be handled when type checking their
+ // corresponding ODCL nodes.
+ base.Timer.Start("fe", "typecheck", "externdcls")
+ for i, n := range typecheck.Target.Externs {
+ if n.Op() == ir.ONAME {
+ typecheck.Target.Externs[i] = typecheck.Expr(typecheck.Target.Externs[i])
+ }
+ }
+
+ // Phase 5: With all user code type-checked, it's now safe to verify map keys.
+ typecheck.CheckMapKeys()
+
+}
+
// Temporary import helper to get type2-based type-checking going.
type gcimports struct {
packages map[string]*types2.Package
@@ -301,7 +384,7 @@ func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
if body == nil {
body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)}
}
- fn.Body.Set(body)
+ fn.Body = body
base.Pos = p.makeXPos(block.Rbrace)
fn.Endlineno = base.Pos
@@ -530,8 +613,48 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node {
p.checkUnused(pragma)
}
+ var init []ir.Node
p.setlineno(decl)
- return typecheck.DeclVars(names, typ, exprs)
+
+ if len(names) > 1 && len(exprs) == 1 {
+ as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, exprs)
+ for _, v := range names {
+ as2.Lhs.Append(v)
+ typecheck.Declare(v, typecheck.DeclContext)
+ v.Ntype = typ
+ v.Defn = as2
+ if ir.CurFunc != nil {
+ init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
+ }
+ }
+
+ return append(init, as2)
+ }
+
+ for i, v := range names {
+ var e ir.Node
+ if i < len(exprs) {
+ e = exprs[i]
+ }
+
+ typecheck.Declare(v, typecheck.DeclContext)
+ v.Ntype = typ
+
+ if ir.CurFunc != nil {
+ init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
+ }
+ as := ir.NewAssignStmt(base.Pos, v, e)
+ init = append(init, as)
+ if e != nil || ir.CurFunc == nil {
+ v.Defn = as
+ }
+ }
+
+ if len(exprs) != 0 && len(names) != len(exprs) {
+ base.Errorf("assignment mismatch: %d variables but %d values", len(names), len(exprs))
+ }
+
+ return init
}
// constState tracks state between constant specifiers within a
@@ -657,7 +780,8 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) ir.Node {
name = ir.BlankNode.Sym() // filled in by typecheckfunc
}
- f.Nname = ir.NewFuncNameAt(p.pos(fun.Name), name, f)
+ f.Nname = ir.NewNameAt(p.pos(fun.Name), name)
+ f.Nname.Func = f
f.Nname.Defn = f
f.Nname.Ntype = t
@@ -787,7 +911,7 @@ func (p *noder) expr(expr syntax.Expr) ir.Node {
for i, e := range l {
l[i] = p.wrapname(expr.ElemList[i], e)
}
- n.List.Set(l)
+ n.List = l
base.Pos = p.makeXPos(expr.Rbrace)
return n
case *syntax.KeyValueExpr:
@@ -1143,8 +1267,8 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
if list, ok := stmt.Lhs.(*syntax.ListExpr); ok && len(list.ElemList) != 1 || len(rhs) != 1 {
n := ir.NewAssignListStmt(p.pos(stmt), ir.OAS2, nil, nil)
n.Def = stmt.Op == syntax.Def
- n.Lhs.Set(p.assignList(stmt.Lhs, n, n.Def))
- n.Rhs.Set(rhs)
+ n.Lhs = p.assignList(stmt.Lhs, n, n.Def)
+ n.Rhs = rhs
return n
}
@@ -1191,10 +1315,10 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
n := ir.NewReturnStmt(p.pos(stmt), p.exprList(stmt.Results))
if len(n.Results) == 0 && ir.CurFunc != nil {
for _, ln := range ir.CurFunc.Dcl {
- if ln.Class_ == ir.PPARAM {
+ if ln.Class == ir.PPARAM {
continue
}
- if ln.Class_ != ir.PPARAMOUT {
+ if ln.Class != ir.PPARAMOUT {
break
}
if ln.Sym().Def != ln {
@@ -1215,7 +1339,7 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
panic("unhandled Stmt")
}
-func (p *noder) assignList(expr syntax.Expr, defn ir.Node, colas bool) []ir.Node {
+func (p *noder) assignList(expr syntax.Expr, defn ir.InitNode, colas bool) []ir.Node {
if !colas {
return p.exprList(expr)
}
@@ -1291,7 +1415,7 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node {
e := p.stmt(stmt.Else)
if e.Op() == ir.OBLOCK {
e := e.(*ir.BlockStmt)
- n.Else.Set(e.List)
+ n.Else = e.List
} else {
n.Else = []ir.Node{e}
}
@@ -1316,7 +1440,7 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) ir.Node {
n.Value = lhs[1]
}
}
- n.Body.Set(p.blockStmt(stmt.Body))
+ n.Body = p.blockStmt(stmt.Body)
p.closeAnotherScope()
return n
}
@@ -1374,7 +1498,7 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitch
body = body[:len(body)-1]
}
- n.Body.Set(p.stmtsFall(body, true))
+ n.Body = p.stmtsFall(body, true)
if l := len(n.Body); l > 0 && n.Body[l-1].Op() == ir.OFALL {
if tswitch != nil {
base.Errorf("cannot fallthrough in type switch")
@@ -1875,7 +1999,9 @@ func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node {
fn := ir.NewFunc(p.pos(expr))
fn.SetIsHiddenClosure(ir.CurFunc != nil)
- fn.Nname = ir.NewFuncNameAt(p.pos(expr), ir.BlankNode.Sym(), fn) // filled in by typecheckclosure
+
+ fn.Nname = ir.NewNameAt(p.pos(expr), ir.BlankNode.Sym()) // filled in by typecheckclosure
+ fn.Nname.Func = fn
fn.Nname.Ntype = xtype
fn.Nname.Defn = fn
@@ -1965,18 +2091,18 @@ func oldname(s *types.Sym) ir.Node {
// the := it looks like a reference to the outer x so we'll
// make x a closure variable unnecessarily.
n := n.(*ir.Name)
- c := n.Name().Innermost
+ c := n.Innermost
if c == nil || c.Curfn != ir.CurFunc {
// Do not have a closure var for the active closure yet; make one.
c = typecheck.NewName(s)
- c.Class_ = ir.PAUTOHEAP
+ c.Class = ir.PAUTOHEAP
c.SetIsClosureVar(true)
c.Defn = n
// Link into list of active closure variables.
// Popped from list in func funcLit.
- c.Outer = n.Name().Innermost
- n.Name().Innermost = c
+ c.Outer = n.Innermost
+ n.Innermost = c
ir.CurFunc.ClosureVars = append(ir.CurFunc.ClosureVars, c)
}
diff --git a/src/cmd/compile/internal/pkginit/init.go b/src/cmd/compile/internal/pkginit/init.go
index f964edee88..5bc66c7e1b 100644
--- a/src/cmd/compile/internal/pkginit/init.go
+++ b/src/cmd/compile/internal/pkginit/init.go
@@ -6,6 +6,7 @@ package pkginit
import (
"cmd/compile/internal/base"
+ "cmd/compile/internal/deadcode"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
"cmd/compile/internal/typecheck"
@@ -31,10 +32,10 @@ func Task() *ir.Name {
if n.Op() == ir.ONONAME {
continue
}
- if n.Op() != ir.ONAME || n.(*ir.Name).Class_ != ir.PEXTERN {
+ if n.Op() != ir.ONAME || n.(*ir.Name).Class != ir.PEXTERN {
base.Fatalf("bad inittask: %v", n)
}
- deps = append(deps, n.(*ir.Name).Sym().Linksym())
+ deps = append(deps, n.(*ir.Name).Linksym())
}
// Make a function that contains all the initialization statements.
@@ -48,7 +49,7 @@ func Task() *ir.Name {
fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
typecheck.InitTodoFunc.Dcl = nil
- fn.Body.Set(nf)
+ fn.Body = nf
typecheck.FinishFuncBody()
typecheck.Func(fn)
@@ -56,7 +57,7 @@ func Task() *ir.Name {
typecheck.Stmts(nf)
ir.CurFunc = nil
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
- fns = append(fns, initializers.Linksym())
+ fns = append(fns, fn.Linksym())
}
if typecheck.InitTodoFunc.Dcl != nil {
// We only generate temps using initTodo if there
@@ -68,13 +69,16 @@ func Task() *ir.Name {
// Record user init functions.
for _, fn := range typecheck.Target.Inits {
+ // Must happen after initOrder; see #43444.
+ deadcode.Func(fn)
+
// Skip init functions with empty bodies.
if len(fn.Body) == 1 {
if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
continue
}
}
- fns = append(fns, fn.Nname.Sym().Linksym())
+ fns = append(fns, fn.Nname.Linksym())
}
if len(deps) == 0 && len(fns) == 0 && types.LocalPkg.Name != "main" && types.LocalPkg.Name != "runtime" {
@@ -85,9 +89,9 @@ func Task() *ir.Name {
sym := typecheck.Lookup(".inittask")
task := typecheck.NewName(sym)
task.SetType(types.Types[types.TUINT8]) // fake type
- task.Class_ = ir.PEXTERN
+ task.Class = ir.PEXTERN
sym.Def = task
- lsym := sym.Linksym()
+ lsym := task.Linksym()
ot := 0
ot = objw.Uintptr(lsym, ot, 0) // state: not initialized yet
ot = objw.Uintptr(lsym, ot, uint64(len(deps)))
diff --git a/src/cmd/compile/internal/pkginit/initorder.go b/src/cmd/compile/internal/pkginit/initorder.go
index c6e223954d..bdefd594ff 100644
--- a/src/cmd/compile/internal/pkginit/initorder.go
+++ b/src/cmd/compile/internal/pkginit/initorder.go
@@ -140,7 +140,7 @@ func (o *InitOrder) processAssign(n ir.Node) {
defn := dep.Defn
// Skip dependencies on functions (PFUNC) and
// variables already initialized (InitDone).
- if dep.Class_ != ir.PEXTERN || o.order[defn] == orderDone {
+ if dep.Class != ir.PEXTERN || o.order[defn] == orderDone {
continue
}
o.order[n]++
@@ -197,14 +197,14 @@ func (o *InitOrder) findInitLoopAndExit(n *ir.Name, path *[]*ir.Name) {
// There might be multiple loops involving n; by sorting
// references, we deterministically pick the one reported.
- refers := collectDeps(n.Name().Defn, false).Sorted(func(ni, nj *ir.Name) bool {
+ refers := collectDeps(n.Defn, false).Sorted(func(ni, nj *ir.Name) bool {
return ni.Pos().Before(nj.Pos())
})
*path = append(*path, n)
for _, ref := range refers {
// Short-circuit variables that were initialized.
- if ref.Class_ == ir.PEXTERN && o.order[ref.Defn] == orderDone {
+ if ref.Class == ir.PEXTERN && o.order[ref.Defn] == orderDone {
continue
}
@@ -221,7 +221,7 @@ func reportInitLoopAndExit(l []*ir.Name) {
// the start.
i := -1
for j, n := range l {
- if n.Class_ == ir.PEXTERN && (i == -1 || n.Pos().Before(l[i].Pos())) {
+ if n.Class == ir.PEXTERN && (i == -1 || n.Pos().Before(l[i].Pos())) {
i = j
}
}
@@ -291,7 +291,7 @@ func (d *initDeps) visit(n ir.Node) {
switch n.Op() {
case ir.ONAME:
n := n.(*ir.Name)
- switch n.Class_ {
+ switch n.Class {
case ir.PEXTERN, ir.PFUNC:
d.foundDep(n)
}
@@ -324,7 +324,7 @@ func (d *initDeps) foundDep(n *ir.Name) {
return
}
d.seen.Add(n)
- if d.transitive && n.Class_ == ir.PFUNC {
+ if d.transitive && n.Class == ir.PFUNC {
d.inspectList(n.Defn.(*ir.Func).Body)
}
}
diff --git a/src/cmd/compile/internal/reflectdata/alg.go b/src/cmd/compile/internal/reflectdata/alg.go
index 1f943f5795..d23ca6c7aa 100644
--- a/src/cmd/compile/internal/reflectdata/alg.go
+++ b/src/cmd/compile/internal/reflectdata/alg.go
@@ -104,7 +104,7 @@ func genhash(t *types.Type) *obj.LSym {
// For other sizes of plain memory, we build a closure
// that calls memhash_varlen. The size of the memory is
// encoded in the first slot of the closure.
- closure := types.TypeSymLookup(fmt.Sprintf(".hashfunc%d", t.Width)).Linksym()
+ closure := TypeLinksymLookup(fmt.Sprintf(".hashfunc%d", t.Width))
if len(closure.P) > 0 { // already generated
return closure
}
@@ -120,7 +120,7 @@ func genhash(t *types.Type) *obj.LSym {
break
}
- closure := TypeSymPrefix(".hashfunc", t).Linksym()
+ closure := TypeLinksymPrefix(".hashfunc", t)
if len(closure.P) > 0 { // already generated
return closure
}
@@ -255,7 +255,7 @@ func genhash(t *types.Type) *obj.LSym {
// Build closure. It doesn't close over any variables, so
// it contains just the function pointer.
- objw.SymPtr(closure, 0, sym.Linksym(), 0)
+ objw.SymPtr(closure, 0, fn.Linksym(), 0)
objw.Global(closure, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
return closure
@@ -347,7 +347,7 @@ func geneq(t *types.Type) *obj.LSym {
case types.AMEM:
// make equality closure. The size of the type
// is encoded in the closure.
- closure := types.TypeSymLookup(fmt.Sprintf(".eqfunc%d", t.Width)).Linksym()
+ closure := TypeLinksymLookup(fmt.Sprintf(".eqfunc%d", t.Width))
if len(closure.P) != 0 {
return closure
}
@@ -363,7 +363,7 @@ func geneq(t *types.Type) *obj.LSym {
break
}
- closure := TypeSymPrefix(".eqfunc", t).Linksym()
+ closure := TypeLinksymPrefix(".eqfunc", t)
if len(closure.P) > 0 { // already generated
return closure
}
@@ -634,7 +634,7 @@ func geneq(t *types.Type) *obj.LSym {
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
// Generate a closure which points at the function we just generated.
- objw.SymPtr(closure, 0, sym.Linksym(), 0)
+ objw.SymPtr(closure, 0, fn.Linksym(), 0)
objw.Global(closure, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
return closure
}
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index df80380fc1..30857fff6d 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -52,13 +52,13 @@ var (
signatslice []*types.Type
itabs []itabEntry
- ptabs []ptabEntry
+ ptabs []*ir.Name
)
type typeSig struct {
name *types.Sym
- isym *types.Sym
- tsym *types.Sym
+ isym *obj.LSym
+ tsym *obj.LSym
type_ *types.Type
mtype *types.Type
}
@@ -327,21 +327,19 @@ func methods(t *types.Type) []*typeSig {
// generating code if necessary.
var ms []*typeSig
for _, f := range mt.AllMethods().Slice() {
+ if f.Sym == nil {
+ base.Fatalf("method with no sym on %v", mt)
+ }
if !f.IsMethod() {
- base.Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
+ base.Fatalf("non-method on %v method %v %v", mt, f.Sym, f)
}
if f.Type.Recv() == nil {
- base.Fatalf("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
+ base.Fatalf("receiver with no type on %v method %v %v", mt, f.Sym, f)
}
if f.Nointerface() {
continue
}
- method := f.Sym
- if method == nil {
- break
- }
-
// get receiver type for this particular method.
// if pointer receiver but non-pointer t and
// this is not an embedded pointer inside a struct,
@@ -351,29 +349,13 @@ func methods(t *types.Type) []*typeSig {
}
sig := &typeSig{
- name: method,
- isym: ir.MethodSym(it, method),
- tsym: ir.MethodSym(t, method),
+ name: f.Sym,
+ isym: methodWrapper(it, f),
+ tsym: methodWrapper(t, f),
type_: typecheck.NewMethodType(f.Type, t),
mtype: typecheck.NewMethodType(f.Type, nil),
}
ms = append(ms, sig)
-
- this := f.Type.Recv().Type
-
- if !sig.isym.Siggen() {
- sig.isym.SetSiggen(true)
- if !types.Identical(this, it) {
- genwrapper(it, f, sig.isym)
- }
- }
-
- if !sig.tsym.Siggen() {
- sig.tsym.SetSiggen(true)
- if !types.Identical(this, t) {
- genwrapper(t, f, sig.tsym)
- }
- }
}
return ms
@@ -407,11 +389,7 @@ func imethods(t *types.Type) []*typeSig {
// IfaceType.Method is not in the reflect data.
// Generate the method body, so that compiled
// code can refer to it.
- isym := ir.MethodSym(t, f.Sym)
- if !isym.Siggen() {
- isym.SetSiggen(true)
- genwrapper(t, f, isym)
- }
+ methodWrapper(t, f)
}
return methods
@@ -636,8 +614,8 @@ func dextratypeData(lsym *obj.LSym, ot int, t *types.Type) int {
ot = objw.SymPtrOff(lsym, ot, nsym)
ot = dmethodptrOff(lsym, ot, WriteType(a.mtype))
- ot = dmethodptrOff(lsym, ot, a.isym.Linksym())
- ot = dmethodptrOff(lsym, ot, a.tsym.Linksym())
+ ot = dmethodptrOff(lsym, ot, a.isym)
+ ot = dmethodptrOff(lsym, ot, a.tsym)
}
return ot
}
@@ -812,8 +790,8 @@ func dcommontype(lsym *obj.LSym, t *types.Type) int {
// TrackSym returns the symbol for tracking use of field/method f, assumed
// to be a member of struct/interface type t.
-func TrackSym(t *types.Type, f *types.Field) *types.Sym {
- return ir.Pkgs.Track.Lookup(t.ShortString() + "." + f.Sym.Name)
+func TrackSym(t *types.Type, f *types.Field) *obj.LSym {
+ return ir.Pkgs.Track.Lookup(t.ShortString() + "." + f.Sym.Name).Linksym()
}
func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
@@ -845,12 +823,24 @@ func TypeSym(t *types.Type) *types.Sym {
return s
}
+func TypeLinksymPrefix(prefix string, t *types.Type) *obj.LSym {
+ return TypeSymPrefix(prefix, t).Linksym()
+}
+
+func TypeLinksymLookup(name string) *obj.LSym {
+ return types.TypeSymLookup(name).Linksym()
+}
+
+func TypeLinksym(t *types.Type) *obj.LSym {
+ return TypeSym(t).Linksym()
+}
+
func TypePtr(t *types.Type) *ir.AddrExpr {
s := TypeSym(t)
if s.Def == nil {
n := ir.NewNameAt(src.NoXPos, s)
n.SetType(types.Types[types.TUINT8])
- n.Class_ = ir.PEXTERN
+ n.Class = ir.PEXTERN
n.SetTypecheck(1)
s.Def = n
}
@@ -869,10 +859,10 @@ func ITabAddr(t, itype *types.Type) *ir.AddrExpr {
if s.Def == nil {
n := typecheck.NewName(s)
n.SetType(types.Types[types.TUINT8])
- n.Class_ = ir.PEXTERN
+ n.Class = ir.PEXTERN
n.SetTypecheck(1)
s.Def = n
- itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
+ itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: n.Linksym()})
}
n := typecheck.NodAddr(ir.AsNode(s.Def))
@@ -1269,7 +1259,7 @@ func genfun(t, it *types.Type) []*obj.LSym {
// so we can find the intersect in a single pass
for _, m := range methods {
if m.name == sigs[0].name {
- out = append(out, m.isym.Linksym())
+ out = append(out, m.isym)
sigs = sigs[1:]
if len(sigs) == 0 {
break
@@ -1378,8 +1368,12 @@ func WriteTabs() {
// name nameOff
// typ typeOff // pointer to symbol
// }
- nsym := dname(p.s.Name, "", nil, true)
- tsym := WriteType(p.t)
+ nsym := dname(p.Sym().Name, "", nil, true)
+ t := p.Type()
+ if p.Class != ir.PFUNC {
+ t = types.NewPtr(t)
+ }
+ tsym := WriteType(t)
ot = objw.SymPtrOff(s, ot, nsym)
ot = objw.SymPtrOff(s, ot, tsym)
// Plugin exports symbols as interfaces. Mark their types
@@ -1391,7 +1385,7 @@ func WriteTabs() {
ot = 0
s = base.Ctxt.Lookup("go.plugin.exports")
for _, p := range ptabs {
- ot = objw.SymPtr(s, ot, p.s.Linksym(), 0)
+ ot = objw.SymPtr(s, ot, p.Linksym(), 0)
}
objw.Global(s, int32(ot), int16(obj.RODATA))
}
@@ -1571,7 +1565,7 @@ func dgcprog(t *types.Type) (*obj.LSym, int64) {
if t.Width == types.BADWIDTH {
base.Fatalf("dgcprog: %v badwidth", t)
}
- lsym := TypeSymPrefix(".gcprog", t).Linksym()
+ lsym := TypeLinksymPrefix(".gcprog", t)
var p gcProg
p.init(lsym)
p.emit(t, 0)
@@ -1680,7 +1674,7 @@ func ZeroAddr(size int64) ir.Node {
if s.Def == nil {
x := typecheck.NewName(s)
x.SetType(types.Types[types.TUINT8])
- x.Class_ = ir.PEXTERN
+ x.Class = ir.PEXTERN
x.SetTypecheck(1)
s.Def = x
}
@@ -1710,13 +1704,7 @@ func CollectPTabs() {
if s.Pkg.Name != "main" {
continue
}
- if n.Type().Kind() == types.TFUNC && n.Class_ == ir.PFUNC {
- // function
- ptabs = append(ptabs, ptabEntry{s: s, t: s.Def.Type()})
- } else {
- // variable
- ptabs = append(ptabs, ptabEntry{s: s, t: types.NewPtr(s.Def.Type())})
- }
+ ptabs = append(ptabs, n)
}
}
@@ -1740,22 +1728,28 @@ func CollectPTabs() {
//
// rcvr - U
// method - M func (t T)(), a TFIELD type struct
-// newnam - the eventual mangled name of this function
-func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
- if false && base.Flag.LowerR != 0 {
- fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
+func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym {
+ newnam := ir.MethodSym(rcvr, method.Sym)
+ lsym := newnam.Linksym()
+ if newnam.Siggen() {
+ return lsym
+ }
+ newnam.SetSiggen(true)
+
+ if types.Identical(rcvr, method.Type.Recv().Type) {
+ return lsym
}
// Only generate (*T).M wrappers for T.M in T's own package.
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg {
- return
+ return lsym
}
// Only generate I.M wrappers for I in I's own package
// but keep doing it for error.Error (was issue #29304).
if rcvr.IsInterface() && rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && rcvr != types.ErrorType {
- return
+ return lsym
}
base.Pos = base.AutogeneratedPos
@@ -1804,7 +1798,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
} else {
fn.SetWrapper(true) // ignore frame for panic+recover matching
call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
- call.Args.Set(ir.ParamNames(tfn.Type()))
+ call.Args = ir.ParamNames(tfn.Type())
call.IsDDD = tfn.Type().IsVariadic()
if method.Type.NumResults() > 0 {
ret := ir.NewReturnStmt(base.Pos, nil)
@@ -1815,10 +1809,6 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
}
}
- if false && base.Flag.LowerR != 0 {
- ir.DumpList("genwrapper body", fn.Body)
- }
-
typecheck.FinishFuncBody()
if base.Debug.DclStack != 0 {
types.CheckDclstack()
@@ -1838,6 +1828,8 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
ir.CurFunc = nil
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
+
+ return lsym
}
var ZeroSize int64
@@ -1845,7 +1837,7 @@ var ZeroSize int64
// MarkTypeUsedInInterface marks that type t is converted to an interface.
// This information is used in the linker in dead method elimination.
func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {
- tsym := TypeSym(t).Linksym()
+ tsym := TypeLinksym(t)
// Emit a marker relocation. The linker will know the type is converted
// to an interface if "from" is reachable.
r := obj.Addrel(from)
@@ -1858,7 +1850,7 @@ func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {
func MarkUsedIfaceMethod(n *ir.CallExpr) {
dot := n.X.(*ir.SelectorExpr)
ityp := dot.X.Type()
- tsym := TypeSym(ityp).Linksym()
+ tsym := TypeLinksym(ityp)
r := obj.Addrel(ir.CurFunc.LSym)
r.Sym = tsym
// dot.Xoffset is the method index * Widthptr (the offset of code pointer
diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go
index a68c82ba97..530918da4d 100644
--- a/src/cmd/compile/internal/ssa/deadstore.go
+++ b/src/cmd/compile/internal/ssa/deadstore.go
@@ -148,7 +148,7 @@ func elimDeadAutosGeneric(f *Func) {
case OpAddr, OpLocalAddr:
// Propagate the address if it points to an auto.
n, ok := v.Aux.(*ir.Name)
- if !ok || n.Class() != ir.PAUTO {
+ if !ok || n.Class != ir.PAUTO {
return
}
if addr[v] == nil {
@@ -159,7 +159,7 @@ func elimDeadAutosGeneric(f *Func) {
case OpVarDef, OpVarKill:
// v should be eliminated if we eliminate the auto.
n, ok := v.Aux.(*ir.Name)
- if !ok || n.Class() != ir.PAUTO {
+ if !ok || n.Class != ir.PAUTO {
return
}
if elim[v] == nil {
@@ -175,7 +175,7 @@ func elimDeadAutosGeneric(f *Func) {
// may not be used by the inline code, but will be used by
// panic processing).
n, ok := v.Aux.(*ir.Name)
- if !ok || n.Class() != ir.PAUTO {
+ if !ok || n.Class != ir.PAUTO {
return
}
if !used[n] {
@@ -307,7 +307,7 @@ func elimUnreadAutos(f *Func) {
if !ok {
continue
}
- if n.Class() != ir.PAUTO {
+ if n.Class != ir.PAUTO {
continue
}
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index 8712ff78c1..32e6d09d1b 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -70,7 +70,7 @@ func (TestFrontend) StringData(s string) *obj.LSym {
}
func (TestFrontend) Auto(pos src.XPos, t *types.Type) *ir.Name {
n := ir.NewNameAt(pos, &types.Sym{Name: "aFakeAuto"})
- n.SetClass(ir.PAUTO)
+ n.Class = ir.PAUTO
return n
}
func (d TestFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go
index 849c9e8967..4378f2d627 100644
--- a/src/cmd/compile/internal/ssa/writebarrier.go
+++ b/src/cmd/compile/internal/ssa/writebarrier.go
@@ -5,6 +5,7 @@
package ssa
import (
+ "cmd/compile/internal/reflectdata"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/objabi"
@@ -270,11 +271,11 @@ func writebarrier(f *Func) {
case OpMoveWB:
fn = typedmemmove
val = w.Args[1]
- typ = w.Aux.(*types.Type).Symbol()
+ typ = reflectdata.TypeLinksym(w.Aux.(*types.Type))
nWBops--
case OpZeroWB:
fn = typedmemclr
- typ = w.Aux.(*types.Type).Symbol()
+ typ = reflectdata.TypeLinksym(w.Aux.(*types.Type))
nWBops--
case OpVarDef, OpVarLive, OpVarKill:
}
diff --git a/src/cmd/compile/internal/ssagen/abi.go b/src/cmd/compile/internal/ssagen/abi.go
index af08fcb7c3..1c013dd2d8 100644
--- a/src/cmd/compile/internal/ssagen/abi.go
+++ b/src/cmd/compile/internal/ssagen/abi.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:generate go run mkbuiltin.go
-
package ssagen
import (
@@ -168,7 +166,7 @@ func selectLSym(f *ir.Func, hasBody bool) {
f.LSym = nam.Sym().LinksymABI0()
needABIWrapper, wrapperABI = true, obj.ABIInternal
} else {
- f.LSym = nam.Sym().Linksym()
+ f.LSym = nam.Linksym()
// No ABI override. Check that the symbol is
// using the expected ABI.
want := obj.ABIInternal
@@ -305,7 +303,7 @@ func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
tail = ir.NewBranchStmt(base.Pos, ir.ORETJMP, f.Nname.Sym())
} else {
call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
- call.Args.Set(ir.ParamNames(tfn.Type()))
+ call.Args = ir.ParamNames(tfn.Type())
call.IsDDD = tfn.Type().IsVariadic()
tail = call
if tfn.Type().NumResults() > 0 {
diff --git a/src/cmd/compile/internal/ssagen/nowb.go b/src/cmd/compile/internal/ssagen/nowb.go
index 7b2e68c8e7..60cfb2f698 100644
--- a/src/cmd/compile/internal/ssagen/nowb.go
+++ b/src/cmd/compile/internal/ssagen/nowb.go
@@ -76,7 +76,7 @@ func (c *nowritebarrierrecChecker) findExtraCalls(nn ir.Node) {
return
}
fn := n.X.(*ir.Name)
- if fn.Class_ != ir.PFUNC || fn.Name().Defn == nil {
+ if fn.Class != ir.PFUNC || fn.Defn == nil {
return
}
if !types.IsRuntimePkg(fn.Sym().Pkg) || fn.Sym().Name != "systemstack" {
@@ -88,7 +88,7 @@ func (c *nowritebarrierrecChecker) findExtraCalls(nn ir.Node) {
switch arg.Op() {
case ir.ONAME:
arg := arg.(*ir.Name)
- callee = arg.Name().Defn.(*ir.Func)
+ callee = arg.Defn.(*ir.Func)
case ir.OCLOSURE:
arg := arg.(*ir.ClosureExpr)
callee = arg.Func
diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go
index bc6be20d86..bbd319d735 100644
--- a/src/cmd/compile/internal/ssagen/pgen.go
+++ b/src/cmd/compile/internal/ssagen/pgen.go
@@ -34,11 +34,11 @@ import (
// the top of the stack and increasing in size.
// Non-autos sort on offset.
func cmpstackvarlt(a, b *ir.Name) bool {
- if (a.Class_ == ir.PAUTO) != (b.Class_ == ir.PAUTO) {
- return b.Class_ == ir.PAUTO
+ if (a.Class == ir.PAUTO) != (b.Class == ir.PAUTO) {
+ return b.Class == ir.PAUTO
}
- if a.Class_ != ir.PAUTO {
+ if a.Class != ir.PAUTO {
return a.FrameOffset() < b.FrameOffset()
}
@@ -79,14 +79,14 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
// Mark the PAUTO's unused.
for _, ln := range fn.Dcl {
- if ln.Class_ == ir.PAUTO {
+ if ln.Class == ir.PAUTO {
ln.SetUsed(false)
}
}
for _, l := range f.RegAlloc {
if ls, ok := l.(ssa.LocalSlot); ok {
- ls.N.Name().SetUsed(true)
+ ls.N.SetUsed(true)
}
}
@@ -94,14 +94,14 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
for _, b := range f.Blocks {
for _, v := range b.Values {
if n, ok := v.Aux.(*ir.Name); ok {
- switch n.Class_ {
+ switch n.Class {
case ir.PPARAM, ir.PPARAMOUT:
// Don't modify nodfp; it is a global.
if n != ir.RegFP {
- n.Name().SetUsed(true)
+ n.SetUsed(true)
}
case ir.PAUTO:
- n.Name().SetUsed(true)
+ n.SetUsed(true)
}
}
if !scratchUsed {
@@ -120,7 +120,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
// Reassign stack offsets of the locals that are used.
lastHasPtr := false
for i, n := range fn.Dcl {
- if n.Op() != ir.ONAME || n.Class_ != ir.PAUTO {
+ if n.Op() != ir.ONAME || n.Class != ir.PAUTO {
continue
}
if !n.Used() {
@@ -207,7 +207,7 @@ func init() {
func StackOffset(slot ssa.LocalSlot) int32 {
n := slot.N
var off int64
- switch n.Class_ {
+ switch n.Class {
case ir.PAUTO:
off = n.FrameOffset()
if base.Ctxt.FixedFrameSize() == 0 {
@@ -225,7 +225,7 @@ func StackOffset(slot ssa.LocalSlot) int32 {
// fieldtrack adds R_USEFIELD relocations to fnsym to record any
// struct fields that it used.
-func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
+func fieldtrack(fnsym *obj.LSym, tracked map[*obj.LSym]struct{}) {
if fnsym == nil {
return
}
@@ -233,24 +233,18 @@ func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
return
}
- trackSyms := make([]*types.Sym, 0, len(tracked))
+ trackSyms := make([]*obj.LSym, 0, len(tracked))
for sym := range tracked {
trackSyms = append(trackSyms, sym)
}
- sort.Sort(symByName(trackSyms))
+ sort.Slice(trackSyms, func(i, j int) bool { return trackSyms[i].Name < trackSyms[j].Name })
for _, sym := range trackSyms {
r := obj.Addrel(fnsym)
- r.Sym = sym.Linksym()
+ r.Sym = sym
r.Type = objabi.R_USEFIELD
}
}
-type symByName []*types.Sym
-
-func (a symByName) Len() int { return len(a) }
-func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
-func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-
// largeStack is info about a function whose stack frame is too large (rare).
type largeStack struct {
locals int64
diff --git a/src/cmd/compile/internal/ssagen/pgen_test.go b/src/cmd/compile/internal/ssagen/pgen_test.go
index 82d8447e9f..69ed8ad74e 100644
--- a/src/cmd/compile/internal/ssagen/pgen_test.go
+++ b/src/cmd/compile/internal/ssagen/pgen_test.go
@@ -46,7 +46,7 @@ func TestCmpstackvar(t *testing.T) {
n := typecheck.NewName(s)
n.SetType(t)
n.SetFrameOffset(xoffset)
- n.Class_ = cl
+ n.Class = cl
return n
}
testdata := []struct {
@@ -161,7 +161,7 @@ func TestStackvarSort(t *testing.T) {
n := typecheck.NewName(s)
n.SetType(t)
n.SetFrameOffset(xoffset)
- n.Class_ = cl
+ n.Class = cl
return n
}
inp := []*ir.Name{
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go
index 0da6ab3272..5998c42012 100644
--- a/src/cmd/compile/internal/ssagen/ssa.go
+++ b/src/cmd/compile/internal/ssagen/ssa.go
@@ -436,7 +436,7 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
var args []ssa.Param
var results []ssa.Param
for _, n := range fn.Dcl {
- switch n.Class_ {
+ switch n.Class {
case ir.PPARAM:
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type()), n, s.sp, s.startmem)
args = append(args, ssa.Param{Type: n.Type(), Offset: int32(n.FrameOffset())})
@@ -457,13 +457,13 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
case ir.PFUNC:
// local function - already handled by frontend
default:
- s.Fatalf("local variable with class %v unimplemented", n.Class_)
+ s.Fatalf("local variable with class %v unimplemented", n.Class)
}
}
// Populate SSAable arguments.
for _, n := range fn.Dcl {
- if n.Class_ == ir.PPARAM && s.canSSA(n) {
+ if n.Class == ir.PPARAM && s.canSSA(n) {
v := s.newValue0A(ssa.OpArg, n.Type(), n)
s.vars[n] = v
s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself.
@@ -1166,7 +1166,7 @@ func (s *state) stmt(n ir.Node) {
case ir.OCALLINTER:
n := n.(*ir.CallExpr)
s.callResult(n, callNormal)
- if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class_ == ir.PFUNC {
+ if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class == ir.PFUNC {
if fn := n.X.Sym().Name; base.Flag.CompilingRuntime && fn == "throw" ||
n.X.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap") {
m := s.mem()
@@ -1242,7 +1242,7 @@ func (s *state) stmt(n ir.Node) {
case ir.ODCL:
n := n.(*ir.Decl)
- if n.X.(*ir.Name).Class_ == ir.PAUTOHEAP {
+ if n.X.Class == ir.PAUTOHEAP {
s.Fatalf("DCL %v", n)
}
@@ -1634,7 +1634,7 @@ func (s *state) stmt(n ir.Node) {
if !v.Addrtaken() {
s.Fatalf("VARLIVE variable %v must have Addrtaken set", v)
}
- switch v.Class_ {
+ switch v.Class {
case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
default:
s.Fatalf("VARLIVE variable %v must be Auto or Arg", v)
@@ -2106,13 +2106,13 @@ func (s *state) expr(n ir.Node) *ssa.Value {
return s.newValue3(ssa.OpSliceMake, n.Type(), ptr, len, len)
case ir.OCFUNC:
n := n.(*ir.UnaryExpr)
- aux := n.X.Sym().Linksym()
+ aux := n.X.(*ir.Name).Linksym()
return s.entryNewValue1A(ssa.OpAddr, n.Type(), aux, s.sb)
case ir.ONAME:
n := n.(*ir.Name)
- if n.Class_ == ir.PFUNC {
+ if n.Class == ir.PFUNC {
// "value" of a function is the address of the function's closure
- sym := staticdata.FuncSym(n.Sym()).Linksym()
+ sym := staticdata.FuncLinksym(n)
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type()), sym, s.sb)
}
if s.canSSA(n) {
@@ -3003,7 +3003,7 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
if inplace {
if sn.Op() == ir.ONAME {
sn := sn.(*ir.Name)
- if sn.Class_ != ir.PEXTERN {
+ if sn.Class != ir.PEXTERN {
// Tell liveness we're about to build a new slice
s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
}
@@ -3222,7 +3222,7 @@ func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask
// If this assignment clobbers an entire local variable, then emit
// OpVarDef so liveness analysis knows the variable is redefined.
- if base := clobberBase(left); base.Op() == ir.ONAME && base.(*ir.Name).Class_ != ir.PEXTERN && skip == 0 {
+ if base := clobberBase(left); base.Op() == ir.ONAME && base.(*ir.Name).Class != ir.PEXTERN && skip == 0 {
s.vars[memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, base.(*ir.Name), s.mem(), !ir.IsAutoTmp(base))
}
@@ -4385,7 +4385,7 @@ func (s *state) openDeferRecord(n *ir.CallExpr) {
closureVal := s.expr(fn)
closure := s.openDeferSave(nil, fn.Type(), closureVal)
opendefer.closureNode = closure.Aux.(*ir.Name)
- if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class_ == ir.PFUNC) {
+ if !(fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC) {
opendefer.closure = closure
}
} else if n.Op() == ir.OCALLMETH {
@@ -4578,7 +4578,7 @@ func (s *state) openDeferExit() {
call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, aux, codeptr, v, s.mem())
}
} else {
- aux := ssa.StaticAuxCall(fn.Sym().Linksym(), ACArgs, ACResults)
+ aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults)
if testLateExpansion {
callArgs = append(callArgs, s.mem())
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
@@ -4651,7 +4651,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
switch n.Op() {
case ir.OCALLFUNC:
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
- if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class_ == ir.PFUNC {
+ if k == callNormal && fn.Op() == ir.ONAME && fn.(*ir.Name).Class == ir.PFUNC {
fn := fn.(*ir.Name)
sym = fn.Sym()
break
@@ -4867,7 +4867,9 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
s.vars[memVar] = call
}
// Insert OVARLIVE nodes
- s.stmtList(n.Body)
+ for _, name := range n.KeepAlive {
+ s.stmt(ir.NewUnaryExpr(n.Pos(), ir.OVARLIVE, name))
+ }
// Finish block for defers
if k == callDefer || k == callDeferStack {
@@ -4956,10 +4958,10 @@ func (s *state) addr(n ir.Node) *ssa.Value {
fallthrough
case ir.ONAME:
n := n.(*ir.Name)
- switch n.Class_ {
+ switch n.Class {
case ir.PEXTERN:
// global variable
- v := s.entryNewValue1A(ssa.OpAddr, t, n.Sym().Linksym(), s.sb)
+ v := s.entryNewValue1A(ssa.OpAddr, t, n.Linksym(), s.sb)
// TODO: Make OpAddr use AuxInt as well as Aux.
if offset != 0 {
v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, offset, v)
@@ -4985,7 +4987,7 @@ func (s *state) addr(n ir.Node) *ssa.Value {
// that cse works on their addresses
return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
default:
- s.Fatalf("variable address class %v not implemented", n.Class_)
+ s.Fatalf("variable address class %v not implemented", n.Class)
return nil
}
case ir.ORESULT:
@@ -5094,10 +5096,10 @@ func (s *state) canSSAName(name *ir.Name) bool {
if ir.IsParamHeapCopy(name) {
return false
}
- if name.Class_ == ir.PAUTOHEAP {
+ if name.Class == ir.PAUTOHEAP {
s.Fatalf("canSSA of PAUTOHEAP %v", name)
}
- switch name.Class_ {
+ switch name.Class {
case ir.PEXTERN:
return false
case ir.PPARAMOUT:
@@ -5115,7 +5117,7 @@ func (s *state) canSSAName(name *ir.Name) bool {
return false
}
}
- if name.Class_ == ir.PPARAM && name.Sym() != nil && name.Sym().Name == ".this" {
+ if name.Class == ir.PPARAM && name.Sym() != nil && name.Sym().Name == ".this" {
// wrappers generated by genwrapper need to update
// the .this pointer in place.
// TODO: treat as a PPARAMOUT?
@@ -5978,8 +5980,8 @@ func (s *state) floatToUint(cvttab *f2uCvtTab, n ir.Node, x *ssa.Value, ft, tt *
// commaok indicates whether to panic or return a bool.
// If commaok is false, resok will be nil.
func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
- iface := s.expr(n.X) // input interface
- target := s.expr(n.Ntype) // target type
+ iface := s.expr(n.X) // input interface
+ target := s.expr(n.DstType) // target type
byteptr := s.f.Config.Types.BytePtr
if n.Type().IsInterface() {
@@ -6086,7 +6088,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
targetITab = target
} else {
// Looking for pointer to itab for target type and source interface.
- targetITab = s.expr(n.Itab[0])
+ targetITab = s.expr(n.Itab)
}
var tmp ir.Node // temporary for use with large types
@@ -6113,7 +6115,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
if !commaok {
// on failure, panic by calling panicdottype
s.startBlock(bFail)
- taddr := s.expr(n.Ntype.(*ir.AddrExpr).Alloc)
+ taddr := s.expr(n.SrcType)
if n.X.Type().IsEmptyInterface() {
s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
} else {
@@ -6208,7 +6210,7 @@ func (s *state) mem() *ssa.Value {
}
func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
- if n.Class_ == ir.Pxxx {
+ if n.Class == ir.Pxxx {
// Don't track our marker nodes (memVar etc.).
return
}
@@ -6216,12 +6218,12 @@ func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
// Don't track temporary variables.
return
}
- if n.Class_ == ir.PPARAMOUT {
+ if n.Class == ir.PPARAMOUT {
// Don't track named output values. This prevents return values
// from being assigned too early. See #14591 and #14762. TODO: allow this.
return
}
- loc := ssa.LocalSlot{N: n.Name(), Type: n.Type(), Off: 0}
+ loc := ssa.LocalSlot{N: n, Type: n.Type(), Off: 0}
values, ok := s.f.NamedValues[loc]
if !ok {
s.f.Names = append(s.f.Names, loc)
@@ -6739,8 +6741,8 @@ func defframe(s *State, e *ssafn) {
if !n.Needzero() {
continue
}
- if n.Class_ != ir.PAUTO {
- e.Fatalf(n.Pos(), "needzero class %d", n.Class_)
+ if n.Class != ir.PAUTO {
+ e.Fatalf(n.Pos(), "needzero class %d", n.Class)
}
if n.Type().Size()%int64(types.PtrSize) != 0 || n.FrameOffset()%int64(types.PtrSize) != 0 || n.Type().Size() == 0 {
e.Fatalf(n.Pos(), "var %L has size %d offset %d", n, n.Type().Size(), n.Offset_)
@@ -6824,14 +6826,14 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
a.Name = obj.NAME_EXTERN
a.Sym = n
case *ir.Name:
- if n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT {
+ if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
a.Name = obj.NAME_PARAM
- a.Sym = ir.Orig(n).Sym().Linksym()
+ a.Sym = ir.Orig(n).(*ir.Name).Linksym()
a.Offset += n.FrameOffset()
break
}
a.Name = obj.NAME_AUTO
- a.Sym = n.Sym().Linksym()
+ a.Sym = n.Linksym()
a.Offset += n.FrameOffset()
default:
v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
@@ -6963,10 +6965,10 @@ func CheckLoweredGetClosurePtr(v *ssa.Value) {
func AddrAuto(a *obj.Addr, v *ssa.Value) {
n, off := ssa.AutoVar(v)
a.Type = obj.TYPE_MEM
- a.Sym = n.Sym().Linksym()
+ a.Sym = n.Linksym()
a.Reg = int16(Arch.REGSP)
a.Offset = n.FrameOffset() + off
- if n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT {
+ if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
a.Name = obj.NAME_PARAM
} else {
a.Name = obj.NAME_AUTO
@@ -6979,7 +6981,7 @@ func (s *State) AddrScratch(a *obj.Addr) {
}
a.Type = obj.TYPE_MEM
a.Name = obj.NAME_AUTO
- a.Sym = s.ScratchFpMem.Sym().Linksym()
+ a.Sym = s.ScratchFpMem.Linksym()
a.Reg = int16(Arch.REGSP)
a.Offset = s.ScratchFpMem.Offset_
}
@@ -7196,7 +7198,7 @@ func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
node := parent.N
- if node.Class_ != ir.PAUTO || node.Name().Addrtaken() {
+ if node.Class != ir.PAUTO || node.Addrtaken() {
// addressed things and non-autos retain their parents (i.e., cannot truly be split)
return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
}
@@ -7206,7 +7208,7 @@ func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t
s.Def = n
ir.AsNode(s.Def).Name().SetUsed(true)
n.SetType(t)
- n.Class_ = ir.PAUTO
+ n.Class = ir.PAUTO
n.SetEsc(ir.EscNever)
n.Curfn = e.curfn
e.curfn.Dcl = append(e.curfn.Dcl, n)
diff --git a/src/cmd/compile/internal/staticdata/data.go b/src/cmd/compile/internal/staticdata/data.go
index 342a2e2bbc..94fa6760a0 100644
--- a/src/cmd/compile/internal/staticdata/data.go
+++ b/src/cmd/compile/internal/staticdata/data.go
@@ -37,8 +37,8 @@ func InitAddr(n *ir.Name, noff int64, a *ir.Name, aoff int64) {
if a.Op() != ir.ONAME {
base.Fatalf("addrsym a op %v", a.Op())
}
- s := n.Sym().Linksym()
- s.WriteAddr(base.Ctxt, noff, types.PtrSize, a.Sym().Linksym(), aoff)
+ s := n.Linksym()
+ s.WriteAddr(base.Ctxt, noff, types.PtrSize, a.Linksym(), aoff)
}
// InitFunc writes the static address of f to n. f must be a global function.
@@ -50,21 +50,21 @@ func InitFunc(n *ir.Name, noff int64, f *ir.Name) {
if n.Sym() == nil {
base.Fatalf("pfuncsym nil n sym")
}
- if f.Class_ != ir.PFUNC {
- base.Fatalf("pfuncsym class not PFUNC %d", f.Class_)
+ if f.Class != ir.PFUNC {
+ base.Fatalf("pfuncsym class not PFUNC %d", f.Class)
}
- s := n.Sym().Linksym()
- s.WriteAddr(base.Ctxt, noff, types.PtrSize, FuncSym(f.Sym()).Linksym(), 0)
+ s := n.Linksym()
+ s.WriteAddr(base.Ctxt, noff, types.PtrSize, FuncLinksym(f), 0)
}
// InitSlice writes a static slice symbol {&arr, lencap, lencap} to n+noff.
// InitSlice does not modify n.
func InitSlice(n *ir.Name, noff int64, arr *ir.Name, lencap int64) {
- s := n.Sym().Linksym()
+ s := n.Linksym()
if arr.Op() != ir.ONAME {
base.Fatalf("slicesym non-name arr %v", arr)
}
- s.WriteAddr(base.Ctxt, noff, types.PtrSize, arr.Sym().Linksym(), 0)
+ s.WriteAddr(base.Ctxt, noff, types.PtrSize, arr.Linksym(), 0)
s.WriteInt(base.Ctxt, noff+types.SliceLenOffset, types.PtrSize, lencap)
s.WriteInt(base.Ctxt, noff+types.SliceCapOffset, types.PtrSize, lencap)
}
@@ -141,7 +141,7 @@ func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.
if readonly {
sym = StringSym(pos, string(data))
} else {
- sym = slicedata(pos, string(data)).Sym().Linksym()
+ sym = slicedata(pos, string(data)).Linksym()
}
if len(hash) > 0 {
sum := sha256.Sum256(data)
@@ -189,7 +189,7 @@ func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.
} else {
// Emit a zero-length data symbol
// and then fix up length and content to use file.
- symdata = slicedata(pos, "").Sym().Linksym()
+ symdata = slicedata(pos, "").Linksym()
symdata.Size = size
symdata.Type = objabi.SNOPTRDATA
info := symdata.NewFileInfo()
@@ -209,7 +209,7 @@ func slicedata(pos src.XPos, s string) *ir.Name {
symnode := typecheck.NewName(sym)
sym.Def = symnode
- lsym := sym.Linksym()
+ lsym := symnode.Linksym()
off := dstringdata(lsym, 0, s, pos, "slice")
objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL)
@@ -258,6 +258,13 @@ func FuncSym(s *types.Sym) *types.Sym {
return sf
}
+func FuncLinksym(n *ir.Name) *obj.LSym {
+ if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
+ base.Fatalf("expected func name: %v", n)
+ }
+ return FuncSym(n.Sym()).Linksym()
+}
+
// NeedFuncSym ensures that s·f is exported.
// It is only used with -dynlink.
// When not compiling for dynamic linking,
@@ -311,7 +318,7 @@ func InitConst(n *ir.Name, noff int64, c ir.Node, wid int) {
if c.Op() != ir.OLITERAL {
base.Fatalf("litsym c op %v", c.Op())
}
- s := n.Sym().Linksym()
+ s := n.Linksym()
switch u := c.Val(); u.Kind() {
case constant.Bool:
i := int64(obj.Bool2int(constant.BoolVal(u)))
diff --git a/src/cmd/compile/internal/staticdata/embed.go b/src/cmd/compile/internal/staticdata/embed.go
index 55c9a3356e..2e551f0b2c 100644
--- a/src/cmd/compile/internal/staticdata/embed.go
+++ b/src/cmd/compile/internal/staticdata/embed.go
@@ -145,7 +145,7 @@ func WriteEmbed(v *ir.Name) {
if err != nil {
base.ErrorfAt(v.Pos(), "embed %s: %v", file, err)
}
- sym := v.Sym().Linksym()
+ sym := v.Linksym()
off := 0
off = objw.SymPtr(sym, off, fsym, 0) // data string
off = objw.Uintptr(sym, off, uint64(size)) // len
@@ -187,7 +187,7 @@ func WriteEmbed(v *ir.Name) {
}
}
objw.Global(slicedata, int32(off), obj.RODATA|obj.LOCAL)
- sym := v.Sym().Linksym()
+ sym := v.Linksym()
objw.SymPtr(sym, 0, slicedata, 0)
}
}
diff --git a/src/cmd/compile/internal/staticinit/sched.go b/src/cmd/compile/internal/staticinit/sched.go
index 2711f6cec0..ac0b6cd87e 100644
--- a/src/cmd/compile/internal/staticinit/sched.go
+++ b/src/cmd/compile/internal/staticinit/sched.go
@@ -78,15 +78,12 @@ func (s *Schedule) tryStaticInit(nn ir.Node) bool {
// like staticassign but we are copying an already
// initialized value r.
func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Type) bool {
- if rn.Class_ == ir.PFUNC {
+ if rn.Class == ir.PFUNC {
// TODO if roff != 0 { panic }
staticdata.InitFunc(l, loff, rn)
return true
}
- if rn.Class_ != ir.PEXTERN || rn.Sym().Pkg != types.LocalPkg {
- return false
- }
- if rn.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
+ if rn.Class != ir.PEXTERN || rn.Sym().Pkg != types.LocalPkg {
return false
}
if rn.Defn.Op() != ir.OAS {
@@ -95,8 +92,16 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
if rn.Type().IsString() { // perhaps overwritten by cmd/link -X (#34675)
return false
}
+ if rn.Embed != nil {
+ return false
+ }
orig := rn
r := rn.Defn.(*ir.AssignStmt).Y
+ if r == nil {
+ // No explicit initialization value. Probably zeroed but perhaps
+ // supplied externally and of unknown value.
+ return false
+ }
for r.Op() == ir.OCONVNOP && !types.Identical(r.Type(), typ) {
r = r.(*ir.ConvExpr).X
@@ -104,7 +109,7 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
switch r.Op() {
case ir.OMETHEXPR:
- r = r.(*ir.MethodExpr).FuncName()
+ r = r.(*ir.SelectorExpr).FuncName()
fallthrough
case ir.ONAME:
r := r.(*ir.Name)
@@ -165,7 +170,7 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
}
x := e.Expr
if x.Op() == ir.OMETHEXPR {
- x = x.(*ir.MethodExpr).FuncName()
+ x = x.(*ir.SelectorExpr).FuncName()
}
if x.Op() == ir.ONAME && s.staticcopy(l, loff+e.Xoffset, x.(*ir.Name), typ) {
continue
@@ -185,6 +190,11 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
}
func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Type) bool {
+ if r == nil {
+ // No explicit initialization value. Either zero or supplied
+ // externally.
+ return true
+ }
for r.Op() == ir.OCONVNOP {
r = r.(*ir.ConvExpr).X
}
@@ -195,7 +205,7 @@ func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Ty
return s.staticcopy(l, loff, r, typ)
case ir.OMETHEXPR:
- r := r.(*ir.MethodExpr)
+ r := r.(*ir.SelectorExpr)
return s.staticcopy(l, loff, r.FuncName(), typ)
case ir.ONIL:
@@ -236,7 +246,7 @@ func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Ty
case ir.OSTR2BYTES:
r := r.(*ir.ConvExpr)
- if l.Class_ == ir.PEXTERN && r.X.Op() == ir.OLITERAL {
+ if l.Class == ir.PEXTERN && r.X.Op() == ir.OLITERAL {
sval := ir.StringVal(r.X)
staticdata.InitSliceBytes(l, loff, sval)
return true
@@ -313,7 +323,7 @@ func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Ty
return val.Op() == ir.ONIL
}
- reflectdata.MarkTypeUsedInInterface(val.Type(), l.Sym().Linksym())
+ reflectdata.MarkTypeUsedInInterface(val.Type(), l.Linksym())
var itab *ir.AddrExpr
if typ.IsEmptyInterface() {
@@ -445,7 +455,7 @@ func StaticName(t *types.Type) *ir.Name {
statuniqgen++
typecheck.Declare(n, ir.PEXTERN)
n.SetType(t)
- n.Sym().Linksym().Set(obj.AttrLocal, true)
+ n.Linksym().Set(obj.AttrLocal, true)
return n
}
@@ -461,7 +471,7 @@ func StaticLoc(n ir.Node) (name *ir.Name, offset int64, ok bool) {
return n, 0, true
case ir.OMETHEXPR:
- n := n.(*ir.MethodExpr)
+ n := n.(*ir.SelectorExpr)
return StaticLoc(n.FuncName())
case ir.ODOT:
diff --git a/src/cmd/compile/internal/syntax/operator_string.go b/src/cmd/compile/internal/syntax/operator_string.go
index 3c759b2e9b..a7cd40fb13 100644
--- a/src/cmd/compile/internal/syntax/operator_string.go
+++ b/src/cmd/compile/internal/syntax/operator_string.go
@@ -1,9 +1,37 @@
-// Code generated by "stringer -type Operator -linecomment"; DO NOT EDIT.
+// Code generated by "stringer -type Operator -linecomment tokens.go"; DO NOT EDIT.
package syntax
import "strconv"
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[Def-1]
+ _ = x[Not-2]
+ _ = x[Recv-3]
+ _ = x[OrOr-4]
+ _ = x[AndAnd-5]
+ _ = x[Eql-6]
+ _ = x[Neq-7]
+ _ = x[Lss-8]
+ _ = x[Leq-9]
+ _ = x[Gtr-10]
+ _ = x[Geq-11]
+ _ = x[Add-12]
+ _ = x[Sub-13]
+ _ = x[Or-14]
+ _ = x[Xor-15]
+ _ = x[Mul-16]
+ _ = x[Div-17]
+ _ = x[Rem-18]
+ _ = x[And-19]
+ _ = x[AndNot-20]
+ _ = x[Shl-21]
+ _ = x[Shr-22]
+}
+
const _Operator_name = ":!<-||&&==!=<<=>>=+-|^*/%&&^<<>>"
var _Operator_index = [...]uint8{0, 1, 2, 4, 6, 8, 10, 12, 13, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 30, 32}
diff --git a/src/cmd/compile/internal/syntax/token_string.go b/src/cmd/compile/internal/syntax/token_string.go
index 3cf5473feb..ef295eb24b 100644
--- a/src/cmd/compile/internal/syntax/token_string.go
+++ b/src/cmd/compile/internal/syntax/token_string.go
@@ -1,9 +1,62 @@
-// Code generated by "stringer -type token -linecomment"; DO NOT EDIT.
+// Code generated by "stringer -type token -linecomment tokens.go"; DO NOT EDIT.
package syntax
import "strconv"
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[_EOF-1]
+ _ = x[_Name-2]
+ _ = x[_Literal-3]
+ _ = x[_Operator-4]
+ _ = x[_AssignOp-5]
+ _ = x[_IncOp-6]
+ _ = x[_Assign-7]
+ _ = x[_Define-8]
+ _ = x[_Arrow-9]
+ _ = x[_Star-10]
+ _ = x[_Lparen-11]
+ _ = x[_Lbrack-12]
+ _ = x[_Lbrace-13]
+ _ = x[_Rparen-14]
+ _ = x[_Rbrack-15]
+ _ = x[_Rbrace-16]
+ _ = x[_Comma-17]
+ _ = x[_Semi-18]
+ _ = x[_Colon-19]
+ _ = x[_Dot-20]
+ _ = x[_DotDotDot-21]
+ _ = x[_Break-22]
+ _ = x[_Case-23]
+ _ = x[_Chan-24]
+ _ = x[_Const-25]
+ _ = x[_Continue-26]
+ _ = x[_Default-27]
+ _ = x[_Defer-28]
+ _ = x[_Else-29]
+ _ = x[_Fallthrough-30]
+ _ = x[_For-31]
+ _ = x[_Func-32]
+ _ = x[_Go-33]
+ _ = x[_Goto-34]
+ _ = x[_If-35]
+ _ = x[_Import-36]
+ _ = x[_Interface-37]
+ _ = x[_Map-38]
+ _ = x[_Package-39]
+ _ = x[_Range-40]
+ _ = x[_Return-41]
+ _ = x[_Select-42]
+ _ = x[_Struct-43]
+ _ = x[_Switch-44]
+ _ = x[_Type-45]
+ _ = x[_Var-46]
+ _ = x[tokenCount-47]
+}
+
const _token_name = "EOFnameliteralopop=opop=:=<-*([{)]},;:....breakcasechanconstcontinuedefaultdeferelsefallthroughforfuncgogotoifimportinterfacemappackagerangereturnselectstructswitchtypevar"
var _token_index = [...]uint8{0, 3, 7, 14, 16, 19, 23, 24, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 42, 47, 51, 55, 60, 68, 75, 80, 84, 95, 98, 102, 104, 108, 110, 116, 125, 128, 135, 140, 146, 152, 158, 164, 168, 171, 171}
diff --git a/src/cmd/compile/internal/syntax/tokens.go b/src/cmd/compile/internal/syntax/tokens.go
index 3b97cb66f2..2936b6576b 100644
--- a/src/cmd/compile/internal/syntax/tokens.go
+++ b/src/cmd/compile/internal/syntax/tokens.go
@@ -6,7 +6,7 @@ package syntax
type token uint
-//go:generate stringer -type token -linecomment
+//go:generate stringer -type token -linecomment tokens.go
const (
_ token = iota
@@ -105,7 +105,7 @@ const (
type Operator uint
-//go:generate stringer -type Operator -linecomment
+//go:generate stringer -type Operator -linecomment tokens.go
const (
_ Operator = iota
diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go
index e22b284e82..d6bf101974 100644
--- a/src/cmd/compile/internal/typecheck/const.go
+++ b/src/cmd/compile/internal/typecheck/const.go
@@ -509,7 +509,7 @@ func EvalConst(n ir.Node) ir.Node {
}
nl := ir.Copy(n).(*ir.AddStringExpr)
- nl.List.Set(s[i:i2])
+ nl.List = s[i:i2]
newList = append(newList, OrigConst(nl, constant.MakeString(strings.Join(strs, ""))))
i = i2 - 1
} else {
@@ -518,7 +518,7 @@ func EvalConst(n ir.Node) ir.Node {
}
nn := ir.Copy(n).(*ir.AddStringExpr)
- nn.List.Set(newList)
+ nn.List = newList
return nn
case ir.OCAP, ir.OLEN:
@@ -564,20 +564,11 @@ func EvalConst(n ir.Node) ir.Node {
return n
}
-func makeInt(i *big.Int) constant.Value {
- if i.IsInt64() {
- return constant.Make(i.Int64()) // workaround #42640 (Int64Val(Make(big.NewInt(10))) returns (10, false), not (10, true))
- }
- return constant.Make(i)
-}
-
func makeFloat64(f float64) constant.Value {
if math.IsInf(f, 0) {
base.Fatalf("infinity is not a valid constant")
}
- v := constant.MakeFloat64(f)
- v = constant.ToFloat(v) // workaround #42641 (MakeFloat64(0).Kind() returns Int, not Float)
- return v
+ return constant.MakeFloat64(f)
}
func makeComplex(real, imag constant.Value) constant.Value {
diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go
index 36057ba2d1..6c3aa3781e 100644
--- a/src/cmd/compile/internal/typecheck/dcl.go
+++ b/src/cmd/compile/internal/typecheck/dcl.go
@@ -15,64 +15,7 @@ import (
"cmd/internal/src"
)
-var DeclContext ir.Class // PEXTERN/PAUTO
-
-func AssignDefn(left []ir.Node, defn ir.Node) {
- for _, n := range left {
- if n.Sym() != nil {
- n.Sym().SetUniq(true)
- }
- }
-
- var nnew, nerr int
- for i, n := range left {
- if ir.IsBlank(n) {
- continue
- }
- if !assignableName(n) {
- base.ErrorfAt(defn.Pos(), "non-name %v on left side of :=", n)
- nerr++
- continue
- }
-
- if !n.Sym().Uniq() {
- base.ErrorfAt(defn.Pos(), "%v repeated on left side of :=", n.Sym())
- n.SetDiag(true)
- nerr++
- continue
- }
-
- n.Sym().SetUniq(false)
- if n.Sym().Block == types.Block {
- continue
- }
-
- nnew++
- n := NewName(n.Sym())
- Declare(n, DeclContext)
- n.Defn = defn
- defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
- left[i] = n
- }
-
- if nnew == 0 && nerr == 0 {
- base.ErrorfAt(defn.Pos(), "no new variables on left side of :=")
- }
-}
-
-// := declarations
-func assignableName(n ir.Node) bool {
- switch n.Op() {
- case ir.ONAME,
- ir.ONONAME,
- ir.OPACK,
- ir.OTYPE,
- ir.OLITERAL:
- return n.Sym() != nil
- }
-
- return false
-}
+var DeclContext ir.Class = ir.PEXTERN // PEXTERN/PAUTO
func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
if tfn.Op() != ir.OTFUNC {
@@ -80,7 +23,8 @@ func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
}
fn := ir.NewFunc(base.Pos)
- fn.Nname = ir.NewFuncNameAt(base.Pos, sym, fn)
+ fn.Nname = ir.NewNameAt(base.Pos, sym)
+ fn.Nname.Func = fn
fn.Nname.Defn = fn
fn.Nname.Ntype = tfn
ir.MarkFunc(fn.Nname)
@@ -89,60 +33,6 @@ func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
return fn
}
-// declare variables from grammar
-// new_name_list (type | [type] = expr_list)
-func DeclVars(vl []*ir.Name, t ir.Ntype, el []ir.Node) []ir.Node {
- var init []ir.Node
- doexpr := len(el) > 0
-
- if len(el) == 1 && len(vl) > 1 {
- e := el[0]
- as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
- as2.Rhs = []ir.Node{e}
- for _, v := range vl {
- as2.Lhs.Append(v)
- Declare(v, DeclContext)
- v.Ntype = t
- v.Defn = as2
- if ir.CurFunc != nil {
- init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
- }
- }
-
- return append(init, as2)
- }
-
- for i, v := range vl {
- var e ir.Node
- if doexpr {
- if i >= len(el) {
- base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
- break
- }
- e = el[i]
- }
-
- Declare(v, DeclContext)
- v.Ntype = t
-
- if e != nil || ir.CurFunc != nil || ir.IsBlank(v) {
- if ir.CurFunc != nil {
- init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
- }
- as := ir.NewAssignStmt(base.Pos, v, e)
- init = append(init, as)
- if e != nil {
- v.Defn = as
- }
- }
- }
-
- if len(el) > len(vl) {
- base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
- }
- return init
-}
-
// Declare records that Node n declares symbol n.Sym in the specified
// declaration context.
func Declare(n *ir.Name, ctxt ir.Class) {
@@ -201,7 +91,7 @@ func Declare(n *ir.Name, ctxt ir.Class) {
s.Lastlineno = base.Pos
s.Def = n
n.Vargen = int32(gen)
- n.Class_ = ctxt
+ n.Class = ctxt
if ctxt == ir.PFUNC {
n.Sym().SetFunc(true)
}
@@ -565,7 +455,7 @@ func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
n := ir.NewNameAt(pos, s)
s.Def = n
n.SetType(t)
- n.Class_ = ir.PAUTO
+ n.Class = ir.PAUTO
n.SetEsc(ir.EscNever)
n.Curfn = curfn
n.SetUsed(true)
@@ -596,6 +486,9 @@ func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
nrecvs++
}
+ // TODO(mdempsky): Move this function to types.
+ // TODO(mdempsky): Preserve positions, names, and package from sig+recv.
+
params := make([]*types.Field, nrecvs+sig.Params().Fields().Len())
if recv != nil {
params[0] = types.NewField(base.Pos, nil, recv)
diff --git a/src/cmd/compile/internal/typecheck/export.go b/src/cmd/compile/internal/typecheck/export.go
index 381a28e3ed..63d0a1ec6c 100644
--- a/src/cmd/compile/internal/typecheck/export.go
+++ b/src/cmd/compile/internal/typecheck/export.go
@@ -31,12 +31,8 @@ func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val
// ipkg is the package being imported
func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t)
-
- fn := ir.NewFunc(pos)
- fn.SetType(t)
- n.SetFunc(fn)
- fn.Nname = n
-
+ n.Func = ir.NewFunc(pos)
+ n.Func.Nname = n
return n
}
@@ -57,9 +53,8 @@ func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Cl
}
n := ir.NewDeclNameAt(pos, op, s)
- n.Class_ = ctxt // TODO(mdempsky): Move this into NewDeclNameAt too?
+ n.Class = ctxt // TODO(mdempsky): Move this into NewDeclNameAt too?
s.SetPkgDef(n)
- s.Importdef = ipkg
return n
}
diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go
index 3e7a880c2a..12bfae67a8 100644
--- a/src/cmd/compile/internal/typecheck/expr.go
+++ b/src/cmd/compile/internal/typecheck/expr.go
@@ -35,14 +35,6 @@ func tcAddr(n *ir.AddrExpr) ir.Node {
if ir.Orig(r) != r {
base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
}
- r.Name().SetAddrtaken(true)
- if r.Name().IsClosureVar() && !CaptureVarsComplete {
- // Mark the original variable as Addrtaken so that capturevars
- // knows not to pass it by value.
- // But if the capturevars phase is complete, don't touch it,
- // in case l.Name's containing function has not yet been compiled.
- r.Name().Defn.Name().SetAddrtaken(true)
- }
}
n.X = DefaultLit(n.X, nil)
if n.X.Type() == nil {
@@ -55,103 +47,50 @@ func tcAddr(n *ir.AddrExpr) ir.Node {
return n
}
-// tcArith typechecks a binary arithmetic expression.
-func tcArith(n ir.Node) ir.Node {
- var l, r ir.Node
- var setLR func()
- switch n := n.(type) {
- case *ir.AssignOpStmt:
- l, r = n.X, n.Y
- setLR = func() { n.X = l; n.Y = r }
- case *ir.BinaryExpr:
- l, r = n.X, n.Y
- setLR = func() { n.X = l; n.Y = r }
- case *ir.LogicalExpr:
- l, r = n.X, n.Y
- setLR = func() { n.X = l; n.Y = r }
- }
- l = Expr(l)
- r = Expr(r)
- setLR()
- if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
+func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) {
+ if l.Type() == nil || l.Type() == nil {
+ return l, r, nil
}
- op := n.Op()
- if n.Op() == ir.OASOP {
- n := n.(*ir.AssignOpStmt)
- checkassign(n, l)
- if n.IncDec && !okforarith[l.Type().Kind()] {
- base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type())
- n.SetType(nil)
- return n
- }
- // TODO(marvin): Fix Node.EType type union.
- op = n.AsOp
- }
- if op == ir.OLSH || op == ir.ORSH {
- r = DefaultLit(r, types.Types[types.TUINT])
- setLR()
- t := r.Type()
- if !t.IsInteger() {
- base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
- n.SetType(nil)
- return n
- }
- if t.IsSigned() && !types.AllowsGoVersion(curpkg(), 1, 13) {
- base.ErrorfVers("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type())
- n.SetType(nil)
- return n
- }
- t = l.Type()
- if t != nil && t.Kind() != types.TIDEAL && !t.IsInteger() {
- base.Errorf("invalid operation: %v (shift of type %v)", n, t)
- n.SetType(nil)
- return n
- }
- // no defaultlit for left
- // the outer context gives the type
- n.SetType(l.Type())
- if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL {
- n.SetType(types.UntypedInt)
- }
- return n
+ r = DefaultLit(r, types.Types[types.TUINT])
+ t := r.Type()
+ if !t.IsInteger() {
+ base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
+ return l, r, nil
+ }
+ if t.IsSigned() && !types.AllowsGoVersion(curpkg(), 1, 13) {
+ base.ErrorfVers("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type())
+ return l, r, nil
+ }
+ t = l.Type()
+ if t != nil && t.Kind() != types.TIDEAL && !t.IsInteger() {
+ base.Errorf("invalid operation: %v (shift of type %v)", n, t)
+ return l, r, nil
}
- // For "x == x && len(s)", it's better to report that "len(s)" (type int)
- // can't be used with "&&" than to report that "x == x" (type untyped bool)
- // can't be converted to int (see issue #41500).
- if n.Op() == ir.OANDAND || n.Op() == ir.OOROR {
- n := n.(*ir.LogicalExpr)
- if !n.X.Type().IsBoolean() {
- base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.X.Type()))
- n.SetType(nil)
- return n
- }
- if !n.Y.Type().IsBoolean() {
- base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Y.Type()))
- n.SetType(nil)
- return n
- }
+ // no defaultlit for left
+ // the outer context gives the type
+ t = l.Type()
+ if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL {
+ t = types.UntypedInt
}
+ return l, r, t
+}
- // ideal mixed with non-ideal
+// tcArith typechecks operands of a binary arithmetic expression.
+// The result of tcArith MUST be assigned back to original operands,
+// t is the type of the expression, and should be set by the caller. e.g:
+// n.X, n.Y, t = tcArith(n, op, n.X, n.Y)
+// n.SetType(t)
+func tcArith(n ir.Node, op ir.Op, l, r ir.Node) (ir.Node, ir.Node, *types.Type) {
l, r = defaultlit2(l, r, false)
- setLR()
-
if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
+ return l, r, nil
}
t := l.Type()
if t.Kind() == types.TIDEAL {
t = r.Type()
}
- et := t.Kind()
- if et == types.TIDEAL {
- et = types.TINT
- }
aop := ir.OXXX
if iscmp[n.Op()] && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
// comparison is okay as long as one side is
@@ -167,15 +106,13 @@ func tcArith(n ir.Node) ir.Node {
if aop != ir.OXXX {
if r.Type().IsInterface() && !l.Type().IsInterface() && !types.IsComparable(l.Type()) {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type()))
- n.SetType(nil)
- return n
+ return l, r, nil
}
types.CalcSize(l.Type())
if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
l.SetTypecheck(1)
- setLR()
}
t = r.Type()
@@ -188,34 +125,28 @@ func tcArith(n ir.Node) ir.Node {
if aop != ir.OXXX {
if l.Type().IsInterface() && !r.Type().IsInterface() && !types.IsComparable(r.Type()) {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type()))
- n.SetType(nil)
- return n
+ return l, r, nil
}
types.CalcSize(r.Type())
if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
r.SetTypecheck(1)
- setLR()
}
t = l.Type()
}
}
-
- et = t.Kind()
}
if t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
l, r = defaultlit2(l, r, true)
if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
+ return l, r, nil
}
if l.Type().IsInterface() == r.Type().IsInterface() || aop == 0 {
base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
- n.SetType(nil)
- return n
+ return l, r, nil
}
}
@@ -224,85 +155,46 @@ func tcArith(n ir.Node) ir.Node {
}
if dt := defaultType(t); !okfor[op][dt.Kind()] {
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
- n.SetType(nil)
- return n
+ return l, r, nil
}
// okfor allows any array == array, map == map, func == func.
// restrict to slice/map/func == nil and nil == slice/map/func.
if l.Type().IsArray() && !types.IsComparable(l.Type()) {
base.Errorf("invalid operation: %v (%v cannot be compared)", n, l.Type())
- n.SetType(nil)
- return n
+ return l, r, nil
}
if l.Type().IsSlice() && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (slice can only be compared to nil)", n)
- n.SetType(nil)
- return n
+ return l, r, nil
}
if l.Type().IsMap() && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (map can only be compared to nil)", n)
- n.SetType(nil)
- return n
+ return l, r, nil
}
if l.Type().Kind() == types.TFUNC && !ir.IsNil(l) && !ir.IsNil(r) {
base.Errorf("invalid operation: %v (func can only be compared to nil)", n)
- n.SetType(nil)
- return n
+ return l, r, nil
}
if l.Type().IsStruct() {
if f := types.IncomparableField(l.Type()); f != nil {
base.Errorf("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
- n.SetType(nil)
- return n
- }
- }
-
- if iscmp[n.Op()] {
- t = types.UntypedBool
- n.SetType(t)
- if con := EvalConst(n); con.Op() == ir.OLITERAL {
- return con
- }
- l, r = defaultlit2(l, r, true)
- setLR()
- return n
- }
-
- if et == types.TSTRING && n.Op() == ir.OADD {
- // create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
- n := n.(*ir.BinaryExpr)
- var add *ir.AddStringExpr
- if l.Op() == ir.OADDSTR {
- add = l.(*ir.AddStringExpr)
- add.SetPos(n.Pos())
- } else {
- add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
- }
- if r.Op() == ir.OADDSTR {
- r := r.(*ir.AddStringExpr)
- add.List.Append(r.List.Take()...)
- } else {
- add.List.Append(r)
+ return l, r, nil
}
- add.SetType(t)
- return add
}
if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
if constant.Sign(r.Val()) == 0 {
base.Errorf("division by zero")
- n.SetType(nil)
- return n
+ return l, r, nil
}
}
- n.SetType(t)
- return n
+ return l, r, t
}
// The result of tcCompLit MUST be assigned back to n, e.g.
@@ -330,7 +222,7 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
// Need to handle [...]T arrays specially.
if array, ok := n.Ntype.(*ir.ArrayType); ok && array.Elem != nil && array.Len == nil {
- array.Elem = typecheck(array.Elem, ctxType)
+ array.Elem = typecheckNtype(array.Elem)
elemType := array.Elem.Type()
if elemType == nil {
n.SetType(nil)
@@ -343,7 +235,7 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
return n
}
- n.Ntype = ir.Node(typecheck(n.Ntype, ctxType)).(ir.Ntype)
+ n.Ntype = typecheckNtype(n.Ntype)
t := n.Ntype.Type()
if t == nil {
n.SetType(nil)
@@ -626,10 +518,8 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
}
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
- // Create top-level function.
- fn := makepartialcall(n)
-
- return ir.NewCallPartExpr(n.Pos(), n.X, n.Selection, fn)
+ n.SetOp(ir.OCALLPART)
+ n.SetType(MethodValueWrapper(n).Type())
}
return n
}
@@ -651,7 +541,7 @@ func tcDotType(n *ir.TypeAssertExpr) ir.Node {
}
if n.Ntype != nil {
- n.Ntype = typecheck(n.Ntype, ctxType)
+ n.Ntype = typecheckNtype(n.Ntype)
n.SetType(n.Ntype.Type())
n.Ntype = nil
if n.Type() == nil {
diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go
index ed4f3ad4fe..8fdb33b145 100644
--- a/src/cmd/compile/internal/typecheck/func.go
+++ b/src/cmd/compile/internal/typecheck/func.go
@@ -21,7 +21,7 @@ func MakeDotArgs(typ *types.Type, args []ir.Node) ir.Node {
n = NodNil()
n.SetType(typ)
} else {
- lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
+ lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
lit.List.Append(args...)
lit.SetImplicit(true)
n = lit
@@ -52,7 +52,7 @@ func FixVariadicCall(call *ir.CallExpr) {
extra[i] = nil // allow GC
}
- call.Args.Set(append(args[:vi], slice))
+ call.Args = append(args[:vi], slice)
call.IsDDD = true
}
@@ -91,7 +91,7 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
// PartialCallType returns the struct type used to hold all the information
// needed in the closure for n (n must be a OCALLPART node).
// The address of a variable of the returned type can be cast to a func.
-func PartialCallType(n *ir.CallPartExpr) *types.Type {
+func PartialCallType(n *ir.SelectorExpr) *types.Type {
t := types.NewStruct(types.NoPkg, []*types.Field{
types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
types.NewField(base.Pos, Lookup("R"), n.X.Type()),
@@ -106,56 +106,24 @@ func PartialCallType(n *ir.CallPartExpr) *types.Type {
// We use value capturing for values <= 128 bytes that are never reassigned
// after capturing (effectively constant).
func CaptureVars(fn *ir.Func) {
- lno := base.Pos
- base.Pos = fn.Pos()
- cvars := fn.ClosureVars
- out := cvars[:0]
- for _, v := range cvars {
- if v.Type() == nil {
- // If v.Type is nil, it means v looked like it
- // was going to be used in the closure, but
- // isn't. This happens in struct literals like
- // s{f: x} where we can't distinguish whether
- // f is a field identifier or expression until
- // resolving s.
- continue
- }
- out = append(out, v)
-
- // type check the & of closed variables outside the closure,
- // so that the outer frame also grabs them and knows they escape.
- types.CalcSize(v.Type())
-
- var outer ir.Node
- outer = v.Outer
+ for _, v := range fn.ClosureVars {
outermost := v.Defn.(*ir.Name)
// out parameters will be assigned to implicitly upon return.
- if outermost.Class_ != ir.PPARAMOUT && !outermost.Name().Addrtaken() && !outermost.Name().Assigned() && v.Type().Width <= 128 {
- v.SetByval(true)
+ if outermost.Class != ir.PPARAMOUT && !outermost.Addrtaken() && !outermost.Assigned() && outermost.Type().Size() <= 128 {
+ outermost.SetByval(true)
} else {
- outermost.Name().SetAddrtaken(true)
- outer = NodAddr(outer)
+ outermost.SetAddrtaken(true)
}
if base.Flag.LowerM > 1 {
- var name *types.Sym
- if v.Curfn != nil && v.Curfn.Nname != nil {
- name = v.Curfn.Sym()
- }
how := "ref"
if v.Byval() {
how = "value"
}
- base.WarnfAt(v.Pos(), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym(), outermost.Name().Addrtaken(), outermost.Name().Assigned(), int32(v.Type().Width))
+ base.WarnfAt(v.Pos(), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", v.Curfn, how, v, outermost.Addrtaken(), outermost.Assigned(), v.Type().Size())
}
-
- outer = Expr(outer)
- fn.ClosureEnter.Append(outer)
}
-
- fn.ClosureVars = out
- base.Pos = lno
}
// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
@@ -163,6 +131,21 @@ func CaptureVars(fn *ir.Func) {
func ImportedBody(fn *ir.Func) {
lno := ir.SetPos(fn.Nname)
+ // When we load an inlined body, we need to allow OADDR
+ // operations on untyped expressions. We will fix the
+ // addrtaken flags on all the arguments of the OADDR with the
+ // computeAddrtaken call below (after we typecheck the body).
+ // TODO: export/import types and addrtaken marks along with inlined bodies,
+ // so this will be unnecessary.
+ IncrementalAddrtaken = false
+ defer func() {
+ if DirtyAddrtaken {
+ ComputeAddrtaken(fn.Inl.Body) // compute addrtaken marks once types are available
+ DirtyAddrtaken = false
+ }
+ IncrementalAddrtaken = true
+ }()
+
ImportBody(fn)
// typecheckinl is only for imported functions;
@@ -247,9 +230,17 @@ func closurename(outerfunc *ir.Func) *types.Sym {
// globClosgen is like Func.Closgen, but for the global scope.
var globClosgen int32
-// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
-// for partial calls.
-func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
+// MethodValueWrapper returns the DCLFUNC node representing the
+// wrapper function (*-fm) needed for the given method value. If the
+// wrapper function hasn't already been created yet, it's created and
+// added to Target.Decls.
+//
+// TODO(mdempsky): Move into walk. This isn't part of type checking.
+func MethodValueWrapper(dot *ir.SelectorExpr) *ir.Func {
+ if dot.Op() != ir.OCALLPART {
+ base.Fatalf("MethodValueWrapper: unexpected %v (%v)", dot, dot.Op())
+ }
+
t0 := dot.Type()
meth := dot.Sel
rcvrtype := dot.X.Type()
@@ -296,7 +287,7 @@ func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
}
call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
- call.Args.Set(ir.ParamNames(tfn.Type()))
+ call.Args = ir.ParamNames(tfn.Type())
call.IsDDD = tfn.Type().IsVariadic()
if t0.NumResults() != 0 {
ret := ir.NewReturnStmt(base.Pos, nil)
@@ -306,7 +297,7 @@ func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
body = append(body, call)
}
- fn.Body.Set(body)
+ fn.Body = body
FinishFuncBody()
Func(fn)
@@ -334,7 +325,7 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
fn.Iota = x
}
- fn.ClosureType = typecheck(fn.ClosureType, ctxType)
+ fn.ClosureType = typecheckNtype(fn.ClosureType)
clo.SetType(fn.ClosureType.Type())
fn.SetClosureCalled(top&ctxCallee != 0)
@@ -379,6 +370,25 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
ir.CurFunc = oldfn
}
+ out := 0
+ for _, v := range fn.ClosureVars {
+ if v.Type() == nil {
+ // If v.Type is nil, it means v looked like it was going to be
+ // used in the closure, but isn't. This happens in struct
+ // literals like s{f: x} where we can't distinguish whether f is
+ // a field identifier or expression until resolving s.
+ continue
+ }
+
+ // type check closed variables outside the closure, so that the
+ // outer frame also captures them.
+ Expr(v.Outer)
+
+ fn.ClosureVars[out] = v
+ out++
+ }
+ fn.ClosureVars = fn.ClosureVars[:out]
+
Target.Decls = append(Target.Decls, fn)
}
@@ -391,7 +401,7 @@ func tcFunc(n *ir.Func) {
}
for _, ln := range n.Dcl {
- if ln.Op() == ir.ONAME && (ln.Class_ == ir.PPARAM || ln.Class_ == ir.PPARAMOUT) {
+ if ln.Op() == ir.ONAME && (ln.Class == ir.PPARAM || ln.Class == ir.PPARAMOUT) {
ln.Decldepth = 1
}
}
@@ -401,7 +411,6 @@ func tcFunc(n *ir.Func) {
if t == nil {
return
}
- n.SetType(t)
rcvr := t.Recv()
if rcvr != nil && n.Shortname != nil {
m := addmethod(n, n.Shortname, t, true, n.Pragma&ir.Nointerface != 0)
@@ -782,7 +791,7 @@ func tcMake(n *ir.CallExpr) ir.Node {
return n
}
- n.Args.Set(nil)
+ n.Args = nil
l := args[0]
l = typecheck(l, ctxType)
t := l.Type()
diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go
index 3b071a61ab..a7927c39a3 100644
--- a/src/cmd/compile/internal/typecheck/iexport.go
+++ b/src/cmd/compile/internal/typecheck/iexport.go
@@ -430,7 +430,7 @@ func (p *iexporter) doDecl(n *ir.Name) {
switch n.Op() {
case ir.ONAME:
- switch n.Class_ {
+ switch n.Class {
case ir.PEXTERN:
// Variable.
w.tag('V')
@@ -450,7 +450,7 @@ func (p *iexporter) doDecl(n *ir.Name) {
w.funcExt(n)
default:
- base.Fatalf("unexpected class: %v, %v", n, n.Class_)
+ base.Fatalf("unexpected class: %v, %v", n, n.Class)
}
case ir.OLITERAL:
@@ -574,6 +574,11 @@ func (w *exportWriter) pos(pos src.XPos) {
}
func (w *exportWriter) pkg(pkg *types.Pkg) {
+ // TODO(mdempsky): Add flag to types.Pkg to mark pseudo-packages.
+ if pkg == ir.Pkgs.Go {
+ base.Fatalf("export of pseudo-package: %q", pkg.Path)
+ }
+
// Ensure any referenced packages are declared in the main index.
w.p.allPkgs[pkg] = true
@@ -936,7 +941,7 @@ func (w *exportWriter) mpfloat(v constant.Value, typ *types.Type) {
if acc != big.Exact {
base.Fatalf("mantissa scaling failed for %f (%s)", f, acc)
}
- w.mpint(makeInt(manti), typ)
+ w.mpint(constant.Make(manti), typ)
if manti.Sign() != 0 {
w.int64(exp)
}
@@ -1067,7 +1072,7 @@ func (w *exportWriter) stmt(n ir.Node) {
n := n.(*ir.Decl)
w.op(ir.ODCL)
w.pos(n.X.Pos())
- w.localName(n.X.(*ir.Name))
+ w.localName(n.X)
w.typ(n.X.Type())
case ir.OAS:
@@ -1187,7 +1192,7 @@ func (w *exportWriter) caseList(cases []*ir.CaseClause, namedTypeSwitch bool) {
w.pos(cas.Pos())
w.stmtList(cas.List)
if namedTypeSwitch {
- w.localName(cas.Var.(*ir.Name))
+ w.localName(cas.Var)
}
w.stmtList(cas.Body)
}
@@ -1252,21 +1257,10 @@ func (w *exportWriter) expr(n ir.Node) {
w.pos(n.Pos())
w.value(n.Type(), n.Val())
- case ir.OMETHEXPR:
- // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
- // but for export, this should be rendered as (*pkg.T).meth.
- // These nodes have the special property that they are names with a left OTYPE and a right ONAME.
- n := n.(*ir.MethodExpr)
- w.op(ir.OXDOT)
- w.pos(n.Pos())
- w.op(ir.OTYPE)
- w.typ(n.T) // n.Left.Op == OTYPE
- w.selector(n.Method.Sym)
-
case ir.ONAME:
// Package scope name.
n := n.(*ir.Name)
- if (n.Class_ == ir.PEXTERN || n.Class_ == ir.PFUNC) && !ir.IsBlank(n) {
+ if (n.Class == ir.PEXTERN || n.Class == ir.PFUNC) && !ir.IsBlank(n) {
w.op(ir.ONONAME)
w.qualifiedIdent(n)
break
@@ -1336,15 +1330,7 @@ func (w *exportWriter) expr(n ir.Node) {
// case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList
- case ir.OCALLPART:
- // An OCALLPART is an OXDOT before type checking.
- n := n.(*ir.CallPartExpr)
- w.op(ir.OXDOT)
- w.pos(n.Pos())
- w.expr(n.X)
- w.selector(n.Method.Sym)
-
- case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH:
+ case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
n := n.(*ir.SelectorExpr)
w.op(ir.OXDOT)
w.pos(n.Pos())
@@ -1540,14 +1526,18 @@ func (w *exportWriter) localName(n *ir.Name) {
// PPARAM/PPARAMOUT, because we only want to include vargen in
// non-param names.
var v int32
- if n.Class_ == ir.PAUTO || (n.Class_ == ir.PAUTOHEAP && n.Name().Stackcopy == nil) {
- v = n.Name().Vargen
+ if n.Class == ir.PAUTO || (n.Class == ir.PAUTOHEAP && n.Stackcopy == nil) {
+ v = n.Vargen
}
w.localIdent(n.Sym(), v)
}
func (w *exportWriter) localIdent(s *types.Sym, v int32) {
+ if w.currPkg == nil {
+ base.Fatalf("missing currPkg")
+ }
+
// Anonymous parameters.
if s == nil {
w.string("")
@@ -1572,8 +1562,8 @@ func (w *exportWriter) localIdent(s *types.Sym, v int32) {
name = fmt.Sprintf("%s·%d", name, v)
}
- if !types.IsExported(name) && s.Pkg != w.currPkg {
- base.Fatalf("weird package in name: %v => %v, not %q", s, name, w.currPkg.Path)
+ if s.Pkg != w.currPkg {
+ base.Fatalf("weird package in name: %v => %v from %q, not %q", s, name, s.Pkg.Path, w.currPkg.Path)
}
w.string(name)
diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go
index 546ddcba79..15c57b2380 100644
--- a/src/cmd/compile/internal/typecheck/iimport.go
+++ b/src/cmd/compile/internal/typecheck/iimport.go
@@ -327,16 +327,17 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
ms := make([]*types.Field, r.uint64())
for i := range ms {
mpos := r.pos()
- msym := r.ident()
+ msym := r.selector()
recv := r.param()
mtyp := r.signature(recv)
- fn := ir.NewFunc(mpos)
- fn.SetType(mtyp)
- m := ir.NewFuncNameAt(mpos, ir.MethodSym(recv.Type, msym), fn)
- m.SetType(mtyp)
- m.Class_ = ir.PFUNC
// methodSym already marked m.Sym as a function.
+ m := ir.NewNameAt(mpos, ir.MethodSym(recv.Type, msym))
+ m.Class = ir.PFUNC
+ m.SetType(mtyp)
+
+ m.Func = ir.NewFunc(mpos)
+ m.Func.Nname = m
f := types.NewField(mpos, msym, mtyp)
f.Nname = m
@@ -372,7 +373,7 @@ func (p *importReader) value(typ *types.Type) constant.Value {
case constant.Int:
var i big.Int
p.mpint(&i, typ)
- return makeInt(&i)
+ return constant.Make(&i)
case constant.Float:
return p.float(typ)
case constant.Complex:
@@ -433,18 +434,21 @@ func (p *importReader) float(typ *types.Type) constant.Value {
return constant.Make(&f)
}
-func (r *importReader) ident() *types.Sym {
+func (r *importReader) ident(selector bool) *types.Sym {
name := r.string()
if name == "" {
return nil
}
pkg := r.currPkg
- if types.IsExported(name) {
+ if selector && types.IsExported(name) {
pkg = types.LocalPkg
}
return pkg.Lookup(name)
}
+func (r *importReader) localIdent() *types.Sym { return r.ident(false) }
+func (r *importReader) selector() *types.Sym { return r.ident(true) }
+
func (r *importReader) qualifiedIdent() *ir.Ident {
name := r.string()
pkg := r.pkg()
@@ -533,7 +537,7 @@ func (r *importReader) typ1() *types.Type {
fs := make([]*types.Field, r.uint64())
for i := range fs {
pos := r.pos()
- sym := r.ident()
+ sym := r.selector()
typ := r.typ()
emb := r.bool()
note := r.string()
@@ -562,7 +566,7 @@ func (r *importReader) typ1() *types.Type {
methods := make([]*types.Field, r.uint64())
for i := range methods {
pos := r.pos()
- sym := r.ident()
+ sym := r.selector()
typ := r.signature(fakeRecvField())
methods[i] = types.NewField(pos, sym, typ)
@@ -598,7 +602,7 @@ func (r *importReader) paramList() []*types.Field {
}
func (r *importReader) param() *types.Field {
- return types.NewField(r.pos(), r.ident(), r.typ())
+ return types.NewField(r.pos(), r.localIdent(), r.typ())
}
func (r *importReader) bool() bool {
@@ -778,17 +782,17 @@ func (r *importReader) caseList(switchExpr ir.Node) []*ir.CaseClause {
cases := make([]*ir.CaseClause, r.uint64())
for i := range cases {
cas := ir.NewCaseStmt(r.pos(), nil, nil)
- cas.List.Set(r.stmtList())
+ cas.List = r.stmtList()
if namedTypeSwitch {
// Note: per-case variables will have distinct, dotted
// names after import. That's okay: swt.go only needs
// Sym for diagnostics anyway.
- caseVar := ir.NewNameAt(cas.Pos(), r.ident())
+ caseVar := ir.NewNameAt(cas.Pos(), r.localIdent())
Declare(caseVar, DeclContext)
cas.Var = caseVar
caseVar.Defn = switchExpr
}
- cas.Body.Set(r.stmtList())
+ cas.Body = r.stmtList()
cases[i] = cas
}
return cases
@@ -850,7 +854,7 @@ func (r *importReader) node() ir.Node {
return r.qualifiedIdent()
case ir.ONAME:
- return r.ident().Def.(*ir.Name)
+ return r.localIdent().Def.(*ir.Name)
// case OPACK, ONONAME:
// unreachable - should have been resolved by typechecking
@@ -861,7 +865,7 @@ func (r *importReader) node() ir.Node {
case ir.OTYPESW:
pos := r.pos()
var tag *ir.Ident
- if s := r.ident(); s != nil {
+ if s := r.localIdent(); s != nil {
tag = ir.NewIdent(pos, s)
}
return ir.NewTypeSwitchGuard(pos, tag, r.expr())
@@ -898,7 +902,7 @@ func (r *importReader) node() ir.Node {
case ir.OXDOT:
// see parser.new_dotname
- return ir.NewSelectorExpr(r.pos(), ir.OXDOT, r.expr(), r.ident())
+ return ir.NewSelectorExpr(r.pos(), ir.OXDOT, r.expr(), r.selector())
// case ODOTTYPE, ODOTTYPE2:
// unreachable - mapped to case ODOTTYPE below by exporter
@@ -931,7 +935,7 @@ func (r *importReader) node() ir.Node {
case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
n := builtinCall(r.pos(), op)
- n.Args.Set(r.exprList())
+ n.Args = r.exprList()
if op == ir.OAPPEND {
n.IsDDD = r.bool()
}
@@ -944,7 +948,7 @@ func (r *importReader) node() ir.Node {
pos := r.pos()
init := r.stmtList()
n := ir.NewCallExpr(pos, ir.OCALL, r.expr(), r.exprList())
- n.PtrInit().Set(init)
+ *n.PtrInit() = init
n.IsDDD = r.bool()
return n
@@ -988,7 +992,7 @@ func (r *importReader) node() ir.Node {
// statements
case ir.ODCL:
pos := r.pos()
- lhs := ir.NewDeclNameAt(pos, ir.ONAME, r.ident())
+ lhs := ir.NewDeclNameAt(pos, ir.ONAME, r.localIdent())
lhs.SetType(r.typ())
Declare(lhs, ir.PAUTO)
@@ -1032,14 +1036,14 @@ func (r *importReader) node() ir.Node {
case ir.OIF:
pos, init := r.pos(), r.stmtList()
n := ir.NewIfStmt(pos, r.expr(), r.stmtList(), r.stmtList())
- n.PtrInit().Set(init)
+ *n.PtrInit() = init
return n
case ir.OFOR:
pos, init := r.pos(), r.stmtList()
cond, post := r.exprsOrNil()
n := ir.NewForStmt(pos, nil, cond, post, r.stmtList())
- n.PtrInit().Set(init)
+ *n.PtrInit() = init
return n
case ir.ORANGE:
@@ -1051,7 +1055,7 @@ func (r *importReader) node() ir.Node {
pos := r.pos()
init := r.stmtList()
n := ir.NewSelectStmt(pos, r.commList())
- n.PtrInit().Set(init)
+ *n.PtrInit() = init
return n
case ir.OSWITCH:
@@ -1059,7 +1063,7 @@ func (r *importReader) node() ir.Node {
init := r.stmtList()
x, _ := r.exprsOrNil()
n := ir.NewSwitchStmt(pos, x, r.caseList(x))
- n.PtrInit().Set(init)
+ *n.PtrInit() = init
return n
// case OCASE:
@@ -1099,7 +1103,7 @@ func (r *importReader) op() ir.Op {
func (r *importReader) fieldList() []ir.Node {
list := make([]ir.Node, r.uint64())
for i := range list {
- list[i] = ir.NewStructKeyExpr(r.pos(), r.ident(), r.expr())
+ list[i] = ir.NewStructKeyExpr(r.pos(), r.selector(), r.expr())
}
return list
}
diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go
index f5d36a663d..d90d13b44c 100644
--- a/src/cmd/compile/internal/typecheck/stmt.go
+++ b/src/cmd/compile/internal/typecheck/stmt.go
@@ -631,7 +631,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
nvar := ncase.Var
nvar.SetType(vt)
if vt != nil {
- nvar = AssignExpr(nvar)
+ nvar = AssignExpr(nvar).(*ir.Name)
} else {
// Clause variable is broken; prevent typechecking.
nvar.SetTypecheck(1)
diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go
index 178eba4484..569075d684 100644
--- a/src/cmd/compile/internal/typecheck/subr.go
+++ b/src/cmd/compile/internal/typecheck/subr.go
@@ -43,6 +43,9 @@ func NewFuncParams(tl *types.Type, mustname bool) []*ir.Field {
// invent a name so that we can refer to it in the trampoline
s = LookupNum(".anon", gen)
gen++
+ } else if s != nil && s.Pkg != types.LocalPkg {
+ // TODO(mdempsky): Preserve original position, name, and package.
+ s = Lookup(s.Name)
}
a := ir.NewField(base.Pos, s, nil, t.Type)
a.Pos = t.Pos
@@ -67,9 +70,57 @@ func NodAddr(n ir.Node) *ir.AddrExpr {
// nodAddrPos returns a node representing &n at position pos.
func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
+ n = markAddrOf(n)
return ir.NewAddrExpr(pos, n)
}
+func markAddrOf(n ir.Node) ir.Node {
+ if IncrementalAddrtaken {
+ // We can only do incremental addrtaken computation when it is ok
+ // to typecheck the argument of the OADDR. That's only safe after the
+ // main typecheck has completed.
+ // The argument to OADDR needs to be typechecked because &x[i] takes
+ // the address of x if x is an array, but not if x is a slice.
+ // Note: outervalue doesn't work correctly until n is typechecked.
+ n = typecheck(n, ctxExpr)
+ if x := ir.OuterValue(n); x.Op() == ir.ONAME {
+ x.Name().SetAddrtaken(true)
+ }
+ } else {
+ // Remember that we built an OADDR without computing the Addrtaken bit for
+ // its argument. We'll do that later in bulk using computeAddrtaken.
+ DirtyAddrtaken = true
+ }
+ return n
+}
+
+// If IncrementalAddrtaken is false, we do not compute Addrtaken for an OADDR Node
+// when it is built. The Addrtaken bits are set in bulk by computeAddrtaken.
+// If IncrementalAddrtaken is true, then when an OADDR Node is built the Addrtaken
+// field of its argument is updated immediately.
+var IncrementalAddrtaken = false
+
+// If DirtyAddrtaken is true, then there are OADDR whose corresponding arguments
+// have not yet been marked as Addrtaken.
+var DirtyAddrtaken = false
+
+func ComputeAddrtaken(top []ir.Node) {
+ for _, n := range top {
+ ir.Visit(n, func(n ir.Node) {
+ if n.Op() == ir.OADDR {
+ if x := ir.OuterValue(n.(*ir.AddrExpr).X); x.Op() == ir.ONAME {
+ x.Name().SetAddrtaken(true)
+ if x.Name().IsClosureVar() {
+ // Mark the original variable as Addrtaken so that capturevars
+ // knows not to pass it by value.
+ x.Name().Defn.Name().SetAddrtaken(true)
+ }
+ }
+ }
+ })
+ }
+}
+
func NodNil() ir.Node {
n := ir.NewNilExpr(base.Pos)
n.SetType(types.Types[types.TNIL])
diff --git a/src/cmd/compile/internal/typecheck/syms.go b/src/cmd/compile/internal/typecheck/syms.go
index ab3384bf90..28db40db91 100644
--- a/src/cmd/compile/internal/typecheck/syms.go
+++ b/src/cmd/compile/internal/typecheck/syms.go
@@ -26,12 +26,12 @@ func LookupRuntime(name string) *ir.Name {
// The result of SubstArgTypes MUST be assigned back to old, e.g.
// n.Left = SubstArgTypes(n.Left, t1, t2)
func SubstArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
- n := old.CloneName()
-
for _, t := range types_ {
types.CalcSize(t)
}
- n.SetType(types.SubstAny(n.Type(), &types_))
+ n := ir.NewNameAt(old.Pos(), old.Sym())
+ n.Class = old.Class
+ n.SetType(types.SubstAny(old.Type(), &types_))
if len(types_) > 0 {
base.Fatalf("substArgTypes: too many argument types")
}
@@ -61,15 +61,13 @@ func Lookup(name string) *types.Sym {
return types.LocalPkg.Lookup(name)
}
-// loadsys loads the definitions for the low-level runtime functions,
+// InitRuntime loads the definitions for the low-level runtime functions,
// so that the compiler can generate calls to them,
// but does not make them visible to user code.
-func loadsys() {
+func InitRuntime() {
+ base.Timer.Start("fe", "loadsys")
types.Block = 1
- inimport = true
- TypecheckAllowed = true
-
typs := runtimeTypes()
for _, d := range &runtimeDecls {
sym := ir.Pkgs.Runtime.Lookup(d.name)
@@ -83,9 +81,6 @@ func loadsys() {
base.Fatalf("unhandled declaration tag %v", d.tag)
}
}
-
- TypecheckAllowed = false
- inimport = false
}
// LookupRuntimeFunc looks up Go function name in package runtime. This function
diff --git a/src/cmd/compile/internal/typecheck/type.go b/src/cmd/compile/internal/typecheck/type.go
index 0c2ebb8b26..6fdafef77d 100644
--- a/src/cmd/compile/internal/typecheck/type.go
+++ b/src/cmd/compile/internal/typecheck/type.go
@@ -14,7 +14,7 @@ import (
// tcArrayType typechecks an OTARRAY node.
func tcArrayType(n *ir.ArrayType) ir.Node {
- n.Elem = typecheck(n.Elem, ctxType)
+ n.Elem = typecheckNtype(n.Elem)
if n.Elem.Type() == nil {
return n
}
@@ -59,7 +59,7 @@ func tcArrayType(n *ir.ArrayType) ir.Node {
// tcChanType typechecks an OTCHAN node.
func tcChanType(n *ir.ChanType) ir.Node {
- n.Elem = typecheck(n.Elem, ctxType)
+ n.Elem = typecheckNtype(n.Elem)
l := n.Elem
if l.Type() == nil {
return n
@@ -103,7 +103,7 @@ func tcInterfaceType(n *ir.InterfaceType) ir.Node {
n.SetOTYPE(types.Types[types.TINTER])
return n
}
-
+
lno := base.Pos
methods := tcFields(n.Methods, nil)
base.Pos = lno
@@ -114,8 +114,8 @@ func tcInterfaceType(n *ir.InterfaceType) ir.Node {
// tcMapType typechecks an OTMAP node.
func tcMapType(n *ir.MapType) ir.Node {
- n.Key = typecheck(n.Key, ctxType)
- n.Elem = typecheck(n.Elem, ctxType)
+ n.Key = typecheckNtype(n.Key)
+ n.Elem = typecheckNtype(n.Elem)
l := n.Key
r := n.Elem
if l.Type() == nil || r.Type() == nil {
@@ -134,7 +134,7 @@ func tcMapType(n *ir.MapType) ir.Node {
// tcSliceType typechecks an OTSLICE node.
func tcSliceType(n *ir.SliceType) ir.Node {
- n.Elem = typecheck(n.Elem, ctxType)
+ n.Elem = typecheckNtype(n.Elem)
if n.Elem.Type() == nil {
return n
}
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index e23c249ff2..c3a5a3c40f 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -31,97 +31,6 @@ var (
NeedRuntimeType = func(*types.Type) {}
)
-func Init() {
- initUniverse()
- DeclContext = ir.PEXTERN
- base.Timer.Start("fe", "loadsys")
- loadsys()
-}
-
-func Package() {
- declareUniverse()
-
- TypecheckAllowed = true
-
- // Process top-level declarations in phases.
-
- // Phase 1: const, type, and names and types of funcs.
- // This will gather all the information about types
- // and methods but doesn't depend on any of it.
- //
- // We also defer type alias declarations until phase 2
- // to avoid cycles like #18640.
- // TODO(gri) Remove this again once we have a fix for #25838.
-
- // Don't use range--typecheck can add closures to Target.Decls.
- base.Timer.Start("fe", "typecheck", "top1")
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).X.Name().Alias()) {
- Target.Decls[i] = Stmt(n)
- }
- }
-
- // Phase 2: Variable assignments.
- // To check interface assignments, depends on phase 1.
-
- // Don't use range--typecheck can add closures to Target.Decls.
- base.Timer.Start("fe", "typecheck", "top2")
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).X.Name().Alias() {
- Target.Decls[i] = Stmt(n)
- }
- }
-
- // Phase 3: Type check function bodies.
- // Don't use range--typecheck can add closures to Target.Decls.
- base.Timer.Start("fe", "typecheck", "func")
- var fcount int64
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
- if n.Op() == ir.ODCLFUNC {
- FuncBody(n.(*ir.Func))
- fcount++
- }
- }
-
- // Phase 4: Check external declarations.
- // TODO(mdempsky): This should be handled when type checking their
- // corresponding ODCL nodes.
- base.Timer.Start("fe", "typecheck", "externdcls")
- for i, n := range Target.Externs {
- if n.Op() == ir.ONAME {
- Target.Externs[i] = Expr(Target.Externs[i])
- }
- }
-
- // Phase 5: With all user code type-checked, it's now safe to verify map keys.
- CheckMapKeys()
-
- // Phase 6: Decide how to capture closed variables.
- // This needs to run before escape analysis,
- // because variables captured by value do not escape.
- base.Timer.Start("fe", "capturevars")
- for _, n := range Target.Decls {
- if n.Op() == ir.ODCLFUNC {
- n := n.(*ir.Func)
- if n.OClosure != nil {
- ir.CurFunc = n
- CaptureVars(n)
- }
- }
- }
- CaptureVarsComplete = true
- ir.CurFunc = nil
-
- if base.Debug.TypecheckInl != 0 {
- // Typecheck imported function bodies if Debug.l > 1,
- // otherwise lazily when used or re-exported.
- AllImportedBodies()
- }
-}
-
func AssignExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxAssign) }
func Expr(n ir.Node) ir.Node { return typecheck(n, ctxExpr) }
func Stmt(n ir.Node) ir.Node { return typecheck(n, ctxStmt) }
@@ -152,13 +61,11 @@ func FuncBody(n *ir.Func) {
decldepth = 1
errorsBefore := base.Errors()
Stmts(n.Body)
+ CheckUnused(n)
CheckReturn(n)
if base.Errors() > errorsBefore {
- n.Body.Set(nil) // type errors; do not compile
+ n.Body = nil // type errors; do not compile
}
- // Now that we've checked whether n terminates,
- // we can eliminate some obviously dead code.
- deadcode(n)
}
var importlist []*ir.Func
@@ -230,7 +137,7 @@ const (
// marks variables that escape the local frame.
// rewrites n.Op to be more specific in some cases.
-var typecheckdefstack []ir.Node
+var typecheckdefstack []*ir.Name
// Resolve ONONAME to definition, if any.
func Resolve(n ir.Node) (res ir.Node) {
@@ -567,26 +474,8 @@ func indexlit(n ir.Node) ir.Node {
// typecheck1 should ONLY be called from typecheck.
func typecheck1(n ir.Node, top int) ir.Node {
- switch n.Op() {
- case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE:
- if n.Sym() == nil {
- return n
- }
-
- if n.Op() == ir.ONAME {
- n := n.(*ir.Name)
- if n.BuiltinOp != 0 && top&ctxCallee == 0 {
- base.Errorf("use of builtin %v not in function call", n.Sym())
- n.SetType(nil)
- return n
- }
- }
-
+ if n, ok := n.(*ir.Name); ok {
typecheckdef(n)
- if n.Op() == ir.ONONAME {
- n.SetType(nil)
- return n
- }
}
switch n.Op() {
@@ -595,22 +484,37 @@ func typecheck1(n ir.Node, top int) ir.Node {
base.Fatalf("typecheck %v", n.Op())
panic("unreachable")
- // names
case ir.OLITERAL:
- if n.Type() == nil && n.Val().Kind() == constant.String {
- base.Fatalf("string literal missing type")
+ if n.Sym() == nil && n.Type() == nil {
+ base.Fatalf("literal missing type: %v", n)
}
return n
- case ir.ONIL, ir.ONONAME:
+ case ir.ONIL:
+ return n
+
+ // names
+ case ir.ONONAME:
+ if !n.Diag() {
+ // Note: adderrorname looks for this string and
+ // adds context about the outer expression
+ base.ErrorfAt(n.Pos(), "undefined: %v", n.Sym())
+ n.SetDiag(true)
+ }
+ n.SetType(nil)
return n
case ir.ONAME:
n := n.(*ir.Name)
- if n.Name().Decldepth == 0 {
- n.Name().Decldepth = decldepth
+ if n.Decldepth == 0 {
+ n.Decldepth = decldepth
}
if n.BuiltinOp != 0 {
+ if top&ctxCallee == 0 {
+ base.Errorf("use of builtin %v not in function call", n.Sym())
+ n.SetType(nil)
+ return n
+ }
return n
}
if top&ctxAssign == 0 {
@@ -620,7 +524,7 @@ func typecheck1(n ir.Node, top int) ir.Node {
n.SetType(nil)
return n
}
- n.Name().SetUsed(true)
+ n.SetUsed(true)
}
return n
@@ -636,9 +540,6 @@ func typecheck1(n ir.Node, top int) ir.Node {
// types (ODEREF is with exprs)
case ir.OTYPE:
- if n.Type() == nil {
- return n
- }
return n
case ir.OTSLICE:
@@ -672,28 +573,98 @@ func typecheck1(n ir.Node, top int) ir.Node {
case ir.ODEREF:
n := n.(*ir.StarExpr)
return tcStar(n, top)
- // arithmetic exprs
- case ir.OASOP,
- ir.OADD,
- ir.OAND,
- ir.OANDAND,
- ir.OANDNOT,
- ir.ODIV,
- ir.OEQ,
- ir.OGE,
- ir.OGT,
- ir.OLE,
- ir.OLT,
- ir.OLSH,
- ir.ORSH,
- ir.OMOD,
- ir.OMUL,
- ir.ONE,
- ir.OOR,
- ir.OOROR,
- ir.OSUB,
- ir.OXOR:
- return tcArith(n)
+
+ // x op= y
+ case ir.OASOP:
+ n := n.(*ir.AssignOpStmt)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ checkassign(n, n.X)
+ if n.IncDec && !okforarith[n.X.Type().Kind()] {
+ base.Errorf("invalid operation: %v (non-numeric type %v)", n, n.X.Type())
+ return n
+ }
+ switch n.AsOp {
+ case ir.OLSH, ir.ORSH:
+ n.X, n.Y, _ = tcShift(n, n.X, n.Y)
+ case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD, ir.OMUL, ir.OOR, ir.OSUB, ir.OXOR:
+ n.X, n.Y, _ = tcArith(n, n.AsOp, n.X, n.Y)
+ default:
+ base.Fatalf("invalid assign op: %v", n.AsOp)
+ }
+ return n
+
+ // logical operators
+ case ir.OANDAND, ir.OOROR:
+ n := n.(*ir.LogicalExpr)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ // For "x == x && len(s)", it's better to report that "len(s)" (type int)
+ // can't be used with "&&" than to report that "x == x" (type untyped bool)
+ // can't be converted to int (see issue #41500).
+ if !n.X.Type().IsBoolean() {
+ base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.X.Type()))
+ n.SetType(nil)
+ return n
+ }
+ if !n.Y.Type().IsBoolean() {
+ base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Y.Type()))
+ n.SetType(nil)
+ return n
+ }
+ l, r, t := tcArith(n, n.Op(), n.X, n.Y)
+ n.X, n.Y = l, r
+ n.SetType(t)
+ return n
+
+ // shift operators
+ case ir.OLSH, ir.ORSH:
+ n := n.(*ir.BinaryExpr)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ l, r, t := tcShift(n, n.X, n.Y)
+ n.X, n.Y = l, r
+ n.SetType(t)
+ return n
+
+ // comparison operators
+ case ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, ir.ONE:
+ n := n.(*ir.BinaryExpr)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ l, r, t := tcArith(n, n.Op(), n.X, n.Y)
+ if t != nil {
+ n.X, n.Y = l, r
+ n.SetType(types.UntypedBool)
+ if con := EvalConst(n); con.Op() == ir.OLITERAL {
+ return con
+ }
+ n.X, n.Y = defaultlit2(l, r, true)
+ }
+ return n
+
+ // binary operators
+ case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD, ir.OMUL, ir.OOR, ir.OSUB, ir.OXOR:
+ n := n.(*ir.BinaryExpr)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ l, r, t := tcArith(n, n.Op(), n.X, n.Y)
+ if t != nil && t.Kind() == types.TSTRING && n.Op() == ir.OADD {
+ // create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
+ var add *ir.AddStringExpr
+ if l.Op() == ir.OADDSTR {
+ add = l.(*ir.AddStringExpr)
+ add.SetPos(n.Pos())
+ } else {
+ add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
+ }
+ if r.Op() == ir.OADDSTR {
+ r := r.(*ir.AddStringExpr)
+ add.List.Append(r.List.Take()...)
+ } else {
+ add.List.Append(r)
+ }
+ add.SetType(t)
+ return add
+ }
+ n.X, n.Y = l, r
+ n.SetType(t)
+ return n
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
n := n.(*ir.UnaryExpr)
@@ -925,12 +896,12 @@ func typecheck1(n ir.Node, top int) ir.Node {
case ir.ODCLCONST:
n := n.(*ir.Decl)
- n.X = Expr(n.X)
+ n.X = Expr(n.X).(*ir.Name)
return n
case ir.ODCLTYPE:
n := n.(*ir.Decl)
- n.X = typecheck(n.X, ctxType)
+ n.X = typecheck(n.X, ctxType).(*ir.Name)
types.CheckSize(n.X.Type())
return n
}
@@ -940,7 +911,7 @@ func typecheck1(n ir.Node, top int) ir.Node {
// Each must execute its own return n.
}
-func typecheckargs(n ir.Node) {
+func typecheckargs(n ir.InitNode) {
var list []ir.Node
switch n := n.(type) {
default:
@@ -997,9 +968,9 @@ func typecheckargs(n ir.Node) {
switch n := n.(type) {
case *ir.CallExpr:
- n.Args.Set(list)
+ n.Args = list
case *ir.ReturnStmt:
- n.Results.Set(list)
+ n.Results = list
}
n.PtrInit().Append(Stmt(as))
@@ -1176,19 +1147,16 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
return n
}
- me := ir.NewMethodExpr(n.Pos(), n.X.Type(), m)
- me.SetType(NewMethodType(m.Type, n.X.Type()))
- f := NewName(ir.MethodSym(t, m.Sym))
- f.Class_ = ir.PFUNC
- f.SetType(me.Type())
- me.FuncName_ = f
+ n.SetOp(ir.OMETHEXPR)
+ n.Selection = m
+ n.SetType(NewMethodType(m.Type, n.X.Type()))
// Issue 25065. Make sure that we emit the symbol for a local method.
if base.Ctxt.Flag_dynlink && !inimport && (t.Sym() == nil || t.Sym().Pkg == types.LocalPkg) {
- NeedFuncSym(me.FuncName_.Sym())
+ NeedFuncSym(n.FuncName().Sym())
}
- return me
+ return n
}
func derefall(t *types.Type) *types.Type {
@@ -1245,6 +1213,7 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
// Already in the process of diagnosing an error.
return f2
}
+ orig := n.X
tt := n.X.Type()
types.CalcSize(tt)
rcvr := f2.Type.Recv().Type
@@ -1275,20 +1244,28 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
}
}
- implicit, ll := n.Implicit(), n.X
- for ll != nil && (ll.Op() == ir.ODOT || ll.Op() == ir.ODOTPTR || ll.Op() == ir.ODEREF) {
- switch l := ll.(type) {
+ // Check that we haven't implicitly dereferenced any defined pointer types.
+ for x := n.X; ; {
+ var inner ir.Node
+ implicit := false
+ switch x := x.(type) {
+ case *ir.AddrExpr:
+ inner, implicit = x.X, x.Implicit()
case *ir.SelectorExpr:
- implicit, ll = l.Implicit(), l.X
+ inner, implicit = x.X, x.Implicit()
case *ir.StarExpr:
- implicit, ll = l.Implicit(), l.X
+ inner, implicit = x.X, x.Implicit()
}
- }
- if implicit && ll.Type().IsPtr() && ll.Type().Sym() != nil && ll.Type().Sym().Def != nil && ir.AsNode(ll.Type().Sym().Def).Op() == ir.OTYPE {
- // It is invalid to automatically dereference a named pointer type when selecting a method.
- // Make n.Left == ll to clarify error message.
- n.X = ll
- return nil
+ if !implicit {
+ break
+ }
+ if inner.Type().Sym() != nil && (x.Op() == ir.ODEREF || x.Op() == ir.ODOTPTR) {
+ // Found an implicit dereference of a defined pointer type.
+ // Restore n.X for better error message.
+ n.X = orig
+ return nil
+ }
+ x = inner
}
n.Selection = f2
@@ -1422,7 +1399,7 @@ notenough:
// Method expressions have the form T.M, and the compiler has
// rewritten those to ONAME nodes but left T in Left.
if call.Op() == ir.OMETHEXPR {
- call := call.(*ir.MethodExpr)
+ call := call.(*ir.SelectorExpr)
base.Errorf("not enough arguments in call to method expression %v%s", call, details)
} else {
base.Errorf("not enough arguments in call to %v%s", call, details)
@@ -1635,14 +1612,22 @@ func checklvalue(n ir.Node, verb string) {
}
func checkassign(stmt ir.Node, n ir.Node) {
+ // have already complained about n being invalid
+ if n.Type() == nil {
+ if base.Errors() == 0 {
+ base.Fatalf("expected an error about %v", n)
+ }
+ return
+ }
+
// Variables declared in ORANGE are assigned on every iteration.
if !ir.DeclaredBy(n, stmt) || stmt.Op() == ir.ORANGE {
r := ir.OuterValue(n)
if r.Op() == ir.ONAME {
r := r.(*ir.Name)
- r.Name().SetAssigned(true)
- if r.Name().IsClosureVar() {
- r.Name().Defn.Name().SetAssigned(true)
+ r.SetAssigned(true)
+ if r.IsClosureVar() {
+ r.Defn.Name().SetAssigned(true)
}
}
}
@@ -1656,11 +1641,6 @@ func checkassign(stmt ir.Node, n ir.Node) {
return
}
- // have already complained about n being invalid
- if n.Type() == nil {
- return
- }
-
switch {
case n.Op() == ir.ODOT && n.(*ir.SelectorExpr).X.Op() == ir.OINDEXMAP:
base.Errorf("cannot assign to struct field %v in map", n)
@@ -1706,8 +1686,8 @@ func stringtoruneslit(n *ir.ConvExpr) ir.Node {
i++
}
- nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(n.Type()).(ir.Ntype), nil)
- nn.List.Set(l)
+ nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(n.Type()), nil)
+ nn.List = l
return Expr(nn)
}
@@ -1755,30 +1735,26 @@ func typecheckdeftype(n *ir.Name) {
types.ResumeCheckSize()
}
-func typecheckdef(n ir.Node) {
+func typecheckdef(n *ir.Name) {
if base.EnableTrace && base.Flag.LowerT {
defer tracePrint("typecheckdef", n)(nil)
}
- lno := ir.SetPos(n)
-
- if n.Op() == ir.ONONAME {
- if !n.Diag() {
- n.SetDiag(true)
-
- // Note: adderrorname looks for this string and
- // adds context about the outer expression
- base.ErrorfAt(base.Pos, "undefined: %v", n.Sym())
- }
- base.Pos = lno
+ if n.Walkdef() == 1 {
return
}
- if n.Walkdef() == 1 {
- base.Pos = lno
+ if n.Type() != nil { // builtin
+ // Mark as Walkdef so that if n.SetType(nil) is called later, we
+ // won't try walking again.
+ if got := n.Walkdef(); got != 0 {
+ base.Fatalf("unexpected walkdef: %v", got)
+ }
+ n.SetWalkdef(1)
return
}
+ lno := ir.SetPos(n)
typecheckdefstack = append(typecheckdefstack, n)
if n.Walkdef() == 2 {
base.FlushErrors()
@@ -1793,27 +1769,23 @@ func typecheckdef(n ir.Node) {
n.SetWalkdef(2)
- if n.Type() != nil || n.Sym() == nil { // builtin or no name
- goto ret
- }
-
switch n.Op() {
default:
base.Fatalf("typecheckdef %v", n.Op())
case ir.OLITERAL:
- if n.Name().Ntype != nil {
- n.Name().Ntype = typecheckNtype(n.Name().Ntype)
- n.SetType(n.Name().Ntype.Type())
- n.Name().Ntype = nil
+ if n.Ntype != nil {
+ n.Ntype = typecheckNtype(n.Ntype)
+ n.SetType(n.Ntype.Type())
+ n.Ntype = nil
if n.Type() == nil {
n.SetDiag(true)
goto ret
}
}
- e := n.Name().Defn
- n.Name().Defn = nil
+ e := n.Defn
+ n.Defn = nil
if e == nil {
ir.Dump("typecheckdef nil defn", n)
base.ErrorfAt(n.Pos(), "xxx")
@@ -1856,10 +1828,9 @@ func typecheckdef(n ir.Node) {
}
case ir.ONAME:
- n := n.(*ir.Name)
- if n.Name().Ntype != nil {
- n.Name().Ntype = typecheckNtype(n.Name().Ntype)
- n.SetType(n.Name().Ntype.Type())
+ if n.Ntype != nil {
+ n.Ntype = typecheckNtype(n.Ntype)
+ n.SetType(n.Ntype.Type())
if n.Type() == nil {
n.SetDiag(true)
goto ret
@@ -1869,7 +1840,7 @@ func typecheckdef(n ir.Node) {
if n.Type() != nil {
break
}
- if n.Name().Defn == nil {
+ if n.Defn == nil {
if n.BuiltinOp != 0 { // like OPRINTN
break
}
@@ -1884,16 +1855,15 @@ func typecheckdef(n ir.Node) {
base.Fatalf("var without type, init: %v", n.Sym())
}
- if n.Name().Defn.Op() == ir.ONAME {
- n.Name().Defn = Expr(n.Name().Defn)
- n.SetType(n.Name().Defn.Type())
+ if n.Defn.Op() == ir.ONAME {
+ n.Defn = Expr(n.Defn)
+ n.SetType(n.Defn.Type())
break
}
- n.Name().Defn = Stmt(n.Name().Defn) // fills in n.Type
+ n.Defn = Stmt(n.Defn) // fills in n.Type
case ir.OTYPE:
- n := n.(*ir.Name)
if n.Alias() {
// Type alias declaration: Simply use the rhs type - no need
// to create a new type.
@@ -1970,8 +1940,8 @@ func markBreak(fn *ir.Func) {
var labels map[*types.Sym]ir.Node
var implicit ir.Node
- var mark func(ir.Node) error
- mark = func(n ir.Node) error {
+ var mark func(ir.Node) bool
+ mark = func(n ir.Node) bool {
switch n.Op() {
default:
ir.DoChildren(n, mark)
@@ -2011,7 +1981,7 @@ func markBreak(fn *ir.Func) {
}
implicit = old
}
- return nil
+ return false
}
mark(fn)
@@ -2122,152 +2092,47 @@ func isTermNode(n ir.Node) bool {
return false
}
-// CheckReturn makes sure that fn terminates appropriately.
-func CheckReturn(fn *ir.Func) {
- if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
- markBreak(fn)
- if !isTermNodes(fn.Body) {
- base.ErrorfAt(fn.Endlineno, "missing return at end of function")
- }
- }
-}
-
-func deadcode(fn *ir.Func) {
- deadcodeslice(&fn.Body)
-
- if len(fn.Body) == 0 {
+// CheckUnused checks for any declared variables that weren't used.
+func CheckUnused(fn *ir.Func) {
+ // Only report unused variables if we haven't seen any type-checking
+ // errors yet.
+ if base.Errors() != 0 {
return
}
- for _, n := range fn.Body {
- if len(n.Init()) > 0 {
- return
- }
- switch n.Op() {
- case ir.OIF:
- n := n.(*ir.IfStmt)
- if !ir.IsConst(n.Cond, constant.Bool) || len(n.Body) > 0 || len(n.Else) > 0 {
- return
- }
- case ir.OFOR:
- n := n.(*ir.ForStmt)
- if !ir.IsConst(n.Cond, constant.Bool) || ir.BoolVal(n.Cond) {
- return
+ // Propagate the used flag for typeswitch variables up to the NONAME in its definition.
+ for _, ln := range fn.Dcl {
+ if ln.Op() == ir.ONAME && ln.Class == ir.PAUTO && ln.Used() {
+ if guard, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
+ guard.Used = true
}
- default:
- return
}
}
- fn.Body.Set([]ir.Node{ir.NewBlockStmt(base.Pos, nil)})
-}
-
-func deadcodeslice(nn *ir.Nodes) {
- var lastLabel = -1
- for i, n := range *nn {
- if n != nil && n.Op() == ir.OLABEL {
- lastLabel = i
- }
- }
- for i, n := range *nn {
- // Cut is set to true when all nodes after i'th position
- // should be removed.
- // In other words, it marks whole slice "tail" as dead.
- cut := false
- if n == nil {
+ for _, ln := range fn.Dcl {
+ if ln.Op() != ir.ONAME || ln.Class != ir.PAUTO || ln.Used() {
continue
}
- if n.Op() == ir.OIF {
- n := n.(*ir.IfStmt)
- n.Cond = deadcodeexpr(n.Cond)
- if ir.IsConst(n.Cond, constant.Bool) {
- var body ir.Nodes
- if ir.BoolVal(n.Cond) {
- n.Else = ir.Nodes{}
- body = n.Body
- } else {
- n.Body = ir.Nodes{}
- body = n.Else
- }
- // If "then" or "else" branch ends with panic or return statement,
- // it is safe to remove all statements after this node.
- // isterminating is not used to avoid goto-related complications.
- // We must be careful not to deadcode-remove labels, as they
- // might be the target of a goto. See issue 28616.
- if body := body; len(body) != 0 {
- switch body[(len(body) - 1)].Op() {
- case ir.ORETURN, ir.ORETJMP, ir.OPANIC:
- if i > lastLabel {
- cut = true
- }
- }
- }
+ if defn, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
+ if defn.Used {
+ continue
}
- }
-
- deadcodeslice(n.PtrInit())
- switch n.Op() {
- case ir.OBLOCK:
- n := n.(*ir.BlockStmt)
- deadcodeslice(&n.List)
- case ir.OFOR:
- n := n.(*ir.ForStmt)
- deadcodeslice(&n.Body)
- case ir.OIF:
- n := n.(*ir.IfStmt)
- deadcodeslice(&n.Body)
- deadcodeslice(&n.Else)
- case ir.ORANGE:
- n := n.(*ir.RangeStmt)
- deadcodeslice(&n.Body)
- case ir.OSELECT:
- n := n.(*ir.SelectStmt)
- for _, cas := range n.Cases {
- deadcodeslice(&cas.Body)
- }
- case ir.OSWITCH:
- n := n.(*ir.SwitchStmt)
- for _, cas := range n.Cases {
- deadcodeslice(&cas.Body)
- }
- }
-
- if cut {
- nn.Set((*nn)[:i+1])
- break
+ base.ErrorfAt(defn.Tag.Pos(), "%v declared but not used", ln.Sym())
+ defn.Used = true // suppress repeats
+ } else {
+ base.ErrorfAt(ln.Pos(), "%v declared but not used", ln.Sym())
}
}
}
-func deadcodeexpr(n ir.Node) ir.Node {
- // Perform dead-code elimination on short-circuited boolean
- // expressions involving constants with the intent of
- // producing a constant 'if' condition.
- switch n.Op() {
- case ir.OANDAND:
- n := n.(*ir.LogicalExpr)
- n.X = deadcodeexpr(n.X)
- n.Y = deadcodeexpr(n.Y)
- if ir.IsConst(n.X, constant.Bool) {
- if ir.BoolVal(n.X) {
- return n.Y // true && x => x
- } else {
- return n.X // false && x => false
- }
- }
- case ir.OOROR:
- n := n.(*ir.LogicalExpr)
- n.X = deadcodeexpr(n.X)
- n.Y = deadcodeexpr(n.Y)
- if ir.IsConst(n.X, constant.Bool) {
- if ir.BoolVal(n.X) {
- return n.X // true || x => true
- } else {
- return n.Y // false || x => x
- }
+// CheckReturn makes sure that fn terminates appropriately.
+func CheckReturn(fn *ir.Func) {
+ if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
+ markBreak(fn)
+ if !isTermNodes(fn.Body) {
+ base.ErrorfAt(fn.Endlineno, "missing return at end of function")
}
}
- return n
}
// getIotaValue returns the current value for "iota",
@@ -2275,7 +2140,7 @@ func deadcodeexpr(n ir.Node) ir.Node {
func getIotaValue() int64 {
if i := len(typecheckdefstack); i > 0 {
if x := typecheckdefstack[i-1]; x.Op() == ir.OLITERAL {
- return x.(*ir.Name).Iota()
+ return x.Iota()
}
}
diff --git a/src/cmd/compile/internal/typecheck/universe.go b/src/cmd/compile/internal/typecheck/universe.go
index fc8e962e28..402b8deeb3 100644
--- a/src/cmd/compile/internal/typecheck/universe.go
+++ b/src/cmd/compile/internal/typecheck/universe.go
@@ -90,8 +90,8 @@ var unsafeFuncs = [...]struct {
{"Sizeof", ir.OSIZEOF},
}
-// initUniverse initializes the universe block.
-func initUniverse() {
+// InitUniverse initializes the universe block.
+func InitUniverse() {
if types.PtrSize == 0 {
base.Fatalf("typeinit before betypeinit")
}
@@ -336,8 +336,8 @@ func makeErrorInterface() *types.Type {
return types.NewInterface(types.NoPkg, []*types.Field{method})
}
-// declareUniverse makes the universe block visible within the current package.
-func declareUniverse() {
+// DeclareUniverse makes the universe block visible within the current package.
+func DeclareUniverse() {
// Operationally, this is similar to a dot import of builtinpkg, except
// that we silently skip symbols that are already declared in the
// package block rather than emitting a redeclared symbol error.
@@ -357,6 +357,6 @@ func declareUniverse() {
ir.RegFP = NewName(Lookup(".fp"))
ir.RegFP.SetType(types.Types[types.TINT32])
- ir.RegFP.Class_ = ir.PPARAM
+ ir.RegFP.Class = ir.PPARAM
ir.RegFP.SetUsed(true)
}
diff --git a/src/cmd/compile/internal/types/sizeof_test.go b/src/cmd/compile/internal/types/sizeof_test.go
index 1ca07b12c8..675739f7f6 100644
--- a/src/cmd/compile/internal/types/sizeof_test.go
+++ b/src/cmd/compile/internal/types/sizeof_test.go
@@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Sym{}, 48, 80},
+ {Sym{}, 44, 72},
{Type{}, 56, 96},
{Map{}, 20, 40},
{Forward{}, 20, 32},
diff --git a/src/cmd/compile/internal/types/sym.go b/src/cmd/compile/internal/types/sym.go
index c512e3a003..2914e2ed3f 100644
--- a/src/cmd/compile/internal/types/sym.go
+++ b/src/cmd/compile/internal/types/sym.go
@@ -27,8 +27,7 @@ import (
// NOTE: In practice, things can be messier than the description above
// for various reasons (historical, convenience).
type Sym struct {
- Importdef *Pkg // where imported definition was found
- Linkname string // link name
+ Linkname string // link name
Pkg *Pkg
Name string // object name
@@ -75,6 +74,10 @@ func (sym *Sym) LinksymName() string {
return sym.Pkg.Prefix + "." + sym.Name
}
+// Deprecated: This method should not be used directly. Instead, use a
+// higher-level abstraction that directly returns the linker symbol
+// for a named object. For example, reflectdata.TypeLinksym(t) instead
+// of reflectdata.TypeSym(t).Linksym().
func (sym *Sym) Linksym() *obj.LSym {
if sym == nil {
return nil
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 6feedbfabc..5176b96c02 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -6,7 +6,6 @@ package types
import (
"cmd/compile/internal/base"
- "cmd/internal/obj"
"cmd/internal/src"
"fmt"
"sync"
@@ -1532,10 +1531,6 @@ func (t *Type) HasPointers() bool {
return true
}
-func (t *Type) Symbol() *obj.LSym {
- return TypeLinkSym(t)
-}
-
// Tie returns 'T' if t is a concrete type,
// 'I' if t is an interface type, and 'E' if t is an empty interface type.
// It is used to build calls to the conv* and assert* runtime routines.
diff --git a/src/cmd/compile/internal/types/utils.go b/src/cmd/compile/internal/types/utils.go
index 2477f1da66..f9f629ca3e 100644
--- a/src/cmd/compile/internal/types/utils.go
+++ b/src/cmd/compile/internal/types/utils.go
@@ -4,19 +4,8 @@
package types
-import (
- "cmd/internal/obj"
-)
-
const BADWIDTH = -1000000000
-// The following variables must be initialized early by the frontend.
-// They are here to break import cycles.
-// TODO(gri) eliminate these dependencies.
-var (
- TypeLinkSym func(*Type) *obj.LSym
-)
-
type bitset8 uint8
func (f *bitset8) set(mask uint8, b bool) {
diff --git a/src/cmd/compile/internal/walk/assign.go b/src/cmd/compile/internal/walk/assign.go
index c01079d236..3fe810ac4e 100644
--- a/src/cmd/compile/internal/walk/assign.go
+++ b/src/cmd/compile/internal/walk/assign.go
@@ -17,7 +17,7 @@ import (
// walkAssign walks an OAS (AssignExpr) or OASOP (AssignOpExpr) node.
func walkAssign(init *ir.Nodes, n ir.Node) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
var left, right ir.Node
switch n.Op() {
@@ -124,7 +124,7 @@ func walkAssignDotType(n *ir.AssignListStmt, init *ir.Nodes) ir.Node {
// walkAssignFunc walks an OAS2FUNC node.
func walkAssignFunc(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
r := n.Rhs[0]
walkExprListSafe(n.Lhs, init)
@@ -142,15 +142,13 @@ func walkAssignFunc(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
// walkAssignList walks an OAS2 node.
func walkAssignList(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
- init.Append(n.PtrInit().Take()...)
- walkExprListSafe(n.Lhs, init)
- walkExprListSafe(n.Rhs, init)
- return ir.NewBlockStmt(src.NoXPos, ascompatee(ir.OAS, n.Lhs, n.Rhs, init))
+ init.Append(ir.TakeInit(n)...)
+ return ir.NewBlockStmt(src.NoXPos, ascompatee(ir.OAS, n.Lhs, n.Rhs))
}
// walkAssignMapRead walks an OAS2MAPR node.
func walkAssignMapRead(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
r := n.Rhs[0].(*ir.IndexExpr)
walkExprListSafe(n.Lhs, init)
@@ -213,7 +211,7 @@ func walkAssignMapRead(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
// walkAssignRecv walks an OAS2RECV node.
func walkAssignRecv(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
r := n.Rhs[0].(*ir.UnaryExpr) // recv
walkExprListSafe(n.Lhs, init)
@@ -232,56 +230,21 @@ func walkAssignRecv(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
// walkReturn walks an ORETURN node.
func walkReturn(n *ir.ReturnStmt) ir.Node {
- ir.CurFunc.NumReturns++
+ fn := ir.CurFunc
+
+ fn.NumReturns++
if len(n.Results) == 0 {
return n
}
- if (ir.HasNamedResults(ir.CurFunc) && len(n.Results) > 1) || paramoutheap(ir.CurFunc) {
- // assign to the function out parameters,
- // so that ascompatee can fix up conflicts
- var rl []ir.Node
-
- for _, ln := range ir.CurFunc.Dcl {
- cl := ln.Class_
- if cl == ir.PAUTO || cl == ir.PAUTOHEAP {
- break
- }
- if cl == ir.PPARAMOUT {
- var ln ir.Node = ln
- if ir.IsParamStackCopy(ln) {
- ln = walkExpr(typecheck.Expr(ir.NewStarExpr(base.Pos, ln.Name().Heapaddr)), nil)
- }
- rl = append(rl, ln)
- }
- }
-
- if got, want := len(n.Results), len(rl); got != want {
- // order should have rewritten multi-value function calls
- // with explicit OAS2FUNC nodes.
- base.Fatalf("expected %v return arguments, have %v", want, got)
- }
-
- // move function calls out, to make ascompatee's job easier.
- walkExprListSafe(n.Results, n.PtrInit())
- n.Results.Set(ascompatee(n.Op(), rl, n.Results, n.PtrInit()))
- return n
+ results := fn.Type().Results().FieldSlice()
+ dsts := make([]ir.Node, len(results))
+ for i, v := range results {
+ // TODO(mdempsky): typecheck should have already checked the result variables.
+ dsts[i] = typecheck.AssignExpr(v.Nname.(*ir.Name))
}
- walkExprList(n.Results, n.PtrInit())
- // For each return parameter (lhs), assign the corresponding result (rhs).
- lhs := ir.CurFunc.Type().Results()
- rhs := n.Results
- res := make([]ir.Node, lhs.NumFields())
- for i, nl := range lhs.FieldSlice() {
- nname := ir.AsNode(nl.Nname)
- if ir.IsParamHeapCopy(nname) {
- nname = nname.Name().Stackcopy
- }
- a := ir.NewAssignStmt(base.Pos, nname, rhs[i])
- res[i] = convas(a, n.PtrInit())
- }
- n.Results.Set(res)
+ n.Results = ascompatee(n.Op(), dsts, n.Results)
return n
}
@@ -342,20 +305,12 @@ func ascompatet(nl ir.Nodes, nr *types.Type) []ir.Node {
// check assign expression list to
// an expression list. called in
// expr-list = expr-list
-func ascompatee(op ir.Op, nl, nr []ir.Node, init *ir.Nodes) []ir.Node {
+func ascompatee(op ir.Op, nl, nr []ir.Node) []ir.Node {
// cannot happen: should have been rejected during type checking
if len(nl) != len(nr) {
base.Fatalf("assignment operands mismatch: %+v / %+v", ir.Nodes(nl), ir.Nodes(nr))
}
- // ensure order of evaluation for function calls
- for i := range nl {
- nl[i] = safeExpr(nl[i], init)
- }
- for i := range nr {
- nr[i] = safeExpr(nr[i], init)
- }
-
var assigned ir.NameSet
var memWrite bool
@@ -376,27 +331,22 @@ func ascompatee(op ir.Op, nl, nr []ir.Node, init *ir.Nodes) []ir.Node {
// If a needed expression may be affected by an
// earlier assignment, make an early copy of that
// expression and use the copy instead.
- var early []ir.Node
+ var early ir.Nodes
save := func(np *ir.Node) {
if n := *np; affected(n) {
- tmp := ir.Node(typecheck.Temp(n.Type()))
- as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, tmp, n))
- early = append(early, as)
- *np = tmp
+ *np = copyExpr(n, n.Type(), &early)
}
}
- var late []ir.Node
- for i, l := range nl {
- r := nr[i]
+ var late ir.Nodes
+ for i, lorig := range nl {
+ l, r := lorig, nr[i]
// Do not generate 'x = x' during return. See issue 4014.
if op == ir.ORETURN && ir.SameSafeExpr(l, r) {
continue
}
- as := ir.NewAssignStmt(base.Pos, l, r)
-
// Save subexpressions needed on left side.
// Drill through non-dereferences.
for {
@@ -438,11 +388,11 @@ func ascompatee(op ir.Op, nl, nr []ir.Node, init *ir.Nodes) []ir.Node {
}
// Save expression on right side.
- save(&as.Y)
+ save(&r)
- late = append(late, convas(as, init))
+ appendWalkStmt(&late, convas(ir.NewAssignStmt(base.Pos, lorig, r), &late))
- if name == nil || name.Addrtaken() || name.Class_ == ir.PEXTERN || name.Class_ == ir.PAUTOHEAP {
+ if name == nil || name.Addrtaken() || name.Class == ir.PEXTERN || name.Class == ir.PAUTOHEAP {
memWrite = true
continue
}
@@ -450,10 +400,16 @@ func ascompatee(op ir.Op, nl, nr []ir.Node, init *ir.Nodes) []ir.Node {
// We can ignore assignments to blank.
continue
}
+ if op == ir.ORETURN && types.OrigSym(name.Sym()) == nil {
+ // We can also ignore assignments to anonymous result
+ // parameters. These can't appear in expressions anyway.
+ continue
+ }
assigned.Add(name)
}
- return append(early, late...)
+ early.Append(late.Take()...)
+ return early
}
// readsMemory reports whether the evaluation n directly reads from
@@ -462,7 +418,7 @@ func readsMemory(n ir.Node) bool {
switch n.Op() {
case ir.ONAME:
n := n.(*ir.Name)
- return n.Class_ == ir.PEXTERN || n.Class_ == ir.PAUTOHEAP || n.Addrtaken()
+ return n.Class == ir.PEXTERN || n.Class == ir.PAUTOHEAP || n.Addrtaken()
case ir.OADD,
ir.OAND,
diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go
index fe6045cbbd..a061181e2f 100644
--- a/src/cmd/compile/internal/walk/builtin.go
+++ b/src/cmd/compile/internal/walk/builtin.go
@@ -206,7 +206,7 @@ func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
// walkDelete walks an ODELETE node.
func walkDelete(init *ir.Nodes, n *ir.CallExpr) ir.Node {
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
map_ := n.Args[0]
key := n.Args[1]
map_ = walkExpr(map_, init)
@@ -531,7 +531,7 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
t = append(t, n)
}
t = append(t, ir.NewString("\n"))
- nn.Args.Set(t)
+ nn.Args = t
}
// Collapse runs of constant strings.
@@ -551,7 +551,7 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
i++
}
}
- nn.Args.Set(t)
+ nn.Args = t
calls := []ir.Node{mkcall("printlock", nil, init)}
for i, n := range nn.Args {
@@ -653,7 +653,7 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
walkExprList(calls, init)
r := ir.NewBlockStmt(base.Pos, nil)
- r.List.Set(calls)
+ r.List = calls
return walkStmt(typecheck.Stmt(r))
}
diff --git a/src/cmd/compile/internal/walk/closure.go b/src/cmd/compile/internal/walk/closure.go
index 30f86f0965..449df88f9e 100644
--- a/src/cmd/compile/internal/walk/closure.go
+++ b/src/cmd/compile/internal/walk/closure.go
@@ -52,7 +52,7 @@ func Closure(fn *ir.Func) {
v = addr
}
- v.Class_ = ir.PPARAM
+ v.Class = ir.PPARAM
decls = append(decls, v)
fld := types.NewField(src.NoXPos, v.Sym(), v.Type())
@@ -67,7 +67,7 @@ func Closure(fn *ir.Func) {
}
types.CalcSize(f.Type())
- fn.SetType(f.Type()) // update type of ODCLFUNC
+ fn.Nname.SetType(f.Type()) // update type of ODCLFUNC
} else {
// The closure is not called, so it is going to stay as closure.
var body []ir.Node
@@ -84,7 +84,7 @@ func Closure(fn *ir.Func) {
if v.Byval() && v.Type().Width <= int64(2*types.PtrSize) {
// If it is a small variable captured by value, downgrade it to PAUTO.
- v.Class_ = ir.PAUTO
+ v.Class = ir.PAUTO
fn.Dcl = append(fn.Dcl, v)
body = append(body, ir.NewAssignStmt(base.Pos, v, cr))
} else {
@@ -92,7 +92,7 @@ func Closure(fn *ir.Func) {
// and initialize in entry prologue.
addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
addr.SetType(types.NewPtr(v.Type()))
- addr.Class_ = ir.PAUTO
+ addr.Class = ir.PAUTO
addr.SetUsed(true)
addr.Curfn = fn
fn.Dcl = append(fn.Dcl, addr)
@@ -107,7 +107,7 @@ func Closure(fn *ir.Func) {
if len(body) > 0 {
typecheck.Stmts(body)
- fn.Enter.Set(body)
+ fn.Enter = body
fn.SetNeedctxt(true)
}
}
@@ -129,9 +129,9 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
typ := typecheck.ClosureType(clo)
- clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
+ clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
clos.SetEsc(clo.Esc())
- clos.List.Set(append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, fn.Nname)}, fn.ClosureEnter...))
+ clos.List = append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, fn.Nname)}, closureArgs(clo)...)
addr := typecheck.NodAddr(clos)
addr.SetEsc(clo.Esc())
@@ -144,14 +144,34 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
if !types.Identical(typ, x.Type()) {
panic("closure type does not match order's assigned type")
}
- addr.Alloc = x
+ addr.Prealloc = x
clo.Prealloc = nil
}
return walkExpr(cfn, init)
}
-func walkCallPart(n *ir.CallPartExpr, init *ir.Nodes) ir.Node {
+// closureArgs returns a slice of expressions that an be used to
+// initialize the given closure's free variables. These correspond
+// one-to-one with the variables in clo.Func.ClosureVars, and will be
+// either an ONAME node (if the variable is captured by value) or an
+// OADDR-of-ONAME node (if not).
+func closureArgs(clo *ir.ClosureExpr) []ir.Node {
+ fn := clo.Func
+
+ args := make([]ir.Node, len(fn.ClosureVars))
+ for i, v := range fn.ClosureVars {
+ var outer ir.Node
+ outer = v.Outer
+ if !v.Byval() {
+ outer = typecheck.NodAddrAt(fn.Pos(), outer)
+ }
+ args[i] = typecheck.Expr(outer)
+ }
+ return args
+}
+
+func walkCallPart(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
// Create closure in the form of a composite literal.
// For x.M with receiver (x) type T, the generated code looks like:
//
@@ -174,9 +194,9 @@ func walkCallPart(n *ir.CallPartExpr, init *ir.Nodes) ir.Node {
typ := typecheck.PartialCallType(n)
- clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
+ clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ), nil)
clos.SetEsc(n.Esc())
- clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, n.Func.Nname), n.X}
+ clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, typecheck.MethodValueWrapper(n).Nname), n.X}
addr := typecheck.NodAddr(clos)
addr.SetEsc(n.Esc())
@@ -189,7 +209,7 @@ func walkCallPart(n *ir.CallPartExpr, init *ir.Nodes) ir.Node {
if !types.Identical(typ, x.Type()) {
panic("partial call type does not match order's assigned type")
}
- addr.Alloc = x
+ addr.Prealloc = x
n.Prealloc = nil
}
diff --git a/src/cmd/compile/internal/walk/complit.go b/src/cmd/compile/internal/walk/complit.go
index 8c4f9583ef..8a77bba2ad 100644
--- a/src/cmd/compile/internal/walk/complit.go
+++ b/src/cmd/compile/internal/walk/complit.go
@@ -59,7 +59,7 @@ func (c initContext) String() string {
func readonlystaticname(t *types.Type) *ir.Name {
n := staticinit.StaticName(t)
n.MarkReadonly()
- n.Sym().Linksym().Set(obj.AttrContentAddressable, true)
+ n.Linksym().Set(obj.AttrContentAddressable, true)
return n
}
@@ -68,7 +68,7 @@ func isSimpleName(nn ir.Node) bool {
return false
}
n := nn.(*ir.Name)
- return n.Class_ != ir.PAUTOHEAP && n.Class_ != ir.PEXTERN
+ return n.Class != ir.PAUTOHEAP && n.Class != ir.PEXTERN
}
func litas(l ir.Node, r ir.Node, init *ir.Nodes) {
@@ -294,7 +294,7 @@ func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes)
// copy static to slice
var_ = typecheck.AssignExpr(var_)
name, offset, ok := staticinit.StaticLoc(var_)
- if !ok || name.Class_ != ir.PEXTERN {
+ if !ok || name.Class != ir.PEXTERN {
base.Fatalf("slicelit: %v", var_)
}
staticdata.InitSlice(name, offset, vstat, t.NumElem())
@@ -539,7 +539,7 @@ func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
case ir.OMETHEXPR:
- n := n.(*ir.MethodExpr)
+ n := n.(*ir.SelectorExpr)
anylit(n.FuncName(), var_, init)
case ir.OPTRLIT:
@@ -549,10 +549,10 @@ func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
}
var r ir.Node
- if n.Alloc != nil {
+ if n.Prealloc != nil {
// n.Right is stack temporary used as backing store.
- appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n.Alloc, nil)) // zero backing store, just in case (#18410)
- r = typecheck.NodAddr(n.Alloc)
+ appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n.Prealloc, nil)) // zero backing store, just in case (#18410)
+ r = typecheck.NodAddr(n.Prealloc)
} else {
r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
r.SetEsc(n.Esc())
@@ -657,7 +657,7 @@ func genAsStatic(as *ir.AssignStmt) {
}
name, offset, ok := staticinit.StaticLoc(as.X)
- if !ok || (name.Class_ != ir.PEXTERN && as.X != ir.BlankNode) {
+ if !ok || (name.Class != ir.PEXTERN && as.X != ir.BlankNode) {
base.Fatalf("genAsStatic: lhs %v", as.X)
}
@@ -666,7 +666,7 @@ func genAsStatic(as *ir.AssignStmt) {
staticdata.InitConst(name, offset, r, int(r.Type().Width))
return
case ir.OMETHEXPR:
- r := r.(*ir.MethodExpr)
+ r := r.(*ir.SelectorExpr)
staticdata.InitFunc(name, offset, r.FuncName())
return
case ir.ONAME:
@@ -674,7 +674,7 @@ func genAsStatic(as *ir.AssignStmt) {
if r.Offset_ != 0 {
base.Fatalf("genAsStatic %+v", as)
}
- if r.Class_ == ir.PFUNC {
+ if r.Class == ir.PFUNC {
staticdata.InitFunc(name, offset, r)
return
}
diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go
index 99abf30668..85459fd92f 100644
--- a/src/cmd/compile/internal/walk/convert.go
+++ b/src/cmd/compile/internal/walk/convert.go
@@ -68,12 +68,12 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
if ir.Names.Staticuint64s == nil {
ir.Names.Staticuint64s = typecheck.NewName(ir.Pkgs.Runtime.Lookup("staticuint64s"))
- ir.Names.Staticuint64s.Class_ = ir.PEXTERN
+ ir.Names.Staticuint64s.Class = ir.PEXTERN
// The actual type is [256]uint64, but we use [256*8]uint8 so we can address
// individual bytes.
ir.Names.Staticuint64s.SetType(types.NewArray(types.Types[types.TUINT8], 256*8))
ir.Names.Zerobase = typecheck.NewName(ir.Pkgs.Runtime.Lookup("zerobase"))
- ir.Names.Zerobase.Class_ = ir.PEXTERN
+ ir.Names.Zerobase.Class = ir.PEXTERN
ir.Names.Zerobase.SetType(types.Types[types.TUINTPTR])
}
@@ -98,7 +98,7 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
xe := ir.NewIndexExpr(base.Pos, ir.Names.Staticuint64s, index)
xe.SetBounded(true)
value = xe
- case n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class_ == ir.PEXTERN && n.X.(*ir.Name).Readonly():
+ case n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class == ir.PEXTERN && n.X.(*ir.Name).Readonly():
// n.Left is a readonly global; use it directly.
value = n.X
case !fromType.IsInterface() && n.Esc() == ir.EscNone && fromType.Width <= 1024:
@@ -438,18 +438,14 @@ func walkCheckPtrAlignment(n *ir.ConvExpr, init *ir.Nodes, count ir.Node) ir.Nod
}
func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
- // Calling cheapexpr(n, init) below leads to a recursive call
- // to walkexpr, which leads us back here again. Use n.Opt to
+ // Calling cheapexpr(n, init) below leads to a recursive call to
+ // walkexpr, which leads us back here again. Use n.Checkptr to
// prevent infinite loops.
- if opt := n.Opt(); opt == &walkCheckPtrArithmeticMarker {
+ if n.CheckPtr() {
return n
- } else if opt != nil {
- // We use n.Opt() here because today it's not used for OCONVNOP. If that changes,
- // there's no guarantee that temporarily replacing it is safe, so just hard fail here.
- base.Fatalf("unexpected Opt: %v", opt)
}
- n.SetOpt(&walkCheckPtrArithmeticMarker)
- defer n.SetOpt(nil)
+ n.SetCheckPtr(true)
+ defer n.SetCheckPtr(false)
// TODO(mdempsky): Make stricter. We only need to exempt
// reflect.Value.Pointer and reflect.Value.UnsafeAddr.
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go
index fd0dd5b062..3dffb496e9 100644
--- a/src/cmd/compile/internal/walk/expr.go
+++ b/src/cmd/compile/internal/walk/expr.go
@@ -26,7 +26,7 @@ func walkExpr(n ir.Node, init *ir.Nodes) ir.Node {
return n
}
- if init == n.PtrInit() {
+ if n, ok := n.(ir.InitNode); ok && init == n.PtrInit() {
// not okay to use n->ninit when walking n,
// because we might replace n with some other node
// and would lose the init list.
@@ -35,7 +35,7 @@ func walkExpr(n ir.Node, init *ir.Nodes) ir.Node {
if len(n.Init()) != 0 {
walkStmtList(n.Init())
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
}
lno := ir.SetPos(n)
@@ -52,9 +52,9 @@ func walkExpr(n ir.Node, init *ir.Nodes) ir.Node {
base.Fatalf("expression has untyped type: %+v", n)
}
- if n.Op() == ir.ONAME && n.(*ir.Name).Class_ == ir.PAUTOHEAP {
+ if n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PAUTOHEAP {
n := n.(*ir.Name)
- nn := ir.NewStarExpr(base.Pos, n.Name().Heapaddr)
+ nn := ir.NewStarExpr(base.Pos, n.Heapaddr)
nn.X.MarkNonNil()
return walkExpr(typecheck.Expr(nn), init)
}
@@ -100,7 +100,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
case ir.OMETHEXPR:
// TODO(mdempsky): Do this right after type checking.
- n := n.(*ir.MethodExpr)
+ n := n.(*ir.SelectorExpr)
return n.FuncName()
case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA:
@@ -306,7 +306,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
return walkClosure(n.(*ir.ClosureExpr), init)
case ir.OCALLPART:
- return walkCallPart(n.(*ir.CallPartExpr), init)
+ return walkCallPart(n.(*ir.SelectorExpr), init)
}
// No return! Each case must return (or panic),
@@ -359,7 +359,7 @@ func safeExpr(n ir.Node, init *ir.Nodes) ir.Node {
if len(n.Init()) != 0 {
walkStmtList(n.Init())
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
}
switch n.Op() {
@@ -477,7 +477,7 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
cat := typecheck.LookupRuntime(fn)
r := ir.NewCallExpr(base.Pos, ir.OCALL, cat, nil)
- r.Args.Set(args)
+ r.Args = args
r1 := typecheck.Expr(r)
r1 = walkExpr(r1, init)
r1.SetType(n.Type())
@@ -498,8 +498,7 @@ func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
// Prepend captured variables to argument list.
clo := n.X.(*ir.ClosureExpr)
- n.Args.Prepend(clo.Func.ClosureEnter...)
- clo.Func.ClosureEnter.Set(nil)
+ n.Args.Prepend(closureArgs(clo)...)
// Replace OCLOSURE with ONAME/PFUNC.
n.X = clo.Func.Nname
@@ -563,8 +562,8 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
}
}
- n.Args.Set(tempAssigns)
- n.Rargs.Set(args)
+ n.Args = tempAssigns
+ n.Rargs = args
}
// walkDivMod walks an ODIV or OMOD node.
@@ -639,12 +638,13 @@ func walkDot(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
func walkDotType(n *ir.TypeAssertExpr, init *ir.Nodes) ir.Node {
n.X = walkExpr(n.X, init)
// Set up interface type addresses for back end.
- n.Ntype = reflectdata.TypePtr(n.Type())
+
+ n.DstType = reflectdata.TypePtr(n.Type())
if n.Op() == ir.ODOTTYPE {
- n.Ntype.(*ir.AddrExpr).Alloc = reflectdata.TypePtr(n.X.Type())
+ n.SrcType = reflectdata.TypePtr(n.X.Type())
}
if !n.Type().IsInterface() && !n.X.Type().IsEmptyInterface() {
- n.Itab = []ir.Node{reflectdata.ITabAddr(n.Type(), n.X.Type())}
+ n.Itab = reflectdata.ITabAddr(n.Type(), n.X.Type())
}
return n
}
@@ -974,7 +974,7 @@ func usefield(n *ir.SelectorExpr) {
sym := reflectdata.TrackSym(outer, field)
if ir.CurFunc.FieldTrack == nil {
- ir.CurFunc.FieldTrack = make(map[*types.Sym]struct{})
+ ir.CurFunc.FieldTrack = make(map[*obj.LSym]struct{})
}
ir.CurFunc.FieldTrack[sym] = struct{}{}
}
diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go
index ebbd467570..38a9bec6e3 100644
--- a/src/cmd/compile/internal/walk/order.go
+++ b/src/cmd/compile/internal/walk/order.go
@@ -102,7 +102,7 @@ func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name {
// copyExpr behaves like newTemp but also emits
// code to initialize the temporary to the value n.
-func (o *orderState) copyExpr(n ir.Node) ir.Node {
+func (o *orderState) copyExpr(n ir.Node) *ir.Name {
return o.copyExpr1(n, false)
}
@@ -235,7 +235,7 @@ func (o *orderState) safeExpr(n ir.Node) ir.Node {
// because we emit explicit VARKILL instructions marking the end of those
// temporaries' lifetimes.
func isaddrokay(n ir.Node) bool {
- return ir.IsAddressable(n) && (n.Op() != ir.ONAME || n.(*ir.Name).Class_ == ir.PEXTERN || ir.IsAutoTmp(n))
+ return ir.IsAddressable(n) && (n.Op() != ir.ONAME || n.(*ir.Name).Class == ir.PEXTERN || ir.IsAutoTmp(n))
}
// addrTemp ensures that n is okay to pass by address to runtime routines.
@@ -406,7 +406,7 @@ func (o *orderState) edge() {
// Create a new uint8 counter to be allocated in section
// __libfuzzer_extra_counters.
counter := staticinit.StaticName(types.Types[types.TUINT8])
- counter.Name().SetLibfuzzerExtraCounter(true)
+ counter.SetLibfuzzerExtraCounter(true)
// counter += 1
incr := ir.NewAssignOpStmt(base.Pos, ir.OADD, counter, ir.NewInt(1))
@@ -423,7 +423,7 @@ func orderBlock(n *ir.Nodes, free map[string][]*ir.Name) {
order.edge()
order.stmtList(*n)
order.cleanTemp(mark)
- n.Set(order.out)
+ *n = order.out
}
// exprInPlace orders the side effects in *np and
@@ -466,8 +466,7 @@ func (o *orderState) init(n ir.Node) {
}
return
}
- o.stmtList(n.Init())
- n.PtrInit().Set(nil)
+ o.stmtList(ir.TakeInit(n))
}
// call orders the call expression n.
@@ -517,8 +516,8 @@ func (o *orderState) call(nn ir.Node) {
if arg.X.Type().IsUnsafePtr() {
x := o.copyExpr(arg.X)
arg.X = x
- x.Name().SetAddrtaken(true) // ensure SSA keeps the x variable
- n.Body.Append(typecheck.Stmt(ir.NewUnaryExpr(base.Pos, ir.OVARLIVE, x)))
+ x.SetAddrtaken(true) // ensure SSA keeps the x variable
+ n.KeepAlive = append(n.KeepAlive, x)
}
}
}
@@ -538,21 +537,7 @@ func (o *orderState) call(nn ir.Node) {
}
}
-// mapAssign appends n to o.out, introducing temporaries
-// to make sure that all map assignments have the form m[k] = x.
-// (Note: expr has already been called on n, so we know k is addressable.)
-//
-// If n is the multiple assignment form ..., m[k], ... = ..., x, ..., the rewrite is
-// t1 = m
-// t2 = k
-// ...., t3, ... = ..., x, ...
-// t1[t2] = t3
-//
-// The temporaries t1, t2 are needed in case the ... being assigned
-// contain m or k. They are usually unnecessary, but in the unnecessary
-// cases they are also typically registerizable, so not much harm done.
-// And this only applies to the multiple-assignment form.
-// We could do a more precise analysis if needed, like in walk.go.
+// mapAssign appends n to o.out.
func (o *orderState) mapAssign(n ir.Node) {
switch n.Op() {
default:
@@ -573,28 +558,7 @@ func (o *orderState) mapAssign(n ir.Node) {
case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC:
n := n.(*ir.AssignListStmt)
- var post []ir.Node
- for i, m := range n.Lhs {
- switch {
- case m.Op() == ir.OINDEXMAP:
- m := m.(*ir.IndexExpr)
- if !ir.IsAutoTmp(m.X) {
- m.X = o.copyExpr(m.X)
- }
- if !ir.IsAutoTmp(m.Index) {
- m.Index = o.copyExpr(m.Index)
- }
- fallthrough
- case base.Flag.Cfg.Instrumenting && n.Op() == ir.OAS2FUNC && !ir.IsBlank(m):
- t := o.newTemp(m.Type(), false)
- n.Lhs[i] = t
- a := ir.NewAssignStmt(base.Pos, m, t)
- post = append(post, typecheck.Stmt(a))
- }
- }
-
o.out = append(o.out, n)
- o.out = append(o.out, post...)
}
}
@@ -938,8 +902,7 @@ func (o *orderState) stmt(n ir.Node) {
if !ir.IsAutoTmp(recv.X) {
recv.X = o.copyExpr(recv.X)
}
- init := *r.PtrInit()
- r.PtrInit().Set(nil)
+ init := ir.TakeInit(r)
colas := r.Def
do := func(i int, t *types.Type) {
@@ -955,7 +918,7 @@ func (o *orderState) stmt(n ir.Node) {
if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).X == n {
init = init[1:]
}
- dcl := typecheck.Stmt(ir.NewDecl(base.Pos, ir.ODCL, n))
+ dcl := typecheck.Stmt(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
ncas.PtrInit().Append(dcl)
}
tmp := o.newTemp(t, t.HasPointers())
@@ -1000,8 +963,7 @@ func (o *orderState) stmt(n ir.Node) {
// TODO(mdempsky): Is this actually necessary?
// walkselect appears to walk Ninit.
- cas.Body.Prepend(cas.Init()...)
- cas.PtrInit().Set(nil)
+ cas.Body.Prepend(ir.TakeInit(cas)...)
}
o.out = append(o.out, n)
@@ -1236,9 +1198,9 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
// If left-hand side doesn't cause a short-circuit, issue right-hand side.
nif := ir.NewIfStmt(base.Pos, r, nil, nil)
if n.Op() == ir.OANDAND {
- nif.Body.Set(gen)
+ nif.Body = gen
} else {
- nif.Else.Set(gen)
+ nif.Else = gen
}
o.out = append(o.out, nif)
return r
@@ -1310,7 +1272,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
return n
case ir.OCALLPART:
- n := n.(*ir.CallPartExpr)
+ n := n.(*ir.SelectorExpr)
n.X = o.expr(n.X, nil)
if n.Transient() {
t := typecheck.PartialCallType(n)
@@ -1404,7 +1366,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
statics = append(statics, r)
}
- n.List.Set(statics)
+ n.List = statics
if len(dynamics) == 0 {
return n
@@ -1451,8 +1413,8 @@ func (o *orderState) as2(n *ir.AssignListStmt) {
o.out = append(o.out, n)
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
- as.Lhs.Set(left)
- as.Rhs.Set(tmplist)
+ as.Lhs = left
+ as.Rhs = tmplist
o.stmt(typecheck.Stmt(as))
}
diff --git a/src/cmd/compile/internal/walk/race.go b/src/cmd/compile/internal/walk/race.go
index 1fe439a99a..77cabe50c6 100644
--- a/src/cmd/compile/internal/walk/race.go
+++ b/src/cmd/compile/internal/walk/race.go
@@ -8,13 +8,14 @@ import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssagen"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"cmd/internal/sys"
)
func instrument(fn *ir.Func) {
- if fn.Pragma&ir.Norace != 0 || (fn.Sym().Linksym() != nil && fn.Sym().Linksym().ABIWrapper()) {
+ if fn.Pragma&ir.Norace != 0 || (fn.Linksym() != nil && fn.Linksym().ABIWrapper()) {
return
}
@@ -36,7 +37,10 @@ func instrument(fn *ir.Func) {
// This only works for amd64. This will not
// work on arm or others that might support
// race in the future.
- nodpc := ir.RegFP.CloneName()
+
+ nodpc := ir.NewNameAt(src.NoXPos, typecheck.Lookup(".fp"))
+ nodpc.Class = ir.PPARAM
+ nodpc.SetUsed(true)
nodpc.SetType(types.Types[types.TUINTPTR])
nodpc.SetFrameOffset(int64(-types.PtrSize))
fn.Dcl = append(fn.Dcl, nodpc)
diff --git a/src/cmd/compile/internal/walk/range.go b/src/cmd/compile/internal/walk/range.go
index 49a69e9751..9225c429f0 100644
--- a/src/cmd/compile/internal/walk/range.go
+++ b/src/cmd/compile/internal/walk/range.go
@@ -210,7 +210,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
a.SetTypecheck(1)
a.Lhs = []ir.Node{hv1, hb}
a.Rhs = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.ORECV, ha)}
- *nfor.Cond.PtrInit() = []ir.Node{a}
+ nfor.Cond = ir.InitExpr([]ir.Node{a}, nfor.Cond)
if v1 == nil {
body = nil
} else {
@@ -429,7 +429,7 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
// i = len(a) - 1
// }
n := ir.NewIfStmt(base.Pos, nil, nil, nil)
- n.Body.Set(nil)
+ n.Body = nil
n.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(0))
// hp = &a[0]
diff --git a/src/cmd/compile/internal/walk/select.go b/src/cmd/compile/internal/walk/select.go
index 1c5e1d7e64..776b020155 100644
--- a/src/cmd/compile/internal/walk/select.go
+++ b/src/cmd/compile/internal/walk/select.go
@@ -17,13 +17,12 @@ func walkSelect(sel *ir.SelectStmt) {
base.Fatalf("double walkselect")
}
- init := sel.Init()
- sel.PtrInit().Set(nil)
+ init := ir.TakeInit(sel)
init = append(init, walkSelectCases(sel.Cases)...)
sel.Cases = nil
- sel.Compiled.Set(init)
+ sel.Compiled = init
walkStmtList(sel.Compiled)
base.Pos = lno
@@ -45,8 +44,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node {
l := cas.Init()
if cas.Comm != nil { // not default:
n := cas.Comm
- l = append(l, n.Init()...)
- n.PtrInit().Set(nil)
+ l = append(l, ir.TakeInit(n)...)
switch n.Op() {
default:
base.Fatalf("select %v", n.Op())
@@ -106,7 +104,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node {
n := cas.Comm
ir.SetPos(n)
r := ir.NewIfStmt(base.Pos, nil, nil, nil)
- r.PtrInit().Set(cas.Init())
+ *r.PtrInit() = cas.Init()
var call ir.Node
switch n.Op() {
default:
@@ -138,8 +136,8 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node {
}
r.Cond = typecheck.Expr(call)
- r.Body.Set(cas.Body)
- r.Else.Set(append(dflt.Init(), dflt.Body...))
+ r.Body = cas.Body
+ r.Else = append(dflt.Init(), dflt.Body...)
return []ir.Node{r, ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)}
}
@@ -171,8 +169,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node {
for _, cas := range cases {
ir.SetPos(cas)
- init = append(init, cas.Init()...)
- cas.PtrInit().Set(nil)
+ init = append(init, ir.TakeInit(cas)...)
n := cas.Comm
if n == nil { // default:
diff --git a/src/cmd/compile/internal/walk/stmt.go b/src/cmd/compile/internal/walk/stmt.go
index 3fe7e103aa..1df491bd4e 100644
--- a/src/cmd/compile/internal/walk/stmt.go
+++ b/src/cmd/compile/internal/walk/stmt.go
@@ -55,19 +55,18 @@ func walkStmt(n ir.Node) ir.Node {
if n.Typecheck() == 0 {
base.Fatalf("missing typecheck: %+v", n)
}
- init := n.Init()
- n.PtrInit().Set(nil)
+ init := ir.TakeInit(n)
n = walkExpr(n, &init)
if n.Op() == ir.ONAME {
// copy rewrote to a statement list and a temp for the length.
// Throw away the temp to avoid plain values as statements.
n = ir.NewBlockStmt(n.Pos(), init)
- init.Set(nil)
+ init = nil
}
if len(init) > 0 {
switch n.Op() {
case ir.OAS, ir.OAS2, ir.OBLOCK:
- n.PtrInit().Prepend(init...)
+ n.(ir.InitNode).PtrInit().Prepend(init...)
default:
init.Append(n)
@@ -176,12 +175,12 @@ func walkStmtList(s []ir.Node) {
// walkDecl walks an ODCL node.
func walkDecl(n *ir.Decl) ir.Node {
- v := n.X.(*ir.Name)
- if v.Class_ == ir.PAUTOHEAP {
+ v := n.X
+ if v.Class == ir.PAUTOHEAP {
if base.Flag.CompilingRuntime {
base.Errorf("%v escapes to heap, not allowed in runtime", v)
}
- nn := ir.NewAssignStmt(base.Pos, v.Name().Heapaddr, callnew(v.Type()))
+ nn := ir.NewAssignStmt(base.Pos, v.Heapaddr, callnew(v.Type()))
nn.Def = true
return walkStmt(typecheck.Stmt(nn))
}
@@ -191,9 +190,8 @@ func walkDecl(n *ir.Decl) ir.Node {
// walkFor walks an OFOR or OFORUNTIL node.
func walkFor(n *ir.ForStmt) ir.Node {
if n.Cond != nil {
- walkStmtList(n.Cond.Init())
- init := n.Cond.Init()
- n.Cond.PtrInit().Set(nil)
+ init := ir.TakeInit(n.Cond)
+ walkStmtList(init)
n.Cond = walkExpr(n.Cond, &init)
n.Cond = ir.InitExpr(init, n.Cond)
}
@@ -228,7 +226,7 @@ func walkGoDefer(n *ir.GoDeferStmt) ir.Node {
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
call := call.(*ir.CallExpr)
- if len(call.Body) > 0 {
+ if len(call.KeepAlive) > 0 {
n.Call = wrapCall(call, &init)
} else {
n.Call = walkExpr(call, &init)
@@ -257,7 +255,7 @@ func walkIf(n *ir.IfStmt) ir.Node {
func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
if len(n.Init()) != 0 {
walkStmtList(n.Init())
- init.Append(n.PtrInit().Take()...)
+ init.Append(ir.TakeInit(n)...)
}
isBuiltinCall := n.Op() != ir.OCALLFUNC && n.Op() != ir.OCALLMETH && n.Op() != ir.OCALLINTER
@@ -267,7 +265,7 @@ func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
last := len(n.Args) - 1
if va := n.Args[last]; va.Op() == ir.OSLICELIT {
va := va.(*ir.CompLitExpr)
- n.Args.Set(append(n.Args[:last], va.List...))
+ n.Args = append(n.Args[:last], va.List...)
n.IsDDD = false
}
}
diff --git a/src/cmd/compile/internal/walk/switch.go b/src/cmd/compile/internal/walk/switch.go
index de0b471b34..59446ef3db 100644
--- a/src/cmd/compile/internal/walk/switch.go
+++ b/src/cmd/compile/internal/walk/switch.go
@@ -201,10 +201,15 @@ func (s *exprSwitch) flush() {
// Merge consecutive integer cases.
if s.exprname.Type().IsInteger() {
+ consecutive := func(last, next constant.Value) bool {
+ delta := constant.BinaryOp(next, token.SUB, last)
+ return constant.Compare(delta, token.EQL, constant.MakeInt64(1))
+ }
+
merged := cc[:1]
for _, c := range cc[1:] {
last := &merged[len(merged)-1]
- if last.jmp == c.jmp && ir.Int64Val(last.hi)+1 == ir.Int64Val(c.lo) {
+ if last.jmp == c.jmp && consecutive(last.hi.Val(), c.lo.Val()) {
last.hi = c.lo
} else {
merged = append(merged, c)
@@ -440,7 +445,7 @@ type typeClause struct {
body ir.Nodes
}
-func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp ir.Node) {
+func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar *ir.Name, jmp ir.Node) {
var body ir.Nodes
if caseVar != nil {
l := []ir.Node{
@@ -450,7 +455,7 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp ir.Node) {
typecheck.Stmts(l)
body.Append(l...)
} else {
- caseVar = ir.BlankNode
+ caseVar = ir.BlankNode.(*ir.Name)
}
// cv, ok = iface.(type)
diff --git a/src/cmd/compile/internal/walk/walk.go b/src/cmd/compile/internal/walk/walk.go
index c4c3debde4..928b673752 100644
--- a/src/cmd/compile/internal/walk/walk.go
+++ b/src/cmd/compile/internal/walk/walk.go
@@ -37,36 +37,6 @@ func Walk(fn *ir.Func) {
lno := base.Pos
- // Final typecheck for any unused variables.
- for i, ln := range fn.Dcl {
- if ln.Op() == ir.ONAME && (ln.Class_ == ir.PAUTO || ln.Class_ == ir.PAUTOHEAP) {
- ln = typecheck.AssignExpr(ln).(*ir.Name)
- fn.Dcl[i] = ln
- }
- }
-
- // Propagate the used flag for typeswitch variables up to the NONAME in its definition.
- for _, ln := range fn.Dcl {
- if ln.Op() == ir.ONAME && (ln.Class_ == ir.PAUTO || ln.Class_ == ir.PAUTOHEAP) && ln.Defn != nil && ln.Defn.Op() == ir.OTYPESW && ln.Used() {
- ln.Defn.(*ir.TypeSwitchGuard).Used = true
- }
- }
-
- for _, ln := range fn.Dcl {
- if ln.Op() != ir.ONAME || (ln.Class_ != ir.PAUTO && ln.Class_ != ir.PAUTOHEAP) || ln.Sym().Name[0] == '&' || ln.Used() {
- continue
- }
- if defn, ok := ln.Defn.(*ir.TypeSwitchGuard); ok {
- if defn.Used {
- continue
- }
- base.ErrorfAt(defn.Tag.Pos(), "%v declared but not used", ln.Sym())
- defn.Used = true // suppress repeats
- } else {
- base.ErrorfAt(ln.Pos(), "%v declared but not used", ln.Sym())
- }
- }
-
base.Pos = lno
if base.Errors() > errorsBefore {
return
@@ -91,7 +61,7 @@ func Walk(fn *ir.Func) {
func paramoutheap(fn *ir.Func) bool {
for _, ln := range fn.Dcl {
- switch ln.Class_ {
+ switch ln.Class {
case ir.PPARAMOUT:
if ir.IsParamStackCopy(ln) || ln.Addrtaken() {
return true
@@ -111,8 +81,7 @@ func walkRecv(n *ir.UnaryExpr) ir.Node {
if n.Typecheck() == 0 {
base.Fatalf("missing typecheck: %+v", n)
}
- init := n.Init()
- n.PtrInit().Set(nil)
+ init := ir.TakeInit(n)
n.X = walkExpr(n.X, &init)
call := walkExpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, typecheck.NodNil()), &init)
@@ -167,8 +136,8 @@ func paramstoheap(params *types.Type) []ir.Node {
}
if stackcopy := v.Name().Stackcopy; stackcopy != nil {
- nn = append(nn, walkStmt(ir.NewDecl(base.Pos, ir.ODCL, v)))
- if stackcopy.Class_ == ir.PPARAM {
+ nn = append(nn, walkStmt(ir.NewDecl(base.Pos, ir.ODCL, v.(*ir.Name))))
+ if stackcopy.Class == ir.PPARAM {
nn = append(nn, walkStmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, v, stackcopy))))
}
}
@@ -216,7 +185,7 @@ func returnsfromheap(params *types.Type) []ir.Node {
if v == nil {
continue
}
- if stackcopy := v.Name().Stackcopy; stackcopy != nil && stackcopy.Class_ == ir.PPARAMOUT {
+ if stackcopy := v.Name().Stackcopy; stackcopy != nil && stackcopy.Class == ir.PPARAMOUT {
nn = append(nn, walkStmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, stackcopy, v))))
}
}
@@ -377,8 +346,6 @@ func walkAppendArgs(n *ir.CallExpr, init *ir.Nodes) {
var wrapCall_prgen int
-var walkCheckPtrArithmeticMarker byte
-
// appendWalkStmt typechecks and walks stmt and then appends it to init.
func appendWalkStmt(init *ir.Nodes, stmt ir.Node) {
op := stmt.Op()