mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
[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
This commit is contained in:
commit
a8fe098a12
152
src/cmd/compile/internal/deadcode/deadcode.go
Normal file
152
src/cmd/compile/internal/deadcode/deadcode.go
Normal file
@ -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
|
||||||
|
}
|
@ -26,7 +26,7 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope,
|
|||||||
fn := curfn.(*ir.Func)
|
fn := curfn.(*ir.Func)
|
||||||
|
|
||||||
if fn.Nname != nil {
|
if fn.Nname != nil {
|
||||||
expect := fn.Sym().Linksym()
|
expect := fn.Linksym()
|
||||||
if fnsym.ABI() == obj.ABI0 {
|
if fnsym.ABI() == obj.ABI0 {
|
||||||
expect = fn.Sym().LinksymABI0()
|
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
|
if n.Op() != ir.ONAME { // might be OTYPE or OLITERAL
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
if !n.Used() {
|
if !n.Used() {
|
||||||
// Text == nil -> generating abstract function
|
// Text == nil -> generating abstract function
|
||||||
@ -90,7 +90,7 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
apdecls = append(apdecls, n)
|
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 {
|
func declPos(decl *ir.Name) src.XPos {
|
||||||
if decl.Name().Defn != nil && (decl.Name().Captured() || decl.Name().Byval()) {
|
return decl.Canonical().Pos()
|
||||||
// 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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// createDwarfVars process fn, returning a list of DWARF variables and the
|
// 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() {
|
if c == '.' || n.Type().IsUntyped() {
|
||||||
continue
|
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
|
// SSA-able args get location lists, and may move in and
|
||||||
// out of registers, so those are handled elsewhere.
|
// out of registers, so those are handled elsewhere.
|
||||||
// Autos and named output params seem to get handled
|
// 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())
|
typename := dwarf.InfoPrefix + types.TypeSymName(n.Type())
|
||||||
decls = append(decls, n)
|
decls = append(decls, n)
|
||||||
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
|
abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
|
||||||
isReturnValue := (n.Class_ == ir.PPARAMOUT)
|
isReturnValue := (n.Class == ir.PPARAMOUT)
|
||||||
if n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT {
|
if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
|
||||||
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
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
|
// If dcl in question has been promoted to heap, do a bit
|
||||||
// of extra work to recover original class (auto or param);
|
// of extra work to recover original class (auto or param);
|
||||||
// see issue 30908. This insures that we get the proper
|
// 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
|
// misleading location for the param (we want pointer-to-heap
|
||||||
// and not stack).
|
// and not stack).
|
||||||
// TODO(thanm): generate a better location expression
|
// TODO(thanm): generate a better location expression
|
||||||
stackcopy := n.Name().Stackcopy
|
stackcopy := n.Stackcopy
|
||||||
if stackcopy != nil && (stackcopy.Class_ == ir.PPARAM || stackcopy.Class_ == ir.PPARAMOUT) {
|
if stackcopy != nil && (stackcopy.Class == ir.PPARAM || stackcopy.Class == ir.PPARAMOUT) {
|
||||||
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
||||||
isReturnValue = (stackcopy.Class_ == ir.PPARAMOUT)
|
isReturnValue = (stackcopy.Class == ir.PPARAMOUT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inlIndex := 0
|
inlIndex := 0
|
||||||
if base.Flag.GenDwarfInl > 1 {
|
if base.Flag.GenDwarfInl > 1 {
|
||||||
if n.Name().InlFormal() || n.Name().InlLocal() {
|
if n.InlFormal() || n.InlLocal() {
|
||||||
inlIndex = posInlIndex(n.Pos()) + 1
|
inlIndex = posInlIndex(n.Pos()) + 1
|
||||||
if n.Name().InlFormal() {
|
if n.InlFormal() {
|
||||||
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,7 +223,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
|
|||||||
ChildIndex: -1,
|
ChildIndex: -1,
|
||||||
})
|
})
|
||||||
// Record go type of to insure that it gets emitted by the linker.
|
// 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
|
return decls, vars
|
||||||
@ -289,7 +272,7 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
|
|||||||
var abbrev int
|
var abbrev int
|
||||||
var offs int64
|
var offs int64
|
||||||
|
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
offs = n.FrameOffset()
|
offs = n.FrameOffset()
|
||||||
abbrev = dwarf.DW_ABRV_AUTO
|
abbrev = dwarf.DW_ABRV_AUTO
|
||||||
@ -305,16 +288,16 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
|
|||||||
abbrev = dwarf.DW_ABRV_PARAM
|
abbrev = dwarf.DW_ABRV_PARAM
|
||||||
offs = n.FrameOffset() + base.Ctxt.FixedFrameSize()
|
offs = n.FrameOffset() + base.Ctxt.FixedFrameSize()
|
||||||
default:
|
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())
|
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
|
inlIndex := 0
|
||||||
if base.Flag.GenDwarfInl > 1 {
|
if base.Flag.GenDwarfInl > 1 {
|
||||||
if n.Name().InlFormal() || n.Name().InlLocal() {
|
if n.InlFormal() || n.InlLocal() {
|
||||||
inlIndex = posInlIndex(n.Pos()) + 1
|
inlIndex = posInlIndex(n.Pos()) + 1
|
||||||
if n.Name().InlFormal() {
|
if n.InlFormal() {
|
||||||
abbrev = dwarf.DW_ABRV_PARAM
|
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))
|
declpos := base.Ctxt.InnermostPos(declPos(n))
|
||||||
return &dwarf.Var{
|
return &dwarf.Var{
|
||||||
Name: n.Sym().Name,
|
Name: n.Sym().Name,
|
||||||
IsReturnValue: n.Class_ == ir.PPARAMOUT,
|
IsReturnValue: n.Class == ir.PPARAMOUT,
|
||||||
IsInlFormal: n.Name().InlFormal(),
|
IsInlFormal: n.InlFormal(),
|
||||||
Abbrev: abbrev,
|
Abbrev: abbrev,
|
||||||
StackOffset: int32(offs),
|
StackOffset: int32(offs),
|
||||||
Type: base.Ctxt.Lookup(typename),
|
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]
|
n := debug.Vars[varID]
|
||||||
|
|
||||||
var abbrev int
|
var abbrev int
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
|
abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
|
||||||
case ir.PPARAM, ir.PPARAMOUT:
|
case ir.PPARAM, ir.PPARAMOUT:
|
||||||
@ -376,14 +359,14 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
gotype := reflectdata.TypeSym(n.Type()).Linksym()
|
gotype := reflectdata.TypeLinksym(n.Type())
|
||||||
delete(fnsym.Func().Autot, gotype)
|
delete(fnsym.Func().Autot, gotype)
|
||||||
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
|
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
|
||||||
inlIndex := 0
|
inlIndex := 0
|
||||||
if base.Flag.GenDwarfInl > 1 {
|
if base.Flag.GenDwarfInl > 1 {
|
||||||
if n.Name().InlFormal() || n.Name().InlLocal() {
|
if n.InlFormal() || n.InlLocal() {
|
||||||
inlIndex = posInlIndex(n.Pos()) + 1
|
inlIndex = posInlIndex(n.Pos()) + 1
|
||||||
if n.Name().InlFormal() {
|
if n.InlFormal() {
|
||||||
abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
|
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())
|
declpos := base.Ctxt.InnermostPos(n.Pos())
|
||||||
dvar := &dwarf.Var{
|
dvar := &dwarf.Var{
|
||||||
Name: n.Sym().Name,
|
Name: n.Sym().Name,
|
||||||
IsReturnValue: n.Class_ == ir.PPARAMOUT,
|
IsReturnValue: n.Class == ir.PPARAMOUT,
|
||||||
IsInlFormal: n.Name().InlFormal(),
|
IsInlFormal: n.InlFormal(),
|
||||||
Abbrev: abbrev,
|
Abbrev: abbrev,
|
||||||
Type: base.Ctxt.Lookup(typename),
|
Type: base.Ctxt.Lookup(typename),
|
||||||
// The stack offset is used as a sorting key, so for decomposed
|
// The stack offset is used as a sorting key, so for decomposed
|
||||||
|
@ -85,20 +85,29 @@ import (
|
|||||||
// u[2], etc. However, we do record the implicit dereference involved
|
// u[2], etc. However, we do record the implicit dereference involved
|
||||||
// in indexing a slice.
|
// 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
|
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
|
// loopDepth counts the current loop nesting depth within
|
||||||
// curfn. It increments within each "for" loop and at each
|
// curfn. It increments within each "for" loop and at each
|
||||||
// label with a corresponding backwards "goto" (i.e.,
|
// label with a corresponding backwards "goto" (i.e.,
|
||||||
// unstructured loop).
|
// unstructured loop).
|
||||||
loopDepth int
|
loopDepth int
|
||||||
|
|
||||||
heapLoc location
|
|
||||||
blankLoc location
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// An location represents an abstract location that stores a Go
|
// 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())
|
text = fmt.Sprintf("esc(%d)", n.Esc())
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, ok := n.Opt().(*location); ok && e.loopDepth != 0 {
|
if n.Op() == ir.ONAME {
|
||||||
if text != "" {
|
n := n.(*ir.Name)
|
||||||
text += " "
|
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
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,23 +196,33 @@ func Batch(fns []*ir.Func, recursive bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var e escape
|
var b batch
|
||||||
e.heapLoc.escapes = true
|
b.heapLoc.escapes = true
|
||||||
|
|
||||||
// Construct data-flow graph from syntax trees.
|
// Construct data-flow graph from syntax trees.
|
||||||
for _, fn := range fns {
|
for _, fn := range fns {
|
||||||
e.initFunc(fn)
|
b.initFunc(fn)
|
||||||
}
|
}
|
||||||
for _, fn := range fns {
|
for _, fn := range fns {
|
||||||
e.walkFunc(fn)
|
if !fn.IsHiddenClosure() {
|
||||||
|
b.walkFunc(fn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e.curfn = nil
|
|
||||||
|
|
||||||
e.walkAll()
|
b.walkAll()
|
||||||
e.finish(fns)
|
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 {
|
if fn.Esc() != escFuncUnknown {
|
||||||
base.Fatalf("unexpected node: %v", fn)
|
base.Fatalf("unexpected node: %v", fn)
|
||||||
}
|
}
|
||||||
@ -208,9 +231,6 @@ func (e *escape) initFunc(fn *ir.Func) {
|
|||||||
ir.Dump("escAnalyze", fn)
|
ir.Dump("escAnalyze", fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
e.curfn = fn
|
|
||||||
e.loopDepth = 1
|
|
||||||
|
|
||||||
// Allocate locations for local variables.
|
// Allocate locations for local variables.
|
||||||
for _, dcl := range fn.Dcl {
|
for _, dcl := range fn.Dcl {
|
||||||
if dcl.Op() == ir.ONAME {
|
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)
|
fn.SetEsc(escFuncStarted)
|
||||||
|
|
||||||
// Identify labels that mark the head of an unstructured loop.
|
// 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)
|
e.block(fn.Body)
|
||||||
|
|
||||||
if len(e.labels) != 0 {
|
if len(e.labels) != 0 {
|
||||||
@ -349,54 +368,52 @@ func (e *escape) stmt(n ir.Node) {
|
|||||||
case ir.ORANGE:
|
case ir.ORANGE:
|
||||||
// for Key, Value = range X { Body }
|
// for Key, Value = range X { Body }
|
||||||
n := n.(*ir.RangeStmt)
|
n := n.(*ir.RangeStmt)
|
||||||
|
|
||||||
|
// X is evaluated outside the loop.
|
||||||
|
tmp := e.newLoc(nil, false)
|
||||||
|
e.expr(tmp.asHole(), n.X)
|
||||||
|
|
||||||
e.loopDepth++
|
e.loopDepth++
|
||||||
e.addr(n.Key)
|
ks := e.addrs([]ir.Node{n.Key, n.Value})
|
||||||
k := e.addr(n.Value)
|
if n.X.Type().IsArray() {
|
||||||
|
e.flow(ks[1].note(n, "range"), tmp)
|
||||||
|
} else {
|
||||||
|
e.flow(ks[1].deref(n, "range-deref"), tmp)
|
||||||
|
}
|
||||||
|
|
||||||
e.block(n.Body)
|
e.block(n.Body)
|
||||||
e.loopDepth--
|
e.loopDepth--
|
||||||
|
|
||||||
// X is evaluated outside the loop.
|
|
||||||
if n.X.Type().IsArray() {
|
|
||||||
k = k.note(n, "range")
|
|
||||||
} else {
|
|
||||||
k = k.deref(n, "range-deref")
|
|
||||||
}
|
|
||||||
e.expr(e.later(k), n.X)
|
|
||||||
|
|
||||||
case ir.OSWITCH:
|
case ir.OSWITCH:
|
||||||
n := n.(*ir.SwitchStmt)
|
n := n.(*ir.SwitchStmt)
|
||||||
typesw := n.Tag != nil && n.Tag.Op() == ir.OTYPESW
|
|
||||||
|
|
||||||
var ks []hole
|
if guard, ok := n.Tag.(*ir.TypeSwitchGuard); ok {
|
||||||
for _, cas := range n.Cases { // cases
|
var ks []hole
|
||||||
if typesw && n.Tag.(*ir.TypeSwitchGuard).Tag != nil {
|
if guard.Tag != nil {
|
||||||
cv := cas.Var
|
for _, cas := range n.Cases {
|
||||||
k := e.dcl(cv) // type switch variables have no ODCL.
|
cv := cas.Var
|
||||||
if cv.Type().HasPointers() {
|
k := e.dcl(cv) // type switch variables have no ODCL.
|
||||||
ks = append(ks, k.dotType(cv.Type(), cas, "switch case"))
|
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)
|
e.expr(e.teeHole(ks...), n.Tag.(*ir.TypeSwitchGuard).X)
|
||||||
} else {
|
} else {
|
||||||
e.discard(n.Tag)
|
e.discard(n.Tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, cas := range n.Cases {
|
||||||
|
e.discards(cas.List)
|
||||||
|
e.block(cas.Body)
|
||||||
|
}
|
||||||
|
|
||||||
case ir.OSELECT:
|
case ir.OSELECT:
|
||||||
n := n.(*ir.SelectStmt)
|
n := n.(*ir.SelectStmt)
|
||||||
for _, cas := range n.Cases {
|
for _, cas := range n.Cases {
|
||||||
e.stmt(cas.Comm)
|
e.stmt(cas.Comm)
|
||||||
e.block(cas.Body)
|
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:
|
case ir.ORECV:
|
||||||
// TODO(mdempsky): Consider e.discard(n.Left).
|
// TODO(mdempsky): Consider e.discard(n.Left).
|
||||||
n := n.(*ir.UnaryExpr)
|
n := n.(*ir.UnaryExpr)
|
||||||
@ -408,28 +425,24 @@ func (e *escape) stmt(n ir.Node) {
|
|||||||
|
|
||||||
case ir.OAS:
|
case ir.OAS:
|
||||||
n := n.(*ir.AssignStmt)
|
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:
|
case ir.OASOP:
|
||||||
n := n.(*ir.AssignOpStmt)
|
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:
|
case ir.OAS2:
|
||||||
n := n.(*ir.AssignListStmt)
|
n := n.(*ir.AssignListStmt)
|
||||||
for i, nl := range n.Lhs {
|
e.assignList(n.Lhs, n.Rhs, "assign-pair", n)
|
||||||
e.assign(nl, n.Rhs[i], "assign-pair", n)
|
|
||||||
}
|
|
||||||
|
|
||||||
case ir.OAS2DOTTYPE: // v, ok = x.(type)
|
case ir.OAS2DOTTYPE: // v, ok = x.(type)
|
||||||
n := n.(*ir.AssignListStmt)
|
n := n.(*ir.AssignListStmt)
|
||||||
e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-dot-type", n)
|
e.assignList(n.Lhs, n.Rhs, "assign-pair-dot-type", n)
|
||||||
e.assign(n.Lhs[1], nil, "assign-pair-dot-type", n)
|
|
||||||
case ir.OAS2MAPR: // v, ok = m[k]
|
case ir.OAS2MAPR: // v, ok = m[k]
|
||||||
n := n.(*ir.AssignListStmt)
|
n := n.(*ir.AssignListStmt)
|
||||||
e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-mapr", n)
|
e.assignList(n.Lhs, n.Rhs, "assign-pair-mapr", n)
|
||||||
e.assign(n.Lhs[1], nil, "assign-pair-mapr", n)
|
case ir.OAS2RECV, ir.OSELRECV2: // v, ok = <-ch
|
||||||
case ir.OAS2RECV: // v, ok = <-ch
|
|
||||||
n := n.(*ir.AssignListStmt)
|
n := n.(*ir.AssignListStmt)
|
||||||
e.assign(n.Lhs[0], n.Rhs[0], "assign-pair-receive", n)
|
e.assignList(n.Lhs, n.Rhs, "assign-pair-receive", n)
|
||||||
e.assign(n.Lhs[1], nil, "assign-pair-receive", n)
|
|
||||||
|
|
||||||
case ir.OAS2FUNC:
|
case ir.OAS2FUNC:
|
||||||
n := n.(*ir.AssignListStmt)
|
n := n.(*ir.AssignListStmt)
|
||||||
@ -438,9 +451,11 @@ func (e *escape) stmt(n ir.Node) {
|
|||||||
case ir.ORETURN:
|
case ir.ORETURN:
|
||||||
n := n.(*ir.ReturnStmt)
|
n := n.(*ir.ReturnStmt)
|
||||||
results := e.curfn.Type().Results().FieldSlice()
|
results := e.curfn.Type().Results().FieldSlice()
|
||||||
for i, v := range n.Results {
|
dsts := make([]ir.Node, len(results))
|
||||||
e.assign(ir.AsNode(results[i].Nname), v, "return", n)
|
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:
|
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)
|
e.call(nil, n, nil)
|
||||||
case ir.OGO, ir.ODEFER:
|
case ir.OGO, ir.ODEFER:
|
||||||
@ -504,7 +519,7 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
|
|||||||
|
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
if n.Class_ == ir.PFUNC || n.Class_ == ir.PEXTERN {
|
if n.Class == ir.PFUNC || n.Class == ir.PEXTERN {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e.flow(k, e.oldLoc(n))
|
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
|
// Flow the receiver argument to both the closure and
|
||||||
// to the receiver parameter.
|
// to the receiver parameter.
|
||||||
|
|
||||||
n := n.(*ir.CallPartExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
closureK := e.spill(k, n)
|
closureK := e.spill(k, n)
|
||||||
|
|
||||||
m := n.Method
|
m := n.Selection
|
||||||
|
|
||||||
// We don't know how the method value will be called
|
// We don't know how the method value will be called
|
||||||
// later, so conservatively assume the result
|
// later, so conservatively assume the result
|
||||||
@ -676,9 +691,13 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
|
|||||||
|
|
||||||
case ir.OCLOSURE:
|
case ir.OCLOSURE:
|
||||||
n := n.(*ir.ClosureExpr)
|
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.
|
// Link addresses of captured variables to closure.
|
||||||
|
k = e.spill(k, n)
|
||||||
for _, v := range n.Func.ClosureVars {
|
for _, v := range n.Func.ClosureVars {
|
||||||
k := k
|
k := k
|
||||||
if !v.Byval() {
|
if !v.Byval() {
|
||||||
@ -772,13 +791,13 @@ func (e *escape) addr(n ir.Node) hole {
|
|||||||
base.Fatalf("unexpected addr: %v", n)
|
base.Fatalf("unexpected addr: %v", n)
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
if n.Class_ == ir.PEXTERN {
|
if n.Class == ir.PEXTERN {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
k = e.oldLoc(n).asHole()
|
k = e.oldLoc(n).asHole()
|
||||||
case ir.ONAMEOFFSET:
|
case ir.ONAMEOFFSET:
|
||||||
n := n.(*ir.NameOffsetExpr)
|
n := n.(*ir.NameOffsetExpr)
|
||||||
e.addr(n.Name_)
|
k = e.addr(n.Name_)
|
||||||
case ir.ODOT:
|
case ir.ODOT:
|
||||||
n := n.(*ir.SelectorExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
k = e.addr(n.X)
|
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)
|
e.assignHeap(n.Index, "key of map put", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !n.Type().HasPointers() {
|
|
||||||
k = e.discardHole()
|
|
||||||
}
|
|
||||||
|
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -813,6 +828,16 @@ func (e *escape) addrs(l ir.Nodes) []hole {
|
|||||||
return ks
|
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.
|
// assign evaluates the assignment dst = src.
|
||||||
func (e *escape) assign(dst, src ir.Node, why string, where ir.Node) {
|
func (e *escape) assign(dst, src ir.Node, why string, where ir.Node) {
|
||||||
// Filter out some no-op assignments for escape analysis.
|
// 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() {
|
switch call.Op() {
|
||||||
case ir.OCALLFUNC:
|
case ir.OCALLFUNC:
|
||||||
switch v := ir.StaticValue(call.X); {
|
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)
|
fn = v.(*ir.Name)
|
||||||
case v.Op() == ir.OCLOSURE:
|
case v.Op() == ir.OCLOSURE:
|
||||||
fn = v.(*ir.ClosureExpr).Func.Nname
|
fn = v.(*ir.ClosureExpr).Func.Nname
|
||||||
@ -1097,7 +1122,7 @@ func (e *escape) teeHole(ks ...hole) hole {
|
|||||||
return loc.asHole()
|
return loc.asHole()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *escape) dcl(n ir.Node) hole {
|
func (e *escape) dcl(n *ir.Name) hole {
|
||||||
loc := e.oldLoc(n)
|
loc := e.oldLoc(n)
|
||||||
loc.loopDepth = e.loopDepth
|
loc.loopDepth = e.loopDepth
|
||||||
return loc.asHole()
|
return loc.asHole()
|
||||||
@ -1121,19 +1146,6 @@ func (e *escape) later(k hole) hole {
|
|||||||
return loc.asHole()
|
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 {
|
func (e *escape) newLoc(n ir.Node, transient bool) *location {
|
||||||
if e.curfn == nil {
|
if e.curfn == nil {
|
||||||
base.Fatalf("e.curfn isn't set")
|
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())
|
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{
|
loc := &location{
|
||||||
n: n,
|
n: n,
|
||||||
curfn: e.curfn,
|
curfn: e.curfn,
|
||||||
@ -1151,15 +1165,17 @@ func (e *escape) newLoc(n ir.Node, transient bool) *location {
|
|||||||
}
|
}
|
||||||
e.allLocs = append(e.allLocs, loc)
|
e.allLocs = append(e.allLocs, loc)
|
||||||
if n != nil {
|
if n != nil {
|
||||||
if n.Op() == ir.ONAME && n.Name().Curfn != e.curfn {
|
if n.Op() == ir.ONAME {
|
||||||
n := n.(*ir.Name)
|
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 {
|
if n.Opt != nil {
|
||||||
base.Fatalf("%v already has a location", n)
|
base.Fatalf("%v already has a location", n)
|
||||||
|
}
|
||||||
|
n.Opt = loc
|
||||||
}
|
}
|
||||||
n.SetOpt(loc)
|
|
||||||
|
|
||||||
if why := HeapAllocReason(n); why != "" {
|
if why := HeapAllocReason(n); why != "" {
|
||||||
e.flow(e.heapHole().addr(n, why), loc)
|
e.flow(e.heapHole().addr(n, why), loc)
|
||||||
@ -1168,9 +1184,8 @@ func (e *escape) newLoc(n ir.Node, transient bool) *location {
|
|||||||
return loc
|
return loc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *escape) oldLoc(n ir.Node) *location {
|
func (b *batch) oldLoc(n *ir.Name) *location {
|
||||||
n = canonicalNode(n)
|
return n.Canonical().Opt.(*location)
|
||||||
return n.Opt().(*location)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *location) asHole() hole {
|
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
|
// walkAll computes the minimal dereferences between all pairs of
|
||||||
// locations.
|
// locations.
|
||||||
func (e *escape) walkAll() {
|
func (b *batch) walkAll() {
|
||||||
// We use a work queue to keep track of locations that we need
|
// We use a work queue to keep track of locations that we need
|
||||||
// to visit, and repeatedly walk until we reach a fixed point.
|
// 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.
|
// happen at most once. So we take Θ(len(e.allLocs)) walks.
|
||||||
|
|
||||||
// LIFO queue, has enough room for e.allLocs and e.heapLoc.
|
// 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) {
|
enqueue := func(loc *location) {
|
||||||
if !loc.queued {
|
if !loc.queued {
|
||||||
todo = append(todo, loc)
|
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(loc)
|
||||||
}
|
}
|
||||||
enqueue(&e.heapLoc)
|
enqueue(&b.heapLoc)
|
||||||
|
|
||||||
var walkgen uint32
|
var walkgen uint32
|
||||||
for len(todo) > 0 {
|
for len(todo) > 0 {
|
||||||
@ -1240,13 +1255,13 @@ func (e *escape) walkAll() {
|
|||||||
root.queued = false
|
root.queued = false
|
||||||
|
|
||||||
walkgen++
|
walkgen++
|
||||||
e.walkOne(root, walkgen, enqueue)
|
b.walkOne(root, walkgen, enqueue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// walkOne computes the minimal number of dereferences from root to
|
// walkOne computes the minimal number of dereferences from root to
|
||||||
// all other locations.
|
// 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
|
// The data flow graph has negative edges (from addressing
|
||||||
// operations), so we use the Bellman-Ford algorithm. However,
|
// operations), so we use the Bellman-Ford algorithm. However,
|
||||||
// we don't have to worry about infinite negative cycles since
|
// 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
|
// l's value flows to root. If l is a function
|
||||||
// parameter and root is the heap or a
|
// parameter and root is the heap or a
|
||||||
// corresponding result parameter, then record
|
// 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 l.isName(ir.PPARAM) {
|
||||||
if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.escapes {
|
if (logopt.Enabled() || base.Flag.LowerM >= 2) && !l.escapes {
|
||||||
if base.Flag.LowerM >= 2 {
|
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() {
|
if logopt.Enabled() {
|
||||||
logopt.LogOpt(l.n.Pos(), "leak", "escape", ir.FuncName(e.curfn),
|
var e_curfn *ir.Func // TODO(mdempsky): Fix.
|
||||||
fmt.Sprintf("parameter %v leaks to %s with derefs=%d", l.n, e.explainLoc(root), derefs), explanation)
|
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)
|
l.leakTo(root, derefs)
|
||||||
@ -1309,9 +1325,10 @@ func (e *escape) walkOne(root *location, walkgen uint32, enqueue func(*location)
|
|||||||
if base.Flag.LowerM >= 2 {
|
if base.Flag.LowerM >= 2 {
|
||||||
fmt.Printf("%s: %v escapes to heap:\n", base.FmtPos(l.n.Pos()), l.n)
|
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() {
|
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
|
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.
|
// 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)
|
visited := make(map[*location]bool)
|
||||||
pos := base.FmtPos(src.n.Pos())
|
pos := base.FmtPos(src.n.Pos())
|
||||||
var explanation []*logopt.LoggedOpt
|
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)
|
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 {
|
if dst == root {
|
||||||
break
|
break
|
||||||
@ -1367,14 +1384,14 @@ func (e *escape) explainPath(root, src *location) []*logopt.LoggedOpt {
|
|||||||
return explanation
|
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 := "&"
|
ops := "&"
|
||||||
if derefs >= 0 {
|
if derefs >= 0 {
|
||||||
ops = strings.Repeat("*", derefs)
|
ops = strings.Repeat("*", derefs)
|
||||||
}
|
}
|
||||||
print := base.Flag.LowerM >= 2
|
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 {
|
if print {
|
||||||
fmt.Printf("%s:%s\n", pos, flow)
|
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 {
|
} else if srcloc != nil && srcloc.n != nil {
|
||||||
epos = srcloc.n.Pos()
|
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 {
|
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()))
|
fmt.Printf("%s: from %v (%v) at %s\n", pos, note.where, note.why, base.FmtPos(note.where.Pos()))
|
||||||
}
|
}
|
||||||
if logopt.Enabled() {
|
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)))
|
fmt.Sprintf(" from %v (%v)", note.where, note.why)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return explanation
|
return explanation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *escape) explainLoc(l *location) string {
|
func (b *batch) explainLoc(l *location) string {
|
||||||
if l == &e.heapLoc {
|
if l == &b.heapLoc {
|
||||||
return "{heap}"
|
return "{heap}"
|
||||||
}
|
}
|
||||||
if l.n == nil {
|
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
|
// outlives reports whether values stored in l may survive beyond
|
||||||
// other's lifetime if stack allocated.
|
// 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.
|
// The heap outlives everything.
|
||||||
if l.escapes {
|
if l.escapes {
|
||||||
return true
|
return true
|
||||||
@ -1497,7 +1516,7 @@ func (l *location) leakTo(sink *location, derefs int) {
|
|||||||
l.paramEsc.AddHeap(derefs)
|
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.
|
// Record parameter tags for package export data.
|
||||||
for _, fn := range fns {
|
for _, fn := range fns {
|
||||||
fn.SetEsc(escFuncTagged)
|
fn.SetEsc(escFuncTagged)
|
||||||
@ -1506,17 +1525,20 @@ func (e *escape) finish(fns []*ir.Func) {
|
|||||||
for _, fs := range &types.RecvsParams {
|
for _, fs := range &types.RecvsParams {
|
||||||
for _, f := range fs(fn.Type()).Fields().Slice() {
|
for _, f := range fs(fn.Type()).Fields().Slice() {
|
||||||
narg++
|
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
|
n := loc.n
|
||||||
if n == nil {
|
if n == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
n.SetOpt(nil)
|
if n.Op() == ir.ONAME {
|
||||||
|
n := n.(*ir.Name)
|
||||||
|
n.Opt = nil
|
||||||
|
}
|
||||||
|
|
||||||
// Update n.Esc based on escape analysis results.
|
// 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)
|
base.WarnfAt(n.Pos(), "%v escapes to heap", n)
|
||||||
}
|
}
|
||||||
if logopt.Enabled() {
|
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)
|
n.SetEsc(ir.EscHeap)
|
||||||
@ -1542,7 +1565,7 @@ func (e *escape) finish(fns []*ir.Func) {
|
|||||||
n := n.(*ir.ClosureExpr)
|
n := n.(*ir.ClosureExpr)
|
||||||
n.SetTransient(true)
|
n.SetTransient(true)
|
||||||
case ir.OCALLPART:
|
case ir.OCALLPART:
|
||||||
n := n.(*ir.CallPartExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
n.SetTransient(true)
|
n.SetTransient(true)
|
||||||
case ir.OSLICELIT:
|
case ir.OSLICELIT:
|
||||||
n := n.(*ir.CompLitExpr)
|
n := n.(*ir.CompLitExpr)
|
||||||
@ -1554,7 +1577,7 @@ func (e *escape) finish(fns []*ir.Func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *location) isName(c ir.Class) bool {
|
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
|
const numEscResults = 7
|
||||||
@ -1847,7 +1870,7 @@ func HeapAllocReason(n ir.Node) string {
|
|||||||
// Parameters are always passed via the stack.
|
// Parameters are always passed via the stack.
|
||||||
if n.Op() == ir.ONAME {
|
if n.Op() == ir.ONAME {
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
if n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT {
|
if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1863,7 +1886,7 @@ func HeapAllocReason(n ir.Node) string {
|
|||||||
if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
|
if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
|
||||||
return "too large for stack"
|
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"
|
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.
|
// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
|
||||||
// on PPARAM it means something different.
|
// 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
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1914,7 +1937,7 @@ func addrescapes(n ir.Node) {
|
|||||||
break
|
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
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1968,7 +1991,7 @@ func moveToHeap(n *ir.Name) {
|
|||||||
if base.Flag.CompilingRuntime {
|
if base.Flag.CompilingRuntime {
|
||||||
base.Errorf("%v escapes to heap, not allowed in runtime", n)
|
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)
|
ir.Dump("n", n)
|
||||||
base.Fatalf("double move to heap")
|
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
|
// Parameters have a local stack copy used at function start/end
|
||||||
// in addition to the copy in the heap that may live longer than
|
// in addition to the copy in the heap that may live longer than
|
||||||
// the function.
|
// 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 {
|
if n.FrameOffset() == types.BADWIDTH {
|
||||||
base.Fatalf("addrescapes before param assignment")
|
base.Fatalf("addrescapes before param assignment")
|
||||||
}
|
}
|
||||||
@ -1999,9 +2022,9 @@ func moveToHeap(n *ir.Name) {
|
|||||||
stackcopy := typecheck.NewName(n.Sym())
|
stackcopy := typecheck.NewName(n.Sym())
|
||||||
stackcopy.SetType(n.Type())
|
stackcopy.SetType(n.Type())
|
||||||
stackcopy.SetFrameOffset(n.FrameOffset())
|
stackcopy.SetFrameOffset(n.FrameOffset())
|
||||||
stackcopy.Class_ = n.Class_
|
stackcopy.Class = n.Class
|
||||||
stackcopy.Heapaddr = heapaddr
|
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.
|
// 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.
|
// 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
|
// 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.
|
// Parameters are before locals, so can stop early.
|
||||||
// This limits the search even in functions with many local variables.
|
// This limits the search even in functions with many local variables.
|
||||||
if d.Class_ == ir.PAUTO {
|
if d.Class == ir.PAUTO {
|
||||||
break
|
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.
|
// 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.SetFrameOffset(0)
|
||||||
n.Heapaddr = heapaddr
|
n.Heapaddr = heapaddr
|
||||||
n.SetEsc(ir.EscHeap)
|
n.SetEsc(ir.EscHeap)
|
||||||
@ -2052,7 +2075,7 @@ const UnsafeUintptrNote = "unsafe-uintptr"
|
|||||||
// marked go:uintptrescapes.
|
// marked go:uintptrescapes.
|
||||||
const UintptrEscapesNote = "uintptr-escapes"
|
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 {
|
name := func() string {
|
||||||
if f.Sym != nil {
|
if f.Sym != nil {
|
||||||
return f.Sym.Name
|
return f.Sym.Name
|
||||||
@ -2122,8 +2145,8 @@ func (e *escape) paramTag(fn *ir.Func, narg int, f *types.Field) string {
|
|||||||
return esc.Encode()
|
return esc.Encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
n := ir.AsNode(f.Nname)
|
n := f.Nname.(*ir.Name)
|
||||||
loc := e.oldLoc(n)
|
loc := b.oldLoc(n)
|
||||||
esc := loc.paramEsc
|
esc := loc.paramEsc
|
||||||
esc.Optimize()
|
esc.Optimize()
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ package gc
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
"cmd/compile/internal/reflectdata"
|
|
||||||
"cmd/compile/internal/ssagen"
|
"cmd/compile/internal/ssagen"
|
||||||
"cmd/compile/internal/typecheck"
|
"cmd/compile/internal/typecheck"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
@ -39,13 +38,7 @@ func TestMain(m *testing.M) {
|
|||||||
base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
|
base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
|
||||||
types.PtrSize = ssagen.Arch.LinkArch.PtrSize
|
types.PtrSize = ssagen.Arch.LinkArch.PtrSize
|
||||||
types.RegSize = ssagen.Arch.LinkArch.RegSize
|
types.RegSize = ssagen.Arch.LinkArch.RegSize
|
||||||
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
typecheck.InitUniverse()
|
||||||
return reflectdata.TypeSym(t).Linksym()
|
|
||||||
}
|
|
||||||
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
|
||||||
return reflectdata.TypeSym(t).Linksym()
|
|
||||||
}
|
|
||||||
typecheck.Init()
|
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
func mkParamResultField(t *types.Type, s *types.Sym, which ir.Class) *types.Field {
|
func mkParamResultField(t *types.Type, s *types.Sym, which ir.Class) *types.Field {
|
||||||
field := types.NewField(src.NoXPos, s, t)
|
field := types.NewField(src.NoXPos, s, t)
|
||||||
n := typecheck.NewName(s)
|
n := typecheck.NewName(s)
|
||||||
n.Class_ = which
|
n.Class = which
|
||||||
field.Nname = n
|
field.Nname = n
|
||||||
n.SetType(t)
|
n.SetType(t)
|
||||||
return field
|
return field
|
||||||
|
@ -83,7 +83,7 @@ func compile(fn *ir.Func) {
|
|||||||
// because symbols must be allocated before the parallel
|
// because symbols must be allocated before the parallel
|
||||||
// phase of the compiler.
|
// phase of the compiler.
|
||||||
for _, n := range fn.Dcl {
|
for _, n := range fn.Dcl {
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
|
case ir.PPARAM, ir.PPARAMOUT, ir.PAUTO:
|
||||||
if liveness.ShouldTrack(n) && n.Addrtaken() {
|
if liveness.ShouldTrack(n) && n.Addrtaken() {
|
||||||
reflectdata.WriteType(n.Type())
|
reflectdata.WriteType(n.Type())
|
||||||
@ -174,5 +174,5 @@ func isInlinableButNotInlined(fn *ir.Func) bool {
|
|||||||
if fn.Sym() == nil {
|
if fn.Sym() == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return !fn.Sym().Linksym().WasInlined()
|
return !fn.Linksym().WasInlined()
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ type exporter struct {
|
|||||||
func (p *exporter) markObject(n ir.Node) {
|
func (p *exporter) markObject(n ir.Node) {
|
||||||
if n.Op() == ir.ONAME {
|
if n.Op() == ir.ONAME {
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
if n.Class_ == ir.PFUNC {
|
if n.Class == ir.PFUNC {
|
||||||
inline.Inline_Flood(n, typecheck.Export)
|
inline.Inline_Flood(n, typecheck.Export)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,13 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:generate go run mkbuiltin.go
|
|
||||||
|
|
||||||
package gc
|
package gc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
|
"cmd/compile/internal/deadcode"
|
||||||
"cmd/compile/internal/devirtualize"
|
"cmd/compile/internal/devirtualize"
|
||||||
"cmd/compile/internal/dwarfgen"
|
"cmd/compile/internal/dwarfgen"
|
||||||
"cmd/compile/internal/escape"
|
"cmd/compile/internal/escape"
|
||||||
@ -192,9 +191,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
|||||||
types.PtrSize = ssagen.Arch.LinkArch.PtrSize
|
types.PtrSize = ssagen.Arch.LinkArch.PtrSize
|
||||||
types.RegSize = ssagen.Arch.LinkArch.RegSize
|
types.RegSize = ssagen.Arch.LinkArch.RegSize
|
||||||
types.MaxWidth = ssagen.Arch.MAXWIDTH
|
types.MaxWidth = ssagen.Arch.MAXWIDTH
|
||||||
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
|
||||||
return reflectdata.TypeSym(t).Linksym()
|
|
||||||
}
|
|
||||||
|
|
||||||
typecheck.Target = new(ir.Package)
|
typecheck.Target = new(ir.Package)
|
||||||
|
|
||||||
@ -204,37 +200,60 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
|||||||
|
|
||||||
base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
|
base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
|
||||||
|
|
||||||
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
typecheck.InitUniverse()
|
||||||
return reflectdata.TypeSym(t).Linksym()
|
|
||||||
}
|
|
||||||
typecheck.Init()
|
|
||||||
|
|
||||||
// Parse input.
|
// Parse and typecheck input.
|
||||||
base.Timer.Start("fe", "parse")
|
noder.LoadPackage(flag.Args())
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
dwarfgen.RecordPackageName()
|
dwarfgen.RecordPackageName()
|
||||||
|
ssagen.CgoSymABIs()
|
||||||
// Typecheck.
|
|
||||||
typecheck.Package()
|
|
||||||
|
|
||||||
// With all user code typechecked, it's now safe to verify unused dot imports.
|
|
||||||
noder.CheckDotImports()
|
|
||||||
base.ExitIfErrors()
|
|
||||||
|
|
||||||
// Build init task.
|
// Build init task.
|
||||||
if initTask := pkginit.Task(); initTask != nil {
|
if initTask := pkginit.Task(); initTask != nil {
|
||||||
typecheck.Export(initTask)
|
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
|
// Inlining
|
||||||
base.Timer.Start("fe", "inlining")
|
base.Timer.Start("fe", "inlining")
|
||||||
if base.Flag.LowerL != 0 {
|
if base.Flag.LowerL != 0 {
|
||||||
@ -285,6 +304,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
|||||||
// Prepare for SSA compilation.
|
// Prepare for SSA compilation.
|
||||||
// This must be before peekitabs, because peekitabs
|
// This must be before peekitabs, because peekitabs
|
||||||
// can trigger function compilation.
|
// can trigger function compilation.
|
||||||
|
typecheck.InitRuntime()
|
||||||
ssagen.InitConfig()
|
ssagen.InitConfig()
|
||||||
|
|
||||||
// Just before compilation, compile itabs found on
|
// Just before compilation, compile itabs found on
|
||||||
|
@ -148,8 +148,8 @@ func dumpdata() {
|
|||||||
dumpglobls(typecheck.Target.Externs[numExterns:])
|
dumpglobls(typecheck.Target.Externs[numExterns:])
|
||||||
|
|
||||||
if reflectdata.ZeroSize > 0 {
|
if reflectdata.ZeroSize > 0 {
|
||||||
zero := ir.Pkgs.Map.Lookup("zero")
|
zero := ir.Pkgs.Map.Lookup("zero").Linksym()
|
||||||
objw.Global(zero.Linksym(), int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
|
objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
|
||||||
}
|
}
|
||||||
|
|
||||||
addGCLocals()
|
addGCLocals()
|
||||||
@ -188,7 +188,7 @@ func dumpGlobal(n *ir.Name) {
|
|||||||
if n.Type() == nil {
|
if n.Type() == nil {
|
||||||
base.Fatalf("external %v nil type\n", n)
|
base.Fatalf("external %v nil type\n", n)
|
||||||
}
|
}
|
||||||
if n.Class_ == ir.PFUNC {
|
if n.Class == ir.PFUNC {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if n.Sym().Pkg != types.LocalPkg {
|
if n.Sym().Pkg != types.LocalPkg {
|
||||||
@ -260,18 +260,18 @@ func addGCLocals() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ggloblnod(nam ir.Node) {
|
func ggloblnod(nam *ir.Name) {
|
||||||
s := nam.Sym().Linksym()
|
s := nam.Linksym()
|
||||||
s.Gotype = reflectdata.TypeSym(nam.Type()).Linksym()
|
s.Gotype = reflectdata.TypeLinksym(nam.Type())
|
||||||
flags := 0
|
flags := 0
|
||||||
if nam.Name().Readonly() {
|
if nam.Readonly() {
|
||||||
flags = obj.RODATA
|
flags = obj.RODATA
|
||||||
}
|
}
|
||||||
if nam.Type() != nil && !nam.Type().HasPointers() {
|
if nam.Type() != nil && !nam.Type().HasPointers() {
|
||||||
flags |= obj.NOPTR
|
flags |= obj.NOPTR
|
||||||
}
|
}
|
||||||
base.Ctxt.Globl(s, nam.Type().Width, flags)
|
base.Ctxt.Globl(s, nam.Type().Width, flags)
|
||||||
if nam.Name().LibfuzzerExtraCounter() {
|
if nam.LibfuzzerExtraCounter() {
|
||||||
s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
|
s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
|
||||||
}
|
}
|
||||||
if nam.Sym().Linkname != "" {
|
if nam.Sym().Linkname != "" {
|
||||||
|
@ -199,8 +199,8 @@ func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) {
|
|||||||
if n == nil {
|
if n == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if n.Op() != ir.ONAME || n.Class_ != ir.PFUNC {
|
if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
|
||||||
base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op(), n.Class_)
|
base.Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op(), n.Class)
|
||||||
}
|
}
|
||||||
fn := n.Func
|
fn := n.Func
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
@ -227,7 +227,7 @@ func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) {
|
|||||||
|
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PFUNC:
|
case ir.PFUNC:
|
||||||
Inline_Flood(n, exportsym)
|
Inline_Flood(n, exportsym)
|
||||||
exportsym(n)
|
exportsym(n)
|
||||||
@ -265,7 +265,7 @@ var errBudget = errors.New("too expensive")
|
|||||||
func (v *hairyVisitor) tooHairy(fn *ir.Func) bool {
|
func (v *hairyVisitor) tooHairy(fn *ir.Func) bool {
|
||||||
v.do = v.doNode // cache closure
|
v.do = v.doNode // cache closure
|
||||||
|
|
||||||
err := ir.DoChildren(fn, v.do)
|
err := errChildren(fn, v.do)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
v.reason = err.Error()
|
v.reason = err.Error()
|
||||||
return true
|
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.
|
// runtime.throw is a "cheap call" like panic in normal code.
|
||||||
if n.X.Op() == ir.ONAME {
|
if n.X.Op() == ir.ONAME {
|
||||||
name := n.X.(*ir.Name)
|
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
|
fn := name.Sym().Name
|
||||||
if fn == "getcallerpc" || fn == "getcallersp" {
|
if fn == "getcallerpc" || fn == "getcallersp" {
|
||||||
return errors.New("call to " + fn)
|
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) {
|
if ir.IsConst(n.Cond, constant.Bool) {
|
||||||
// This if and the condition cost nothing.
|
// This if and the condition cost nothing.
|
||||||
// TODO(rsc): It seems strange that we visit the dead branch.
|
// 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
|
return err
|
||||||
}
|
}
|
||||||
if err := ir.DoList(n.Body, v.do); err != nil {
|
if err := errList(n.Body, v.do); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ir.DoList(n.Else, v.do); err != nil {
|
if err := errList(n.Else, v.do); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -407,7 +407,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
|
|||||||
|
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
if n.Class_ == ir.PAUTO {
|
if n.Class == ir.PAUTO {
|
||||||
v.usedLocals[n] = true
|
v.usedLocals[n] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,6 +419,9 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
|
|||||||
|
|
||||||
case ir.OCALLPART, ir.OSLICELIT:
|
case ir.OCALLPART, ir.OSLICELIT:
|
||||||
v.budget-- // Hack for toolstash -cmp.
|
v.budget-- // Hack for toolstash -cmp.
|
||||||
|
|
||||||
|
case ir.OMETHEXPR:
|
||||||
|
v.budget++ // Hack for toolstash -cmp.
|
||||||
}
|
}
|
||||||
|
|
||||||
v.budget--
|
v.budget--
|
||||||
@ -428,7 +431,7 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
|
|||||||
return errBudget
|
return errBudget
|
||||||
}
|
}
|
||||||
|
|
||||||
return ir.DoChildren(n, v.do)
|
return errChildren(n, v.do)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isBigFunc(fn *ir.Func) bool {
|
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 {
|
if as := n; as.Op() == ir.OAS2FUNC {
|
||||||
as := as.(*ir.AssignListStmt)
|
as := as.(*ir.AssignListStmt)
|
||||||
if as.Rhs[0].Op() == ir.OINLCALL {
|
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.SetOp(ir.OAS2)
|
||||||
as.SetTypecheck(0)
|
as.SetTypecheck(0)
|
||||||
n = typecheck.Stmt(as)
|
n = typecheck.Stmt(as)
|
||||||
@ -613,18 +616,18 @@ func inlCallee(fn ir.Node) *ir.Func {
|
|||||||
fn = ir.StaticValue(fn)
|
fn = ir.StaticValue(fn)
|
||||||
switch fn.Op() {
|
switch fn.Op() {
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
fn := fn.(*ir.MethodExpr)
|
fn := fn.(*ir.SelectorExpr)
|
||||||
n := ir.MethodExprName(fn)
|
n := ir.MethodExprName(fn)
|
||||||
// Check that receiver type matches fn.Left.
|
// Check that receiver type matches fn.X.
|
||||||
// TODO(mdempsky): Handle implicit dereference
|
// TODO(mdempsky): Handle implicit dereference
|
||||||
// of pointer receiver argument?
|
// 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 nil
|
||||||
}
|
}
|
||||||
return n.Func
|
return n.Func
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
fn := fn.(*ir.Name)
|
fn := fn.(*ir.Name)
|
||||||
if fn.Class_ == ir.PFUNC {
|
if fn.Class == ir.PFUNC {
|
||||||
return fn.Func
|
return fn.Func
|
||||||
}
|
}
|
||||||
case ir.OCLOSURE:
|
case ir.OCLOSURE:
|
||||||
@ -636,13 +639,15 @@ func inlCallee(fn ir.Node) *ir.Func {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func inlParam(t *types.Field, as ir.Node, inlvars map[*ir.Name]ir.Node) ir.Node {
|
func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
|
||||||
n := ir.AsNode(t.Nname)
|
if t.Nname == nil {
|
||||||
if n == nil || ir.IsBlank(n) {
|
|
||||||
return ir.BlankNode
|
return ir.BlankNode
|
||||||
}
|
}
|
||||||
|
n := t.Nname.(*ir.Name)
|
||||||
inlvar := inlvars[n.(*ir.Name)]
|
if ir.IsBlank(n) {
|
||||||
|
return ir.BlankNode
|
||||||
|
}
|
||||||
|
inlvar := inlvars[n]
|
||||||
if inlvar == nil {
|
if inlvar == nil {
|
||||||
base.Fatalf("missing inlvar for %v", n)
|
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
|
callee := n.X
|
||||||
for callee.Op() == ir.OCONVNOP {
|
for callee.Op() == ir.OCONVNOP {
|
||||||
conv := callee.(*ir.ConvExpr)
|
conv := callee.(*ir.ConvExpr)
|
||||||
ninit.Append(conv.PtrInit().Take()...)
|
ninit.Append(ir.TakeInit(conv)...)
|
||||||
callee = conv.X
|
callee = conv.X
|
||||||
}
|
}
|
||||||
if callee.Op() != ir.ONAME && callee.Op() != ir.OCLOSURE && callee.Op() != ir.OMETHEXPR {
|
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.
|
// 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
|
// record formals/locals for later post-processing
|
||||||
var inlfvars []ir.Node
|
var inlfvars []*ir.Name
|
||||||
|
|
||||||
// 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ln := range fn.Inl.Dcl {
|
for _, ln := range fn.Inl.Dcl {
|
||||||
if ln.Op() != ir.ONAME {
|
if ln.Op() != ir.ONAME {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ln.Class_ == ir.PPARAMOUT { // return values handled below.
|
if ln.Class == ir.PPARAMOUT { // return values handled below.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ir.IsParamStackCopy(ln) { // ignore the on-stack copy of a parameter that moved to the heap
|
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.
|
// nothing should have moved to the heap yet.
|
||||||
base.Fatalf("impossible: %v", ln)
|
base.Fatalf("impossible: %v", ln)
|
||||||
}
|
}
|
||||||
inlf := typecheck.Expr(inlvar(ln))
|
inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
|
||||||
inlvars[ln] = inlf
|
inlvars[ln] = inlf
|
||||||
if base.Flag.GenDwarfInl > 0 {
|
if base.Flag.GenDwarfInl > 0 {
|
||||||
if ln.Class_ == ir.PPARAM {
|
if ln.Class == ir.PPARAM {
|
||||||
inlf.Name().SetInlFormal(true)
|
inlf.Name().SetInlFormal(true)
|
||||||
} else {
|
} else {
|
||||||
inlf.Name().SetInlLocal(true)
|
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.
|
// temporaries for return values.
|
||||||
var retvars []ir.Node
|
var retvars []ir.Node
|
||||||
for i, t := range fn.Type().Results().Fields().Slice() {
|
for i, t := range fn.Type().Results().Fields().Slice() {
|
||||||
var m ir.Node
|
var m *ir.Name
|
||||||
if n := ir.AsNode(t.Nname); n != nil && !ir.IsBlank(n) && !strings.HasPrefix(n.Sym().Name, "~r") {
|
if nn := t.Nname; nn != nil && !ir.IsBlank(nn.(*ir.Name)) && !strings.HasPrefix(nn.Sym().Name, "~r") {
|
||||||
n := n.(*ir.Name)
|
n := nn.(*ir.Name)
|
||||||
m = inlvar(n)
|
m = inlvar(n)
|
||||||
m = typecheck.Expr(m)
|
m = typecheck.Expr(m).(*ir.Name)
|
||||||
inlvars[n] = m
|
inlvars[n] = m
|
||||||
delayretvars = false // found a named result parameter
|
delayretvars = false // found a named result parameter
|
||||||
} else {
|
} 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 = typecheck.NodNil()
|
||||||
vas.Y.SetType(param.Type)
|
vas.Y.SetType(param.Type)
|
||||||
} else {
|
} else {
|
||||||
lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type).(ir.Ntype), nil)
|
lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type), nil)
|
||||||
lit.List.Set(varargs)
|
lit.List = varargs
|
||||||
vas.Y = lit
|
vas.Y = lit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -914,7 +883,7 @@ func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]b
|
|||||||
if !delayretvars {
|
if !delayretvars {
|
||||||
// Zero the return parameters.
|
// Zero the return parameters.
|
||||||
for _, n := range retvars {
|
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)
|
ras := ir.NewAssignStmt(base.Pos, n, nil)
|
||||||
ninit.Append(typecheck.Stmt(ras))
|
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()
|
parent = b.InliningIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
sym := fn.Sym().Linksym()
|
sym := fn.Linksym()
|
||||||
newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
|
newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
|
||||||
|
|
||||||
// Add an inline mark just before the inlined body.
|
// 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);
|
//dumplist("ninit post", ninit);
|
||||||
|
|
||||||
call := ir.NewInlinedCallExpr(base.Pos, nil, nil)
|
call := ir.NewInlinedCallExpr(base.Pos, nil, nil)
|
||||||
call.PtrInit().Set(ninit)
|
*call.PtrInit() = ninit
|
||||||
call.Body.Set(body)
|
call.Body = body
|
||||||
call.ReturnVars.Set(retvars)
|
call.ReturnVars = retvars
|
||||||
call.SetType(n.Type())
|
call.SetType(n.Type())
|
||||||
call.SetTypecheck(1)
|
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,
|
// 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
|
// PAUTO's in the calling functions, and link them off of the
|
||||||
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
|
// 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 {
|
if base.Flag.LowerM > 3 {
|
||||||
fmt.Printf("inlvar %+v\n", var_)
|
fmt.Printf("inlvar %+v\n", var_)
|
||||||
}
|
}
|
||||||
|
|
||||||
n := typecheck.NewName(var_.Sym())
|
n := typecheck.NewName(var_.Sym())
|
||||||
n.SetType(var_.Type())
|
n.SetType(var_.Type())
|
||||||
n.Class_ = ir.PAUTO
|
n.Class = ir.PAUTO
|
||||||
n.SetUsed(true)
|
n.SetUsed(true)
|
||||||
n.Curfn = ir.CurFunc // the calling function, not the called one
|
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)
|
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synthesize a variable to store the inlined function's results in.
|
// 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 := typecheck.NewName(typecheck.LookupNum("~R", i))
|
||||||
n.SetType(t.Type)
|
n.SetType(t.Type)
|
||||||
n.Class_ = ir.PAUTO
|
n.Class = ir.PAUTO
|
||||||
n.SetUsed(true)
|
n.SetUsed(true)
|
||||||
n.Curfn = ir.CurFunc // the calling function, not the called one
|
n.Curfn = ir.CurFunc // the calling function, not the called one
|
||||||
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
|
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 {
|
func argvar(t *types.Type, i int) ir.Node {
|
||||||
n := typecheck.NewName(typecheck.LookupNum("~arg", i))
|
n := typecheck.NewName(typecheck.LookupNum("~arg", i))
|
||||||
n.SetType(t.Elem())
|
n.SetType(t.Elem())
|
||||||
n.Class_ = ir.PAUTO
|
n.Class = ir.PAUTO
|
||||||
n.SetUsed(true)
|
n.SetUsed(true)
|
||||||
n.Curfn = ir.CurFunc // the calling function, not the called one
|
n.Curfn = ir.CurFunc // the calling function, not the called one
|
||||||
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
|
ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
|
||||||
@ -1051,7 +1020,7 @@ type inlsubst struct {
|
|||||||
// "return" statement.
|
// "return" statement.
|
||||||
delayretvars bool
|
delayretvars bool
|
||||||
|
|
||||||
inlvars map[*ir.Name]ir.Node
|
inlvars map[*ir.Name]*ir.Name
|
||||||
|
|
||||||
// bases maps from original PosBase to PosBase with an extra
|
// bases maps from original PosBase to PosBase with an extra
|
||||||
// inlined call frame.
|
// inlined call frame.
|
||||||
@ -1085,6 +1054,25 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
|
|||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
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 inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
|
||||||
if base.Flag.LowerM > 2 {
|
if base.Flag.LowerM > 2 {
|
||||||
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
|
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
|
||||||
@ -1098,7 +1086,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
|
|||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
n := n.(*ir.MethodExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OLITERAL, ir.ONIL, ir.OTYPE:
|
case ir.OLITERAL, ir.ONIL, ir.OTYPE:
|
||||||
@ -1108,15 +1096,6 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
|
|||||||
if n.Sym() != nil {
|
if n.Sym() != nil {
|
||||||
return n
|
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:
|
case ir.ORETURN:
|
||||||
// Since we don't handle bodies with closures,
|
// 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 {
|
for _, n := range subst.retvars {
|
||||||
as.Lhs.Append(n)
|
as.Lhs.Append(n)
|
||||||
}
|
}
|
||||||
as.Rhs.Set(subst.list(n.Results))
|
as.Rhs = subst.list(n.Results)
|
||||||
|
|
||||||
if subst.delayretvars {
|
if subst.delayretvars {
|
||||||
for _, n := range as.Lhs {
|
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
|
n.Name().Defn = as
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1151,7 +1130,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
|
|||||||
n := n.(*ir.BranchStmt)
|
n := n.(*ir.BranchStmt)
|
||||||
m := ir.Copy(n).(*ir.BranchStmt)
|
m := ir.Copy(n).(*ir.BranchStmt)
|
||||||
m.SetPos(subst.updatedPos(m.Pos()))
|
m.SetPos(subst.updatedPos(m.Pos()))
|
||||||
m.PtrInit().Set(nil)
|
*m.PtrInit() = nil
|
||||||
p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
|
p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
|
||||||
m.Label = typecheck.Lookup(p)
|
m.Label = typecheck.Lookup(p)
|
||||||
return m
|
return m
|
||||||
@ -1160,7 +1139,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node {
|
|||||||
n := n.(*ir.LabelStmt)
|
n := n.(*ir.LabelStmt)
|
||||||
m := ir.Copy(n).(*ir.LabelStmt)
|
m := ir.Copy(n).(*ir.LabelStmt)
|
||||||
m.SetPos(subst.updatedPos(m.Pos()))
|
m.SetPos(subst.updatedPos(m.Pos()))
|
||||||
m.PtrInit().Set(nil)
|
*m.PtrInit() = nil
|
||||||
p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
|
p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
|
||||||
m.Label = typecheck.Lookup(p)
|
m.Label = typecheck.Lookup(p)
|
||||||
return m
|
return m
|
||||||
@ -1191,7 +1170,7 @@ func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
|
|||||||
func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
|
func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
|
||||||
s := make([]*ir.Name, 0, len(ll))
|
s := make([]*ir.Name, 0, len(ll))
|
||||||
for _, n := range ll {
|
for _, n := range ll {
|
||||||
if n.Class_ == ir.PAUTO {
|
if n.Class == ir.PAUTO {
|
||||||
if _, found := vis.usedLocals[n]; !found {
|
if _, found := vis.usedLocals[n]; !found {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -1211,3 +1190,22 @@ func numNonClosures(list []*ir.Func) int {
|
|||||||
}
|
}
|
||||||
return count
|
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
|
||||||
|
}
|
||||||
|
@ -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
|
package ir
|
||||||
|
|
||||||
|
@ -25,6 +25,14 @@ type OrigNode interface {
|
|||||||
SetOrig(Node)
|
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.
|
// Orig returns the “original” node for n.
|
||||||
// If n implements OrigNode, Orig returns n.Orig().
|
// If n implements OrigNode, Orig returns n.Orig().
|
||||||
// Otherwise Orig returns n itself.
|
// Otherwise Orig returns n itself.
|
||||||
|
@ -14,27 +14,6 @@ import (
|
|||||||
"go/token"
|
"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.
|
// An Expr is a Node that can appear as an expression.
|
||||||
type Expr interface {
|
type Expr interface {
|
||||||
Node
|
Node
|
||||||
@ -48,8 +27,7 @@ type Expr interface {
|
|||||||
type miniExpr struct {
|
type miniExpr struct {
|
||||||
miniNode
|
miniNode
|
||||||
typ *types.Type
|
typ *types.Type
|
||||||
init Nodes // TODO(rsc): Don't require every Node to have an init
|
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?
|
|
||||||
flags bitset8
|
flags bitset8
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,14 +37,13 @@ const (
|
|||||||
miniExprTransient
|
miniExprTransient
|
||||||
miniExprBounded
|
miniExprBounded
|
||||||
miniExprImplicit // for use by implementations; not supported by every Expr
|
miniExprImplicit // for use by implementations; not supported by every Expr
|
||||||
|
miniExprCheckPtr
|
||||||
)
|
)
|
||||||
|
|
||||||
func (*miniExpr) isExpr() {}
|
func (*miniExpr) isExpr() {}
|
||||||
|
|
||||||
func (n *miniExpr) Type() *types.Type { return n.typ }
|
func (n *miniExpr) Type() *types.Type { return n.typ }
|
||||||
func (n *miniExpr) SetType(x *types.Type) { n.typ = x }
|
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) HasCall() bool { return n.flags&miniExprHasCall != 0 }
|
||||||
func (n *miniExpr) SetHasCall(b bool) { n.flags.set(miniExprHasCall, b) }
|
func (n *miniExpr) SetHasCall(b bool) { n.flags.set(miniExprHasCall, b) }
|
||||||
func (n *miniExpr) NonNil() bool { return n.flags&miniExprNonNil != 0 }
|
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) PtrInit() *Nodes { return &n.init }
|
||||||
func (n *miniExpr) SetInit(x Nodes) { n.init = x }
|
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].
|
// An AddStringExpr is a string concatenation Expr[0] + Exprs[1] + ... + Expr[len(Expr)-1].
|
||||||
type AddStringExpr struct {
|
type AddStringExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
@ -100,7 +67,7 @@ func NewAddStringExpr(pos src.XPos, list []Node) *AddStringExpr {
|
|||||||
n := &AddStringExpr{}
|
n := &AddStringExpr{}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.op = OADDSTR
|
n.op = OADDSTR
|
||||||
n.List.Set(list)
|
n.List = list
|
||||||
return n
|
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.
|
// It may end up being a normal address-of or an allocation of a composite literal.
|
||||||
type AddrExpr struct {
|
type AddrExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
X Node
|
X Node
|
||||||
Alloc Node // preallocated storage if any
|
Prealloc *Name // preallocated storage if any
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAddrExpr(pos src.XPos, x Node) *AddrExpr {
|
func NewAddrExpr(pos src.XPos, x Node) *AddrExpr {
|
||||||
@ -191,14 +158,14 @@ const (
|
|||||||
// A CallExpr is a function call X(Args).
|
// A CallExpr is a function call X(Args).
|
||||||
type CallExpr struct {
|
type CallExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
orig Node
|
origNode
|
||||||
X Node
|
X Node
|
||||||
Args Nodes
|
Args Nodes
|
||||||
Rargs Nodes // TODO(rsc): Delete.
|
Rargs Nodes // TODO(rsc): Delete.
|
||||||
Body Nodes // TODO(rsc): Delete.
|
KeepAlive []*Name // vars to be kept alive until call returns
|
||||||
IsDDD bool
|
IsDDD bool
|
||||||
Use CallUse
|
Use CallUse
|
||||||
NoInline bool
|
NoInline bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCallExpr(pos src.XPos, op Op, fun Node, args []Node) *CallExpr {
|
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.pos = pos
|
||||||
n.orig = n
|
n.orig = n
|
||||||
n.SetOp(op)
|
n.SetOp(op)
|
||||||
n.Args.Set(args)
|
n.Args = args
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*CallExpr) isStmt() {}
|
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) {
|
func (n *CallExpr) SetOp(op Op) {
|
||||||
switch op {
|
switch op {
|
||||||
default:
|
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.
|
// A ClosureExpr is a function literal expression.
|
||||||
type ClosureExpr struct {
|
type ClosureExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
Func *Func
|
Func *Func `mknode:"-"`
|
||||||
Prealloc *Name
|
Prealloc *Name
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,7 +220,7 @@ func NewClosureRead(typ *types.Type, offset int64) *ClosureReadExpr {
|
|||||||
// Before type-checking, the type is Ntype.
|
// Before type-checking, the type is Ntype.
|
||||||
type CompLitExpr struct {
|
type CompLitExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
orig Node
|
origNode
|
||||||
Ntype Ntype
|
Ntype Ntype
|
||||||
List Nodes // initialized values
|
List Nodes // initialized values
|
||||||
Prealloc *Name
|
Prealloc *Name
|
||||||
@ -287,13 +231,11 @@ func NewCompLitExpr(pos src.XPos, op Op, typ Ntype, list []Node) *CompLitExpr {
|
|||||||
n := &CompLitExpr{Ntype: typ}
|
n := &CompLitExpr{Ntype: typ}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.SetOp(op)
|
n.SetOp(op)
|
||||||
n.List.Set(list)
|
n.List = list
|
||||||
n.orig = n
|
n.orig = n
|
||||||
return 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) Implicit() bool { return n.flags&miniExprImplicit != 0 }
|
||||||
func (n *CompLitExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
|
func (n *CompLitExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
|
||||||
|
|
||||||
@ -308,14 +250,15 @@ func (n *CompLitExpr) SetOp(op Op) {
|
|||||||
|
|
||||||
type ConstExpr struct {
|
type ConstExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
val constant.Value
|
origNode
|
||||||
orig Node
|
val constant.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConstExpr(val constant.Value, orig Node) Node {
|
func NewConstExpr(val constant.Value, orig Node) Node {
|
||||||
n := &ConstExpr{orig: orig, val: val}
|
n := &ConstExpr{val: val}
|
||||||
n.op = OLITERAL
|
n.op = OLITERAL
|
||||||
n.pos = orig.Pos()
|
n.pos = orig.Pos()
|
||||||
|
n.orig = orig
|
||||||
n.SetType(orig.Type())
|
n.SetType(orig.Type())
|
||||||
n.SetTypecheck(orig.Typecheck())
|
n.SetTypecheck(orig.Typecheck())
|
||||||
n.SetDiag(orig.Diag())
|
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) 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 }
|
func (n *ConstExpr) Val() constant.Value { return n.val }
|
||||||
|
|
||||||
// A ConvExpr is a conversion Type(X).
|
// 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) Implicit() bool { return n.flags&miniExprImplicit != 0 }
|
||||||
func (n *ConvExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
|
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) {
|
func (n *ConvExpr) SetOp(op Op) {
|
||||||
switch op {
|
switch op {
|
||||||
@ -421,8 +364,8 @@ func NewInlinedCallExpr(pos src.XPos, body, retvars []Node) *InlinedCallExpr {
|
|||||||
n := &InlinedCallExpr{}
|
n := &InlinedCallExpr{}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.op = OINLCALL
|
n.op = OINLCALL
|
||||||
n.Body.Set(body)
|
n.Body = body
|
||||||
n.ReturnVars.Set(retvars)
|
n.ReturnVars = retvars
|
||||||
return n
|
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.
|
// A NilExpr represents the predefined untyped constant nil.
|
||||||
// (It may be copied and assigned a type, though.)
|
// (It may be copied and assigned a type, though.)
|
||||||
type NilExpr struct {
|
type NilExpr struct {
|
||||||
@ -567,12 +492,13 @@ func NewNameOffsetExpr(pos src.XPos, name *Name, offset int64, typ *types.Type)
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// A SelectorExpr is a selector expression X.Sym.
|
// A SelectorExpr is a selector expression X.Sel.
|
||||||
type SelectorExpr struct {
|
type SelectorExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
X Node
|
X Node
|
||||||
Sel *types.Sym
|
Sel *types.Sym
|
||||||
Selection *types.Field
|
Selection *types.Field
|
||||||
|
Prealloc *Name // preallocated storage for OCALLPART, if any
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr {
|
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 {
|
switch op {
|
||||||
default:
|
default:
|
||||||
panic(n.no("SetOp " + op.String()))
|
panic(n.no("SetOp " + op.String()))
|
||||||
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
|
case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OCALLPART, OMETHEXPR:
|
||||||
n.op = op
|
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) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
|
||||||
func (n *SelectorExpr) Offset() int64 { return n.Selection.Offset }
|
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.
|
// Before type-checking, bytes.Buffer is a SelectorExpr.
|
||||||
// After type-checking it becomes a Name.
|
// After type-checking it becomes a Name.
|
||||||
func (*SelectorExpr) CanBeNtype() {}
|
func (*SelectorExpr) CanBeNtype() {}
|
||||||
@ -687,8 +623,13 @@ func (n *StarExpr) SetOTYPE(t *types.Type) {
|
|||||||
type TypeAssertExpr struct {
|
type TypeAssertExpr struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
X Node
|
X Node
|
||||||
Ntype Node // TODO: Should be Ntype, but reused as address of type structure
|
Ntype Ntype
|
||||||
Itab Nodes // Itab[0] is itab
|
|
||||||
|
// 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 {
|
func NewTypeAssertExpr(pos src.XPos, x Node, typ Ntype) *TypeAssertExpr {
|
||||||
@ -795,7 +736,7 @@ func IsAddressable(n Node) bool {
|
|||||||
|
|
||||||
case ONAME:
|
case ONAME:
|
||||||
n := n.(*Name)
|
n := n.(*Name)
|
||||||
if n.Class_ == PFUNC {
|
if n.Class == PFUNC {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -830,11 +771,11 @@ func staticValue1(nn Node) Node {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
n := nn.(*Name)
|
n := nn.(*Name)
|
||||||
if n.Class_ != PAUTO || n.Name().Addrtaken() {
|
if n.Class != PAUTO {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defn := n.Name().Defn
|
defn := n.Defn
|
||||||
if defn == nil {
|
if defn == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -882,23 +823,46 @@ func reassigned(name *Name) bool {
|
|||||||
if name.Curfn == nil {
|
if name.Curfn == nil {
|
||||||
return true
|
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() {
|
switch n.Op() {
|
||||||
case OAS:
|
case OAS:
|
||||||
n := n.(*AssignStmt)
|
n := n.(*AssignStmt)
|
||||||
if n.X == name && n != name.Defn {
|
if isName(n.X) && n != name.Defn {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV, OSELRECV2:
|
case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV, OSELRECV2:
|
||||||
n := n.(*AssignListStmt)
|
n := n.(*AssignListStmt)
|
||||||
for _, p := range n.Lhs {
|
for _, p := range n.Lhs {
|
||||||
if p == name && n != name.Defn {
|
if isName(p) && n != name.Defn {
|
||||||
return true
|
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 false
|
||||||
})
|
}
|
||||||
|
return Any(name.Curfn, do)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsIntrinsicCall reports whether the compiler back end will treat the call as an intrinsic operation.
|
// 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.
|
// MethodFunc is like MethodName, but returns the types.Field instead.
|
||||||
func MethodExprFunc(n Node) *types.Field {
|
func MethodExprFunc(n Node) *types.Field {
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ODOTMETH:
|
case ODOTMETH, OMETHEXPR, OCALLPART:
|
||||||
return n.(*SelectorExpr).Selection
|
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())
|
base.Fatalf("unexpected node: %v (%v)", n, n.Op())
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
|
@ -128,7 +128,7 @@ func (o Op) Format(s fmt.State, verb rune) {
|
|||||||
// %L Go syntax followed by " (type T)" if type is known.
|
// %L Go syntax followed by " (type T)" if type is known.
|
||||||
// %+v Debug syntax, as in Dump.
|
// %+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.
|
// %+v prints Dump.
|
||||||
// Otherwise we print Go syntax.
|
// Otherwise we print Go syntax.
|
||||||
if s.Flag('+') && verb == 'v' {
|
if s.Flag('+') && verb == 'v' {
|
||||||
@ -216,6 +216,7 @@ var OpPrec = []int{
|
|||||||
OTINTER: 8,
|
OTINTER: 8,
|
||||||
OTMAP: 8,
|
OTMAP: 8,
|
||||||
OTSTRUCT: 8,
|
OTSTRUCT: 8,
|
||||||
|
OTYPE: 8,
|
||||||
OINDEXMAP: 8,
|
OINDEXMAP: 8,
|
||||||
OINDEX: 8,
|
OINDEX: 8,
|
||||||
OSLICE: 8,
|
OSLICE: 8,
|
||||||
@ -232,6 +233,7 @@ var OpPrec = []int{
|
|||||||
ODOT: 8,
|
ODOT: 8,
|
||||||
OXDOT: 8,
|
OXDOT: 8,
|
||||||
OCALLPART: 8,
|
OCALLPART: 8,
|
||||||
|
OMETHEXPR: 8,
|
||||||
OPLUS: 7,
|
OPLUS: 7,
|
||||||
ONOT: 7,
|
ONOT: 7,
|
||||||
OBITNOT: 7,
|
OBITNOT: 7,
|
||||||
@ -551,8 +553,8 @@ func exprFmt(n Node, s fmt.State, prec int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nprec := OpPrec[n.Op()]
|
nprec := OpPrec[n.Op()]
|
||||||
if n.Op() == OTYPE && n.Sym() != nil {
|
if n.Op() == OTYPE && n.Type().IsPtr() {
|
||||||
nprec = 8
|
nprec = OpPrec[ODEREF]
|
||||||
}
|
}
|
||||||
|
|
||||||
if prec > nprec {
|
if prec > nprec {
|
||||||
@ -630,10 +632,6 @@ func exprFmt(n Node, s fmt.State, prec int) {
|
|||||||
case OPACK, ONONAME:
|
case OPACK, ONONAME:
|
||||||
fmt.Fprint(s, n.Sym())
|
fmt.Fprint(s, n.Sym())
|
||||||
|
|
||||||
case OMETHEXPR:
|
|
||||||
n := n.(*MethodExpr)
|
|
||||||
fmt.Fprint(s, n.FuncName().Sym())
|
|
||||||
|
|
||||||
case ONAMEOFFSET:
|
case ONAMEOFFSET:
|
||||||
n := n.(*NameOffsetExpr)
|
n := n.(*NameOffsetExpr)
|
||||||
fmt.Fprintf(s, "(%v)(%v@%d)", n.Type(), n.Name_, n.Offset_)
|
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)
|
n := n.(*StructKeyExpr)
|
||||||
fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
|
fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
|
||||||
|
|
||||||
case OCALLPART:
|
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OCALLPART, OMETHEXPR:
|
||||||
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:
|
|
||||||
n := n.(*SelectorExpr)
|
n := n.(*SelectorExpr)
|
||||||
exprFmt(n.X, s, nprec)
|
exprFmt(n.X, s, nprec)
|
||||||
if n.Sel == nil {
|
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.
|
// Dump prints the message s followed by a debug dump of n.
|
||||||
func Dump(s string, n Node) {
|
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.
|
// 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
|
return
|
||||||
|
|
||||||
case OMETHEXPR:
|
|
||||||
n := n.(*MethodExpr)
|
|
||||||
fmt.Fprintf(w, "%+v-%+v", n.Op(), n.FuncName().Sym())
|
|
||||||
dumpNodeHeader(w, n)
|
|
||||||
return
|
|
||||||
|
|
||||||
case OASOP:
|
case OASOP:
|
||||||
n := n.(*AssignOpStmt)
|
n := n.(*AssignOpStmt)
|
||||||
fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
|
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)
|
fmt.Fprintf(w, "%+v-%s", n.Op(), name)
|
||||||
}
|
}
|
||||||
dumpNodes(w, val, depth+1)
|
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) {
|
func dumpNodes(w io.Writer, list Nodes, depth int) {
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
fmt.Fprintf(w, " <nil>")
|
fmt.Fprintf(w, " <nil>")
|
||||||
|
@ -49,7 +49,6 @@ import (
|
|||||||
// pointer from the Func back to the OCALLPART.
|
// pointer from the Func back to the OCALLPART.
|
||||||
type Func struct {
|
type Func struct {
|
||||||
miniNode
|
miniNode
|
||||||
typ *types.Type
|
|
||||||
Body Nodes
|
Body Nodes
|
||||||
Iota int64
|
Iota int64
|
||||||
|
|
||||||
@ -66,9 +65,15 @@ type Func struct {
|
|||||||
// include closurevars until transformclosure runs.
|
// include closurevars until transformclosure runs.
|
||||||
Dcl []*Name
|
Dcl []*Name
|
||||||
|
|
||||||
ClosureEnter Nodes // list of ONAME nodes (or OADDR-of-ONAME nodes, for output parameters) of captured variables
|
ClosureType Ntype // closure representation type
|
||||||
ClosureType Node // closure representation type
|
|
||||||
ClosureVars []*Name // closure params; each has closurevar set
|
// 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
|
// Parents records the parent scope of each scope within a
|
||||||
// function. The root scope (0) has no parent, so the i'th
|
// 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 records scope boundary changes.
|
||||||
Marks []Mark
|
Marks []Mark
|
||||||
|
|
||||||
FieldTrack map[*types.Sym]struct{}
|
FieldTrack map[*obj.LSym]struct{}
|
||||||
DebugInfo interface{}
|
DebugInfo interface{}
|
||||||
LSym *obj.LSym
|
LSym *obj.LSym
|
||||||
|
|
||||||
@ -116,15 +121,13 @@ func NewFunc(pos src.XPos) *Func {
|
|||||||
|
|
||||||
func (f *Func) isStmt() {}
|
func (f *Func) isStmt() {}
|
||||||
|
|
||||||
func (f *Func) Type() *types.Type { return f.typ }
|
func (n *Func) copy() Node { panic(n.no("copy")) }
|
||||||
func (f *Func) SetType(x *types.Type) { f.typ = x }
|
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 {
|
func (f *Func) Type() *types.Type { return f.Nname.Type() }
|
||||||
if f.Nname != nil {
|
func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
|
||||||
return f.Nname.Sym()
|
func (f *Func) Linksym() *obj.LSym { return f.Nname.Linksym() }
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Inline holds fields used for function bodies that can be inlined.
|
// An Inline holds fields used for function bodies that can be inlined.
|
||||||
type Inline struct {
|
type Inline struct {
|
||||||
@ -240,24 +243,13 @@ func FuncSymName(s *types.Sym) string {
|
|||||||
return s.Name + "·f"
|
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.
|
// MarkFunc marks a node as a function.
|
||||||
func MarkFunc(n *Name) {
|
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)
|
base.Fatalf("expected ONAME/Pxxx node, got %v", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Class_ = PFUNC
|
n.Class = PFUNC
|
||||||
n.Sym().SetFunc(true)
|
n.Sym().SetFunc(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,20 +54,13 @@ func (n *miniNode) Esc() uint16 { return n.esc }
|
|||||||
func (n *miniNode) SetEsc(x uint16) { n.esc = x }
|
func (n *miniNode) SetEsc(x uint16) { n.esc = x }
|
||||||
|
|
||||||
const (
|
const (
|
||||||
miniWalkdefShift = 0
|
miniWalkdefShift = 0 // TODO(mdempsky): Move to Name.flags.
|
||||||
miniTypecheckShift = 2
|
miniTypecheckShift = 2
|
||||||
miniDiag = 1 << 4
|
miniDiag = 1 << 4
|
||||||
miniHasCall = 1 << 5 // for miniStmt
|
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) 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) {
|
func (n *miniNode) SetTypecheck(x uint8) {
|
||||||
if x > 3 {
|
if x > 3 {
|
||||||
panic(fmt.Sprintf("cannot SetTypecheck %d", x))
|
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.
|
// Empty, immutable graph structure.
|
||||||
|
|
||||||
func (n *miniNode) Init() Nodes { return Nodes{} }
|
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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Additional functionality unavailable.
|
// 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) SetHasCall(bool) { panic(n.no("SetHasCall")) }
|
||||||
func (n *miniNode) NonNil() bool { return false }
|
func (n *miniNode) NonNil() bool { return false }
|
||||||
func (n *miniNode) MarkNonNil() { panic(n.no("MarkNonNil")) }
|
func (n *miniNode) MarkNonNil() { panic(n.no("MarkNonNil")) }
|
||||||
func (n *miniNode) Opt() interface{} { return nil }
|
|
||||||
func (n *miniNode) SetOpt(interface{}) { panic(n.no("SetOpt")) }
|
|
||||||
|
@ -13,11 +13,16 @@ import (
|
|||||||
"go/types"
|
"go/types"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/tools/go/packages"
|
"golang.org/x/tools/go/packages"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var irPkg *types.Package
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfg := &packages.Config{
|
cfg := &packages.Config{
|
||||||
Mode: packages.NeedSyntax | packages.NeedTypes,
|
Mode: packages.NeedSyntax | packages.NeedTypes,
|
||||||
@ -26,116 +31,59 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
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, "// Code generated by mknode.go. DO NOT EDIT.")
|
||||||
fmt.Fprintln(&buf)
|
fmt.Fprintln(&buf)
|
||||||
fmt.Fprintln(&buf, "package ir")
|
fmt.Fprintln(&buf, "package ir")
|
||||||
fmt.Fprintln(&buf)
|
fmt.Fprintln(&buf)
|
||||||
fmt.Fprintln(&buf, `import "fmt"`)
|
fmt.Fprintln(&buf, `import "fmt"`)
|
||||||
|
|
||||||
|
scope := irPkg.Scope()
|
||||||
for _, name := range scope.Names() {
|
for _, name := range scope.Names() {
|
||||||
|
if strings.HasPrefix(name, "mini") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
obj, ok := scope.Lookup(name).(*types.TypeName)
|
obj, ok := scope.Lookup(name).(*types.TypeName)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
typ := obj.Type().(*types.Named)
|
||||||
typName := obj.Name()
|
if !implementsNode(types.NewPointer(typ)) {
|
||||||
typ, ok := obj.Type().(*types.Named).Underlying().(*types.Struct)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(typName, "mini") || !hasMiniNode(typ) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(&buf, "\n")
|
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 {
|
switch name {
|
||||||
case "Name":
|
case "Name", "Func":
|
||||||
fmt.Fprintf(&buf, "func (n *%s) copy() Node {panic(\"%s.copy\")}\n", name, name)
|
// Too specialized to automate.
|
||||||
default:
|
continue
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(&buf, "func (n *%s) doChildren(do func(Node) error) error { var err error\n", name)
|
forNodeFields(typ,
|
||||||
forNodeFields(typName, typ, func(name string, is func(types.Type) bool) {
|
"func (n *%[1]s) copy() Node { c := *n\n",
|
||||||
switch {
|
"",
|
||||||
case is(ptrIdentType):
|
"c.%[1]s = copy%[2]s(c.%[1]s)",
|
||||||
fmt.Fprintf(&buf, "if n.%s != nil { err = maybeDo(n.%s, err, do) }\n", name, name)
|
"return &c }\n")
|
||||||
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(typ,
|
||||||
forNodeFields(typName, typ, func(name string, is func(types.Type) bool) {
|
"func (n *%[1]s) doChildren(do func(Node) bool) bool {\n",
|
||||||
switch {
|
"if n.%[1]s != nil && do(n.%[1]s) { return true }",
|
||||||
case is(ptrIdentType):
|
"if do%[2]s(n.%[1]s, do) { return true }",
|
||||||
fmt.Fprintf(&buf, "if n.%s != nil { n.%s = edit(n.%s).(*Ident) }\n", name, name, name)
|
"return false }\n")
|
||||||
case is(nodeType):
|
|
||||||
fmt.Fprintf(&buf, "n.%s = maybeEdit(n.%s, edit)\n", name, name)
|
forNodeFields(typ,
|
||||||
case is(ntypeType):
|
"func (n *%[1]s) editChildren(edit func(Node) Node) {\n",
|
||||||
fmt.Fprintf(&buf, "n.%s = toNtype(maybeEdit(n.%s, edit))\n", name, name)
|
"if n.%[1]s != nil { n.%[1]s = edit(n.%[1]s).(%[2]s) }",
|
||||||
case is(nodesType):
|
"edit%[2]s(n.%[1]s, edit)",
|
||||||
fmt.Fprintf(&buf, "editList(n.%s, edit)\n", name)
|
"}\n")
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
makeHelpers()
|
||||||
|
|
||||||
out, err := format.Source(buf.Bytes())
|
out, err := format.Source(buf.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// write out mangled source so we can see the bug.
|
// 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)) {
|
// needHelper maps needed slice helpers from their base name to their
|
||||||
for i, n := 0, typ.NumFields(); i < n; i++ {
|
// respective slice-element type.
|
||||||
v := typ.Field(i)
|
var needHelper = map[string]string{}
|
||||||
if v.Embedded() {
|
|
||||||
if typ, ok := v.Type().Underlying().(*types.Struct); ok {
|
func makeHelpers() {
|
||||||
forNodeFields(typName, typ, f)
|
var names []string
|
||||||
continue
|
for name := range needHelper {
|
||||||
}
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
switch typName {
|
sort.Strings(names)
|
||||||
case "Func":
|
|
||||||
if strings.ToLower(strings.TrimSuffix(v.Name(), "_")) != "body" {
|
for _, name := range names {
|
||||||
continue
|
fmt.Fprintf(&buf, sliceHelperTmpl, name, needHelper[name])
|
||||||
}
|
|
||||||
case "Name":
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch v.Name() {
|
|
||||||
case "orig":
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
f(v.Name(), func(t types.Type) bool { return types.Identical(t, v.Type()) })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasMiniNode(typ *types.Struct) bool {
|
const sliceHelperTmpl = `
|
||||||
for i, n := 0, typ.NumFields(); i < n; i++ {
|
func copy%[1]s(list []%[2]s) []%[2]s {
|
||||||
v := typ.Field(i)
|
if list == nil {
|
||||||
if v.Name() == "miniNode" {
|
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
|
return true
|
||||||
}
|
}
|
||||||
if v.Embedded() {
|
}
|
||||||
if typ, ok := v.Type().Underlying().(*types.Struct); ok && hasMiniNode(typ) {
|
return false
|
||||||
return true
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
} else if what == "*Field" {
|
||||||
|
// Special case for *Field.
|
||||||
|
tmpl = sliceTmpl
|
||||||
|
if slice != nil {
|
||||||
|
what = "Fields"
|
||||||
|
} else {
|
||||||
|
what = "Field"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func anyField(typ *types.Struct, pred func(f *types.Var) bool) bool {
|
||||||
|
for i, n := 0, typ.NumFields(); i < n; i++ {
|
||||||
|
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 f.Embedded() {
|
||||||
|
if typ, ok := f.Type().Underlying().(*types.Struct); ok {
|
||||||
|
if anyField(typ, pred) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,10 @@ package ir
|
|||||||
import (
|
import (
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
|
"cmd/internal/obj"
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"go/constant"
|
"go/constant"
|
||||||
)
|
)
|
||||||
@ -34,16 +36,16 @@ func (*Ident) CanBeNtype() {}
|
|||||||
// Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL).
|
// Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL).
|
||||||
type Name struct {
|
type Name struct {
|
||||||
miniExpr
|
miniExpr
|
||||||
BuiltinOp Op // uint8
|
BuiltinOp Op // uint8
|
||||||
Class_ Class // uint8
|
Class Class // uint8
|
||||||
flags bitset16
|
|
||||||
pragma PragmaFlag // int16
|
pragma PragmaFlag // int16
|
||||||
|
flags bitset16
|
||||||
sym *types.Sym
|
sym *types.Sym
|
||||||
Func *Func
|
Func *Func
|
||||||
Offset_ int64
|
Offset_ int64
|
||||||
val constant.Value
|
val constant.Value
|
||||||
orig Node
|
Opt interface{} // for use by escape analysis
|
||||||
Embed *[]Embed // list of embedded files, for ONAME var
|
Embed *[]Embed // list of embedded files, for ONAME var
|
||||||
|
|
||||||
PkgName *PkgName // real package for import . names
|
PkgName *PkgName // real package for import . names
|
||||||
// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
|
// 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() {}
|
func (n *Name) isExpr() {}
|
||||||
|
|
||||||
// CloneName makes a cloned copy of the name.
|
func (n *Name) copy() Node { panic(n.no("copy")) }
|
||||||
// It's not ir.Copy(n) because in general that operation is a mistake on names,
|
func (n *Name) doChildren(do func(Node) bool) bool { return false }
|
||||||
// which uniquely identify variables.
|
func (n *Name) editChildren(edit func(Node) Node) {}
|
||||||
// Callers must use n.CloneName to make clear they intend to create a separate name.
|
|
||||||
func (n *Name) CloneName() *Name { c := *n; return &c }
|
|
||||||
|
|
||||||
// TypeDefn returns the type definition for a named OTYPE.
|
// TypeDefn returns the type definition for a named OTYPE.
|
||||||
// That is, given "type T Defn", it returns Defn.
|
// 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 := new(Name)
|
||||||
n.op = op
|
n.op = op
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.orig = n
|
|
||||||
n.sym = sym
|
n.sym = sym
|
||||||
return n
|
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) SetSym(x *types.Sym) { n.sym = x }
|
||||||
func (n *Name) SubOp() Op { return n.BuiltinOp }
|
func (n *Name) SubOp() Op { return n.BuiltinOp }
|
||||||
func (n *Name) SetSubOp(x Op) { n.BuiltinOp = x }
|
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) SetFunc(x *Func) { n.Func = x }
|
||||||
func (n *Name) Offset() int64 { panic("Name.Offset") }
|
func (n *Name) Offset() int64 { panic("Name.Offset") }
|
||||||
func (n *Name) SetOffset(x int64) {
|
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) SetFrameOffset(x int64) { n.Offset_ = x }
|
||||||
func (n *Name) Iota() int64 { return n.Offset_ }
|
func (n *Name) Iota() int64 { return n.Offset_ }
|
||||||
func (n *Name) SetIota(x int64) { n.Offset_ = x }
|
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) CanBeNtype() {}
|
||||||
func (*Name) CanBeAnSSASym() {}
|
func (*Name) CanBeAnSSASym() {}
|
||||||
@ -273,7 +279,6 @@ const (
|
|||||||
|
|
||||||
func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 }
|
func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 }
|
||||||
func (n *Name) Readonly() bool { return n.flags&nameReadonly != 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) Needzero() bool { return n.flags&nameNeedzero != 0 }
|
||||||
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
|
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
|
||||||
func (n *Name) Used() bool { return n.flags&nameUsed != 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) SetCaptured(b bool) { n.flags.set(nameCaptured, b) }
|
||||||
func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, 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) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
|
||||||
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
|
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
|
||||||
func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
|
func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
|
||||||
@ -306,11 +310,11 @@ func (n *Name) MarkReadonly() {
|
|||||||
if n.Op() != ONAME {
|
if n.Op() != ONAME {
|
||||||
base.Fatalf("Node.MarkReadonly %v", n.Op())
|
base.Fatalf("Node.MarkReadonly %v", n.Op())
|
||||||
}
|
}
|
||||||
n.Name().setReadonly(true)
|
n.setReadonly(true)
|
||||||
// Mark the linksym as readonly immediately
|
// Mark the linksym as readonly immediately
|
||||||
// so that the SSA backend can use this information.
|
// so that the SSA backend can use this information.
|
||||||
// It will be overridden later during dumpglobls.
|
// 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.
|
// Val returns the constant.Value for the node.
|
||||||
@ -321,8 +325,7 @@ func (n *Name) Val() constant.Value {
|
|||||||
return n.val
|
return n.val
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetVal sets the constant.Value for the node,
|
// SetVal sets the constant.Value for the node.
|
||||||
// which must not have been used with SetOpt.
|
|
||||||
func (n *Name) SetVal(v constant.Value) {
|
func (n *Name) SetVal(v constant.Value) {
|
||||||
if n.op != OLITERAL {
|
if n.op != OLITERAL {
|
||||||
panic(n.no("SetVal"))
|
panic(n.no("SetVal"))
|
||||||
@ -331,6 +334,33 @@ func (n *Name) SetVal(v constant.Value) {
|
|||||||
n.val = v
|
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
|
// SameSource reports whether two nodes refer to the same source
|
||||||
// element.
|
// element.
|
||||||
//
|
//
|
||||||
@ -373,7 +403,7 @@ func DeclaredBy(x, stmt Node) bool {
|
|||||||
// called declaration contexts.
|
// called declaration contexts.
|
||||||
type Class uint8
|
type Class uint8
|
||||||
|
|
||||||
//go:generate stringer -type=Class
|
//go:generate stringer -type=Class name.go
|
||||||
const (
|
const (
|
||||||
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
|
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
|
||||||
PEXTERN // global variables
|
PEXTERN // global variables
|
||||||
@ -418,7 +448,7 @@ func IsParamStackCopy(n Node) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
name := n.(*Name)
|
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
|
// IsParamHeapCopy reports whether this is the on-heap copy of
|
||||||
@ -428,7 +458,7 @@ func IsParamHeapCopy(n Node) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
name := n.(*Name)
|
name := n.(*Name)
|
||||||
return name.Class_ == PAUTOHEAP && name.Name().Stackcopy != nil
|
return name.Class == PAUTOHEAP && name.Stackcopy != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegFP *Name
|
var RegFP *Name
|
||||||
|
@ -28,14 +28,12 @@ type Node interface {
|
|||||||
// For making copies. For Copy and SepCopy.
|
// For making copies. For Copy and SepCopy.
|
||||||
copy() Node
|
copy() Node
|
||||||
|
|
||||||
doChildren(func(Node) error) error
|
doChildren(func(Node) bool) bool
|
||||||
editChildren(func(Node) Node)
|
editChildren(func(Node) Node)
|
||||||
|
|
||||||
// Abstract graph structure, for generic traversals.
|
// Abstract graph structure, for generic traversals.
|
||||||
Op() Op
|
Op() Op
|
||||||
Init() Nodes
|
Init() Nodes
|
||||||
PtrInit() *Nodes
|
|
||||||
SetInit(x Nodes)
|
|
||||||
|
|
||||||
// Fields specific to certain Ops only.
|
// Fields specific to certain Ops only.
|
||||||
Type() *types.Type
|
Type() *types.Type
|
||||||
@ -48,10 +46,6 @@ type Node interface {
|
|||||||
// Storage for analysis passes.
|
// Storage for analysis passes.
|
||||||
Esc() uint16
|
Esc() uint16
|
||||||
SetEsc(x uint16)
|
SetEsc(x uint16)
|
||||||
Walkdef() uint8
|
|
||||||
SetWalkdef(x uint8)
|
|
||||||
Opt() interface{}
|
|
||||||
SetOpt(x interface{})
|
|
||||||
Diag() bool
|
Diag() bool
|
||||||
SetDiag(x bool)
|
SetDiag(x bool)
|
||||||
Typecheck() uint8
|
Typecheck() uint8
|
||||||
@ -92,7 +86,21 @@ func MayBeShared(n Node) bool {
|
|||||||
return false
|
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
|
type Op uint8
|
||||||
|
|
||||||
@ -220,10 +228,10 @@ const (
|
|||||||
OPAREN // (Left)
|
OPAREN // (Left)
|
||||||
OSEND // Left <- Right
|
OSEND // Left <- Right
|
||||||
OSLICE // Left[List[0] : List[1]] (Left is untypechecked or slice)
|
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)
|
OSLICESTR // Left[List[0] : List[1]] (Left is string)
|
||||||
OSLICE3 // Left[List[0] : List[1] : List[2]] (Left is untypedchecked or slice)
|
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)
|
OSLICEHEADER // sliceheader{Left, List[0], List[1]} (Left is unsafe.Pointer, List[0] is length, List[1] is capacity)
|
||||||
ORECOVER // recover()
|
ORECOVER // recover()
|
||||||
ORECV // <-Left
|
ORECV // <-Left
|
||||||
@ -313,35 +321,11 @@ const (
|
|||||||
// a slice to save space.
|
// a slice to save space.
|
||||||
type Nodes []Node
|
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.
|
// Append appends entries to Nodes.
|
||||||
func (n *Nodes) Append(a ...Node) {
|
func (n *Nodes) Append(a ...Node) {
|
||||||
if len(a) == 0 {
|
if len(a) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n.mutate()
|
|
||||||
*n = append(*n, a...)
|
*n = append(*n, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +335,6 @@ func (n *Nodes) Prepend(a ...Node) {
|
|||||||
if len(a) == 0 {
|
if len(a) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n.mutate()
|
|
||||||
*n = append(a, *n...)
|
*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.
|
// The result of InitExpr MUST be assigned back to n, e.g.
|
||||||
// n.Left = InitExpr(init, n.Left)
|
// n.Left = InitExpr(init, n.Left)
|
||||||
func InitExpr(init []Node, n Node) Node {
|
func InitExpr(init []Node, expr Node) Node {
|
||||||
if len(init) == 0 {
|
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.
|
// Introduce OCONVNOP to hold init list.
|
||||||
old := n
|
n = NewConvExpr(base.Pos, OCONVNOP, nil, expr)
|
||||||
n = NewConvExpr(base.Pos, OCONVNOP, nil, old)
|
n.SetType(expr.Type())
|
||||||
n.SetType(old.Type())
|
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,7 +568,10 @@ func OuterValue(n Node) Node {
|
|||||||
continue
|
continue
|
||||||
case OINDEX:
|
case OINDEX:
|
||||||
nn := nn.(*IndexExpr)
|
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
|
n = nn.X
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
package ir
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ func (v *bottomUpVisitor) visit(n *Func) uint32 {
|
|||||||
Visit(n, func(n Node) {
|
Visit(n, func(n Node) {
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
if n := n.(*Name); n.Class_ == PFUNC {
|
if n := n.(*Name); n.Class == PFUNC {
|
||||||
do(n.Defn)
|
do(n.Defn)
|
||||||
}
|
}
|
||||||
case ODOTMETH, OCALLPART, OMETHEXPR:
|
case ODOTMETH, OCALLPART, OMETHEXPR:
|
||||||
|
@ -20,8 +20,8 @@ func TestSizeof(t *testing.T) {
|
|||||||
_32bit uintptr // size on 32bit platforms
|
_32bit uintptr // size on 32bit platforms
|
||||||
_64bit uintptr // size on 64bit platforms
|
_64bit uintptr // size on 64bit platforms
|
||||||
}{
|
}{
|
||||||
{Func{}, 200, 352},
|
{Func{}, 184, 320},
|
||||||
{Name{}, 132, 232},
|
{Name{}, 124, 216},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -13,10 +13,10 @@ import (
|
|||||||
// A Decl is a declaration of a const, type, or var. (A declared func is a Func.)
|
// A Decl is a declaration of a const, type, or var. (A declared func is a Func.)
|
||||||
type Decl struct {
|
type Decl struct {
|
||||||
miniNode
|
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 := &Decl{X: x}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
switch op {
|
switch op {
|
||||||
@ -70,8 +70,8 @@ func NewAssignListStmt(pos src.XPos, op Op, lhs, rhs []Node) *AssignListStmt {
|
|||||||
n := &AssignListStmt{}
|
n := &AssignListStmt{}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.SetOp(op)
|
n.SetOp(op)
|
||||||
n.Lhs.Set(lhs)
|
n.Lhs = lhs
|
||||||
n.Rhs.Set(rhs)
|
n.Rhs = rhs
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +112,6 @@ func (n *AssignStmt) SetOp(op Op) {
|
|||||||
// An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y.
|
// An AssignOpStmt is an AsOp= assignment statement: X AsOp= Y.
|
||||||
type AssignOpStmt struct {
|
type AssignOpStmt struct {
|
||||||
miniStmt
|
miniStmt
|
||||||
typ *types.Type
|
|
||||||
X Node
|
X Node
|
||||||
AsOp Op // OADD etc
|
AsOp Op // OADD etc
|
||||||
Y Node
|
Y Node
|
||||||
@ -126,9 +125,6 @@ func NewAssignOpStmt(pos src.XPos, asOp Op, x, y Node) *AssignOpStmt {
|
|||||||
return n
|
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 }.
|
// A BlockStmt is a block: { List }.
|
||||||
type BlockStmt struct {
|
type BlockStmt struct {
|
||||||
miniStmt
|
miniStmt
|
||||||
@ -145,7 +141,7 @@ func NewBlockStmt(pos src.XPos, list []Node) *BlockStmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.op = OBLOCK
|
n.op = OBLOCK
|
||||||
n.List.Set(list)
|
n.List = list
|
||||||
return n
|
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.
|
// A CaseClause is a case statement in a switch or select: case List: Body.
|
||||||
type CaseClause struct {
|
type CaseClause struct {
|
||||||
miniStmt
|
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
|
List Nodes // list of expressions for switch, early select
|
||||||
Body Nodes
|
Body Nodes
|
||||||
}
|
}
|
||||||
@ -188,36 +184,6 @@ func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause {
|
|||||||
return n
|
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 {
|
type CommClause struct {
|
||||||
miniStmt
|
miniStmt
|
||||||
Comm Node // communication case
|
Comm Node // communication case
|
||||||
@ -231,36 +197,6 @@ func NewCommStmt(pos src.XPos, comm Node, body []Node) *CommClause {
|
|||||||
return n
|
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 }
|
// A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
|
||||||
// Op can be OFOR or OFORUNTIL (!Cond).
|
// Op can be OFOR or OFORUNTIL (!Cond).
|
||||||
type ForStmt struct {
|
type ForStmt struct {
|
||||||
@ -280,7 +216,7 @@ func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node) *ForStmt
|
|||||||
if init != nil {
|
if init != nil {
|
||||||
n.init = []Node{init}
|
n.init = []Node{init}
|
||||||
}
|
}
|
||||||
n.Body.Set(body)
|
n.Body = body
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,8 +262,8 @@ func NewIfStmt(pos src.XPos, cond Node, body, els []Node) *IfStmt {
|
|||||||
n := &IfStmt{Cond: cond}
|
n := &IfStmt{Cond: cond}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.op = OIF
|
n.op = OIF
|
||||||
n.Body.Set(body)
|
n.Body = body
|
||||||
n.Else.Set(els)
|
n.Else = els
|
||||||
return n
|
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 := &RangeStmt{X: x, Key: key, Value: value}
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.op = ORANGE
|
n.op = ORANGE
|
||||||
n.Body.Set(body)
|
n.Body = body
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// A ReturnStmt is a return statement.
|
// A ReturnStmt is a return statement.
|
||||||
type ReturnStmt struct {
|
type ReturnStmt struct {
|
||||||
miniStmt
|
miniStmt
|
||||||
orig Node // for typecheckargs rewrite
|
origNode // for typecheckargs rewrite
|
||||||
Results Nodes // return list
|
Results Nodes // return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
|
func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
|
||||||
@ -395,13 +331,10 @@ func NewReturnStmt(pos src.XPos, results []Node) *ReturnStmt {
|
|||||||
n.pos = pos
|
n.pos = pos
|
||||||
n.op = ORETURN
|
n.op = ORETURN
|
||||||
n.orig = n
|
n.orig = n
|
||||||
n.Results.Set(results)
|
n.Results = results
|
||||||
return n
|
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 }.
|
// A SelectStmt is a block: { Cases }.
|
||||||
type SelectStmt struct {
|
type SelectStmt struct {
|
||||||
miniStmt
|
miniStmt
|
||||||
|
@ -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.
|
// setOTYPE also records t.Nod = self if t.Nod is not already set.
|
||||||
// (Some types are shared by multiple OTYPE nodes, so only
|
// (Some types are shared by multiple OTYPE nodes, so only
|
||||||
// the first such node is used as t.Nod.)
|
// 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 {
|
if n.typ != nil {
|
||||||
panic(n.op.String() + " SetType: type already set")
|
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.
|
// A ChanType represents a chan Elem syntax with the direction Dir.
|
||||||
type ChanType struct {
|
type ChanType struct {
|
||||||
miniType
|
miniType
|
||||||
Elem Node
|
Elem Ntype
|
||||||
Dir types.ChanDir
|
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 := &ChanType{Elem: elem, Dir: dir}
|
||||||
n.op = OTCHAN
|
n.op = OTCHAN
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
@ -80,11 +80,11 @@ func (n *ChanType) SetOTYPE(t *types.Type) {
|
|||||||
// A MapType represents a map[Key]Value type syntax.
|
// A MapType represents a map[Key]Value type syntax.
|
||||||
type MapType struct {
|
type MapType struct {
|
||||||
miniType
|
miniType
|
||||||
Key Node
|
Key Ntype
|
||||||
Elem Node
|
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 := &MapType{Key: key, Elem: elem}
|
||||||
n.op = OTMAP
|
n.op = OTMAP
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
@ -185,45 +185,28 @@ func (f *Field) String() string {
|
|||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) copy() *Field {
|
// TODO(mdempsky): Make Field a Node again so these can be generated?
|
||||||
|
// Fields are Nodes in go/ast and cmd/compile/internal/syntax.
|
||||||
|
|
||||||
|
func copyField(f *Field) *Field {
|
||||||
|
if f == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
c := *f
|
c := *f
|
||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
|
func doField(f *Field, do func(Node) bool) bool {
|
||||||
func copyFields(list []*Field) []*Field {
|
if f == nil {
|
||||||
out := make([]*Field, len(list))
|
return false
|
||||||
copy(out, list)
|
|
||||||
for i, f := range out {
|
|
||||||
out[i] = f.copy()
|
|
||||||
}
|
}
|
||||||
return out
|
if f.Decl != nil && do(f.Decl) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if f.Ntype != nil && do(f.Ntype) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func maybeDoFields(list []*Field, err error, do func(Node) error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, f := range list {
|
|
||||||
err = maybeDoField(f, err, do)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func editField(f *Field, edit func(Node) Node) {
|
func editField(f *Field, edit func(Node) Node) {
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return
|
return
|
||||||
@ -232,10 +215,25 @@ func editField(f *Field, edit func(Node) Node) {
|
|||||||
f.Decl = edit(f.Decl).(*Name)
|
f.Decl = edit(f.Decl).(*Name)
|
||||||
}
|
}
|
||||||
if f.Ntype != nil {
|
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) {
|
func editFields(list []*Field, edit func(Node) Node) {
|
||||||
for _, f := range list {
|
for _, f := range list {
|
||||||
editField(f, edit)
|
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.
|
// If DDD is true, it's the ...Elem at the end of a function list.
|
||||||
type SliceType struct {
|
type SliceType struct {
|
||||||
miniType
|
miniType
|
||||||
Elem Node
|
Elem Ntype
|
||||||
DDD bool
|
DDD bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSliceType(pos src.XPos, elem Node) *SliceType {
|
func NewSliceType(pos src.XPos, elem Ntype) *SliceType {
|
||||||
n := &SliceType{Elem: elem}
|
n := &SliceType{Elem: elem}
|
||||||
n.op = OTSLICE
|
n.op = OTSLICE
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
@ -267,11 +265,11 @@ func (n *SliceType) SetOTYPE(t *types.Type) {
|
|||||||
type ArrayType struct {
|
type ArrayType struct {
|
||||||
miniType
|
miniType
|
||||||
Len Node
|
Len Node
|
||||||
Elem Node
|
Elem Ntype
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArrayType(pos src.XPos, size Node, elem Node) *ArrayType {
|
func NewArrayType(pos src.XPos, len Node, elem Ntype) *ArrayType {
|
||||||
n := &ArrayType{Len: size, Elem: elem}
|
n := &ArrayType{Len: len, Elem: elem}
|
||||||
n.op = OTARRAY
|
n.op = OTARRAY
|
||||||
n.pos = pos
|
n.pos = pos
|
||||||
return n
|
return n
|
||||||
|
@ -4,23 +4,18 @@
|
|||||||
|
|
||||||
// IR visitors for walking the IR tree.
|
// IR visitors for walking the IR tree.
|
||||||
//
|
//
|
||||||
// The lowest level helpers are DoChildren and EditChildren,
|
// The lowest level helpers are DoChildren and EditChildren, which
|
||||||
// which nodes help implement (TODO(rsc): eventually) and
|
// nodes help implement and provide control over whether and when
|
||||||
// provide control over whether and when recursion happens
|
// recursion happens during the walk of the IR.
|
||||||
// during the walk of the IR.
|
|
||||||
//
|
//
|
||||||
// Although these are both useful directly, two simpler patterns
|
// 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
|
package ir
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DoChildren calls do(x) on each of n's non-nil child nodes x.
|
// 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.
|
// If any call returns true, DoChildren stops and returns true.
|
||||||
// Otherwise, DoChildren returns nil.
|
// Otherwise, DoChildren returns false.
|
||||||
//
|
//
|
||||||
// Note that DoChildren(n, do) only calls do(x) for n's immediate children.
|
// 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).
|
// 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
|
// DoChildren allows constructing general traversals of the IR graph
|
||||||
// that can stop early if needed. The most general usage is:
|
// that can stop early if needed. The most general usage is:
|
||||||
//
|
//
|
||||||
// var do func(ir.Node) error
|
// var do func(ir.Node) bool
|
||||||
// do = func(x ir.Node) error {
|
// do = func(x ir.Node) bool {
|
||||||
// ... processing BEFORE visting children ...
|
// ... processing BEFORE visting children ...
|
||||||
// if ... should visit children ... {
|
// if ... should visit children ... {
|
||||||
// ir.DoChildren(x, do)
|
// ir.DoChildren(x, do)
|
||||||
// ... processing AFTER visting children ...
|
// ... processing AFTER visting children ...
|
||||||
// }
|
// }
|
||||||
// if ... should stop parent DoChildren call from visiting siblings ... {
|
// if ... should stop parent DoChildren call from visiting siblings ... {
|
||||||
// return non-nil error
|
// return true
|
||||||
// }
|
// }
|
||||||
// return nil
|
// return false
|
||||||
// }
|
// }
|
||||||
// do(root)
|
// do(root)
|
||||||
//
|
//
|
||||||
// Since DoChildren does not generate any errors itself, if the do function
|
// Since DoChildren does not return true itself, if the do function
|
||||||
// never wants to stop the traversal, it can assume that DoChildren itself
|
// never wants to stop the traversal, it can assume that DoChildren
|
||||||
// will always return nil, simplifying to:
|
// itself will always return false, simplifying to:
|
||||||
//
|
//
|
||||||
// var do func(ir.Node) error
|
// var do func(ir.Node) bool
|
||||||
// do = func(x ir.Node) error {
|
// do = func(x ir.Node) bool {
|
||||||
// ... processing BEFORE visting children ...
|
// ... processing BEFORE visting children ...
|
||||||
// if ... should visit children ... {
|
// if ... should visit children ... {
|
||||||
// ir.DoChildren(x, do)
|
// ir.DoChildren(x, do)
|
||||||
// }
|
// }
|
||||||
// ... processing AFTER visting children ...
|
// ... processing AFTER visting children ...
|
||||||
// return nil
|
// return false
|
||||||
// }
|
// }
|
||||||
// do(root)
|
// do(root)
|
||||||
//
|
//
|
||||||
@ -61,14 +56,15 @@ import (
|
|||||||
// only processing before visiting children and never stopping:
|
// only processing before visiting children and never stopping:
|
||||||
//
|
//
|
||||||
// func Visit(n ir.Node, visit func(ir.Node)) {
|
// func Visit(n ir.Node, visit func(ir.Node)) {
|
||||||
// var do func(ir.Node) error
|
// if n == nil {
|
||||||
// do = func(x ir.Node) error {
|
// return
|
||||||
|
// }
|
||||||
|
// var do func(ir.Node) bool
|
||||||
|
// do = func(x ir.Node) bool {
|
||||||
// visit(x)
|
// visit(x)
|
||||||
// return ir.DoChildren(x, do)
|
// return ir.DoChildren(x, do)
|
||||||
// }
|
// }
|
||||||
// if n != nil {
|
// do(n)
|
||||||
// visit(n)
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The Any function illustrates a different simplification of the pattern,
|
// 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
|
// a node x for which cond(x) returns true, at which point the entire
|
||||||
// traversal stops and returns true.
|
// traversal stops and returns true.
|
||||||
//
|
//
|
||||||
// func Any(n ir.Node, find cond(ir.Node)) bool {
|
// func Any(n ir.Node, cond(ir.Node) bool) bool {
|
||||||
// stop := errors.New("stop")
|
// if n == nil {
|
||||||
// var do func(ir.Node) error
|
// return false
|
||||||
// do = func(x ir.Node) error {
|
|
||||||
// if cond(x) {
|
|
||||||
// return stop
|
|
||||||
// }
|
|
||||||
// return ir.DoChildren(x, do)
|
|
||||||
// }
|
// }
|
||||||
// return do(n) == stop
|
// var do func(ir.Node) bool
|
||||||
|
// do = func(x ir.Node) bool {
|
||||||
|
// return cond(x) || ir.DoChildren(x, do)
|
||||||
|
// }
|
||||||
|
// return do(n)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Visit and Any are presented above as examples of how to use
|
// Visit and Any are presented above as examples of how to use
|
||||||
// DoChildren effectively, but of course, usage that fits within the
|
// DoChildren effectively, but of course, usage that fits within the
|
||||||
// simplifications captured by Visit or Any will be best served
|
// simplifications captured by Visit or Any will be best served
|
||||||
// by directly calling the ones provided by this package.
|
// 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 {
|
if n == nil {
|
||||||
return nil
|
return false
|
||||||
}
|
}
|
||||||
return n.doChildren(do)
|
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
|
// 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.
|
// in a depth-first preorder traversal, calling visit on each node visited.
|
||||||
func Visit(n Node, visit func(Node)) {
|
func Visit(n Node, visit func(Node)) {
|
||||||
var do func(Node) error
|
if n == nil {
|
||||||
do = func(x Node) error {
|
return
|
||||||
|
}
|
||||||
|
var do func(Node) bool
|
||||||
|
do = func(x Node) bool {
|
||||||
visit(x)
|
visit(x)
|
||||||
return DoChildren(x, do)
|
return DoChildren(x, do)
|
||||||
}
|
}
|
||||||
if n != nil {
|
do(n)
|
||||||
do(n)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisitList calls Visit(x, visit) for each node x in the list.
|
// 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
|
// Any looks for a non-nil node x in the IR tree rooted at n
|
||||||
// for which cond(x) returns true.
|
// for which cond(x) returns true.
|
||||||
// Any considers nodes in a depth-first, preorder traversal.
|
// 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 {
|
if n == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
var do func(Node) error
|
var do func(Node) bool
|
||||||
do = func(x Node) error {
|
do = func(x Node) bool {
|
||||||
if cond(x) {
|
return cond(x) || DoChildren(x, do)
|
||||||
return stop
|
|
||||||
}
|
|
||||||
return DoChildren(x, do)
|
|
||||||
}
|
}
|
||||||
return do(n) == stop
|
return do(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnyList calls Any(x, cond) for each node x in the list, in order.
|
// 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)
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -181,7 +181,7 @@ type progeffectscache struct {
|
|||||||
// nor do we care about empty structs (handled by the pointer check),
|
// nor do we care about empty structs (handled by the pointer check),
|
||||||
// nor do we care about the fake PAUTOHEAP variables.
|
// nor do we care about the fake PAUTOHEAP variables.
|
||||||
func ShouldTrack(n *ir.Name) bool {
|
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
|
// 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
|
lv.cache.initialized = true
|
||||||
|
|
||||||
for i, node := range lv.vars {
|
for i, node := range lv.vars {
|
||||||
switch node.Class_ {
|
switch node.Class {
|
||||||
case ir.PPARAM:
|
case ir.PPARAM:
|
||||||
// A return instruction with a p.to is a tail return, which brings
|
// 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
|
// 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).
|
// variable" ICEs (issue 19632).
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
|
case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
|
||||||
if !n.Name().Used() {
|
if !n.Used() {
|
||||||
return -1, 0
|
return -1, 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,7 +386,7 @@ func (lv *liveness) pointerMap(liveout bitvec.BitVec, vars []*ir.Name, args, loc
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
node := vars[i]
|
node := vars[i]
|
||||||
switch node.Class_ {
|
switch node.Class {
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
typebits.Set(node.Type(), node.FrameOffset()+lv.stkptrsize, locals)
|
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?
|
// don't need to keep the stack copy live?
|
||||||
if lv.fn.HasDefer() {
|
if lv.fn.HasDefer() {
|
||||||
for i, n := range lv.vars {
|
for i, n := range lv.vars {
|
||||||
if n.Class_ == ir.PPARAMOUT {
|
if n.Class == ir.PPARAMOUT {
|
||||||
if n.Name().IsOutputParamHeapAddr() {
|
if n.IsOutputParamHeapAddr() {
|
||||||
// Just to be paranoid. Heap addresses are PAUTOs.
|
// Just to be paranoid. Heap addresses are PAUTOs.
|
||||||
base.Fatalf("variable %v both output param and heap output param", n)
|
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
|
// If this variable moved to the heap, then
|
||||||
// its stack copy is not live.
|
// its stack copy is not live.
|
||||||
continue
|
continue
|
||||||
@ -700,21 +700,21 @@ func (lv *liveness) epilogue() {
|
|||||||
// Note: zeroing is handled by zeroResults in walk.go.
|
// Note: zeroing is handled by zeroResults in walk.go.
|
||||||
livedefer.Set(int32(i))
|
livedefer.Set(int32(i))
|
||||||
}
|
}
|
||||||
if n.Name().IsOutputParamHeapAddr() {
|
if n.IsOutputParamHeapAddr() {
|
||||||
// This variable will be overwritten early in the function
|
// This variable will be overwritten early in the function
|
||||||
// prologue (from the result of a mallocgc) but we need to
|
// prologue (from the result of a mallocgc) but we need to
|
||||||
// zero it in case that malloc causes a stack scan.
|
// zero it in case that malloc causes a stack scan.
|
||||||
n.Name().SetNeedzero(true)
|
n.SetNeedzero(true)
|
||||||
livedefer.Set(int32(i))
|
livedefer.Set(int32(i))
|
||||||
}
|
}
|
||||||
if n.Name().OpenDeferSlot() {
|
if n.OpenDeferSlot() {
|
||||||
// Open-coded defer args slots must be live
|
// Open-coded defer args slots must be live
|
||||||
// everywhere in a function, since a panic can
|
// everywhere in a function, since a panic can
|
||||||
// occur (almost) anywhere. Because it is live
|
// occur (almost) anywhere. Because it is live
|
||||||
// everywhere, it must be zeroed on entry.
|
// everywhere, it must be zeroed on entry.
|
||||||
livedefer.Set(int32(i))
|
livedefer.Set(int32(i))
|
||||||
// It was already marked as Needzero when created.
|
// 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")
|
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)) {
|
if !liveout.Get(int32(i)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.Class_ == ir.PPARAM {
|
if n.Class == ir.PPARAM {
|
||||||
continue // ok
|
continue // ok
|
||||||
}
|
}
|
||||||
base.Fatalf("bad live variable at entry of %v: %L", lv.fn.Nname, n)
|
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
|
// the only things that can possibly be live are the
|
||||||
// input parameters.
|
// input parameters.
|
||||||
for j, n := range lv.vars {
|
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)
|
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.)
|
// (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
|
||||||
var maxArgNode *ir.Name
|
var maxArgNode *ir.Name
|
||||||
for _, n := range lv.vars {
|
for _, n := range lv.vars {
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PPARAM, ir.PPARAMOUT:
|
case ir.PPARAM, ir.PPARAMOUT:
|
||||||
if maxArgNode == nil || n.FrameOffset() > maxArgNode.FrameOffset() {
|
if maxArgNode == nil || n.FrameOffset() > maxArgNode.FrameOffset() {
|
||||||
maxArgNode = n
|
maxArgNode = n
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:generate go run mkbuiltin.go
|
|
||||||
|
|
||||||
package noder
|
package noder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -28,6 +28,26 @@ import (
|
|||||||
"cmd/internal/src"
|
"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.
|
// ParseFiles concurrently parses files into *syntax.File structures.
|
||||||
// Each declaration in every *syntax.File is converted to a syntax tree
|
// Each declaration in every *syntax.File is converted to a syntax tree
|
||||||
// and its root represented by *Node is appended to Target.Decls.
|
// and its root represented by *Node is appended to Target.Decls.
|
||||||
@ -170,6 +190,69 @@ func ParseFiles(filenames []string) (lines uint) {
|
|||||||
return
|
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.
|
// Temporary import helper to get type2-based type-checking going.
|
||||||
type gcimports struct {
|
type gcimports struct {
|
||||||
packages map[string]*types2.Package
|
packages map[string]*types2.Package
|
||||||
@ -301,7 +384,7 @@ func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
|
|||||||
if body == nil {
|
if body == nil {
|
||||||
body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)}
|
body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)}
|
||||||
}
|
}
|
||||||
fn.Body.Set(body)
|
fn.Body = body
|
||||||
|
|
||||||
base.Pos = p.makeXPos(block.Rbrace)
|
base.Pos = p.makeXPos(block.Rbrace)
|
||||||
fn.Endlineno = base.Pos
|
fn.Endlineno = base.Pos
|
||||||
@ -530,8 +613,48 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node {
|
|||||||
p.checkUnused(pragma)
|
p.checkUnused(pragma)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var init []ir.Node
|
||||||
p.setlineno(decl)
|
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
|
// 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
|
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.Defn = f
|
||||||
f.Nname.Ntype = t
|
f.Nname.Ntype = t
|
||||||
|
|
||||||
@ -787,7 +911,7 @@ func (p *noder) expr(expr syntax.Expr) ir.Node {
|
|||||||
for i, e := range l {
|
for i, e := range l {
|
||||||
l[i] = p.wrapname(expr.ElemList[i], e)
|
l[i] = p.wrapname(expr.ElemList[i], e)
|
||||||
}
|
}
|
||||||
n.List.Set(l)
|
n.List = l
|
||||||
base.Pos = p.makeXPos(expr.Rbrace)
|
base.Pos = p.makeXPos(expr.Rbrace)
|
||||||
return n
|
return n
|
||||||
case *syntax.KeyValueExpr:
|
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 {
|
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 := ir.NewAssignListStmt(p.pos(stmt), ir.OAS2, nil, nil)
|
||||||
n.Def = stmt.Op == syntax.Def
|
n.Def = stmt.Op == syntax.Def
|
||||||
n.Lhs.Set(p.assignList(stmt.Lhs, n, n.Def))
|
n.Lhs = p.assignList(stmt.Lhs, n, n.Def)
|
||||||
n.Rhs.Set(rhs)
|
n.Rhs = rhs
|
||||||
return n
|
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))
|
n := ir.NewReturnStmt(p.pos(stmt), p.exprList(stmt.Results))
|
||||||
if len(n.Results) == 0 && ir.CurFunc != nil {
|
if len(n.Results) == 0 && ir.CurFunc != nil {
|
||||||
for _, ln := range ir.CurFunc.Dcl {
|
for _, ln := range ir.CurFunc.Dcl {
|
||||||
if ln.Class_ == ir.PPARAM {
|
if ln.Class == ir.PPARAM {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ln.Class_ != ir.PPARAMOUT {
|
if ln.Class != ir.PPARAMOUT {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if ln.Sym().Def != ln {
|
if ln.Sym().Def != ln {
|
||||||
@ -1215,7 +1339,7 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
|
|||||||
panic("unhandled Stmt")
|
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 {
|
if !colas {
|
||||||
return p.exprList(expr)
|
return p.exprList(expr)
|
||||||
}
|
}
|
||||||
@ -1291,7 +1415,7 @@ func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node {
|
|||||||
e := p.stmt(stmt.Else)
|
e := p.stmt(stmt.Else)
|
||||||
if e.Op() == ir.OBLOCK {
|
if e.Op() == ir.OBLOCK {
|
||||||
e := e.(*ir.BlockStmt)
|
e := e.(*ir.BlockStmt)
|
||||||
n.Else.Set(e.List)
|
n.Else = e.List
|
||||||
} else {
|
} else {
|
||||||
n.Else = []ir.Node{e}
|
n.Else = []ir.Node{e}
|
||||||
}
|
}
|
||||||
@ -1316,7 +1440,7 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) ir.Node {
|
|||||||
n.Value = lhs[1]
|
n.Value = lhs[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.Body.Set(p.blockStmt(stmt.Body))
|
n.Body = p.blockStmt(stmt.Body)
|
||||||
p.closeAnotherScope()
|
p.closeAnotherScope()
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
@ -1374,7 +1498,7 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitch
|
|||||||
body = body[:len(body)-1]
|
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 l := len(n.Body); l > 0 && n.Body[l-1].Op() == ir.OFALL {
|
||||||
if tswitch != nil {
|
if tswitch != nil {
|
||||||
base.Errorf("cannot fallthrough in type switch")
|
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 := ir.NewFunc(p.pos(expr))
|
||||||
fn.SetIsHiddenClosure(ir.CurFunc != nil)
|
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.Ntype = xtype
|
||||||
fn.Nname.Defn = fn
|
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
|
// the := it looks like a reference to the outer x so we'll
|
||||||
// make x a closure variable unnecessarily.
|
// make x a closure variable unnecessarily.
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
c := n.Name().Innermost
|
c := n.Innermost
|
||||||
if c == nil || c.Curfn != ir.CurFunc {
|
if c == nil || c.Curfn != ir.CurFunc {
|
||||||
// Do not have a closure var for the active closure yet; make one.
|
// Do not have a closure var for the active closure yet; make one.
|
||||||
c = typecheck.NewName(s)
|
c = typecheck.NewName(s)
|
||||||
c.Class_ = ir.PAUTOHEAP
|
c.Class = ir.PAUTOHEAP
|
||||||
c.SetIsClosureVar(true)
|
c.SetIsClosureVar(true)
|
||||||
c.Defn = n
|
c.Defn = n
|
||||||
|
|
||||||
// Link into list of active closure variables.
|
// Link into list of active closure variables.
|
||||||
// Popped from list in func funcLit.
|
// Popped from list in func funcLit.
|
||||||
c.Outer = n.Name().Innermost
|
c.Outer = n.Innermost
|
||||||
n.Name().Innermost = c
|
n.Innermost = c
|
||||||
|
|
||||||
ir.CurFunc.ClosureVars = append(ir.CurFunc.ClosureVars, c)
|
ir.CurFunc.ClosureVars = append(ir.CurFunc.ClosureVars, c)
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package pkginit
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
|
"cmd/compile/internal/deadcode"
|
||||||
"cmd/compile/internal/ir"
|
"cmd/compile/internal/ir"
|
||||||
"cmd/compile/internal/objw"
|
"cmd/compile/internal/objw"
|
||||||
"cmd/compile/internal/typecheck"
|
"cmd/compile/internal/typecheck"
|
||||||
@ -31,10 +32,10 @@ func Task() *ir.Name {
|
|||||||
if n.Op() == ir.ONONAME {
|
if n.Op() == ir.ONONAME {
|
||||||
continue
|
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)
|
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.
|
// 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...)
|
fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
|
||||||
typecheck.InitTodoFunc.Dcl = nil
|
typecheck.InitTodoFunc.Dcl = nil
|
||||||
|
|
||||||
fn.Body.Set(nf)
|
fn.Body = nf
|
||||||
typecheck.FinishFuncBody()
|
typecheck.FinishFuncBody()
|
||||||
|
|
||||||
typecheck.Func(fn)
|
typecheck.Func(fn)
|
||||||
@ -56,7 +57,7 @@ func Task() *ir.Name {
|
|||||||
typecheck.Stmts(nf)
|
typecheck.Stmts(nf)
|
||||||
ir.CurFunc = nil
|
ir.CurFunc = nil
|
||||||
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
|
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
|
||||||
fns = append(fns, initializers.Linksym())
|
fns = append(fns, fn.Linksym())
|
||||||
}
|
}
|
||||||
if typecheck.InitTodoFunc.Dcl != nil {
|
if typecheck.InitTodoFunc.Dcl != nil {
|
||||||
// We only generate temps using initTodo if there
|
// We only generate temps using initTodo if there
|
||||||
@ -68,13 +69,16 @@ func Task() *ir.Name {
|
|||||||
|
|
||||||
// Record user init functions.
|
// Record user init functions.
|
||||||
for _, fn := range typecheck.Target.Inits {
|
for _, fn := range typecheck.Target.Inits {
|
||||||
|
// Must happen after initOrder; see #43444.
|
||||||
|
deadcode.Func(fn)
|
||||||
|
|
||||||
// Skip init functions with empty bodies.
|
// Skip init functions with empty bodies.
|
||||||
if len(fn.Body) == 1 {
|
if len(fn.Body) == 1 {
|
||||||
if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
|
if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
|
||||||
continue
|
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" {
|
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")
|
sym := typecheck.Lookup(".inittask")
|
||||||
task := typecheck.NewName(sym)
|
task := typecheck.NewName(sym)
|
||||||
task.SetType(types.Types[types.TUINT8]) // fake type
|
task.SetType(types.Types[types.TUINT8]) // fake type
|
||||||
task.Class_ = ir.PEXTERN
|
task.Class = ir.PEXTERN
|
||||||
sym.Def = task
|
sym.Def = task
|
||||||
lsym := sym.Linksym()
|
lsym := task.Linksym()
|
||||||
ot := 0
|
ot := 0
|
||||||
ot = objw.Uintptr(lsym, ot, 0) // state: not initialized yet
|
ot = objw.Uintptr(lsym, ot, 0) // state: not initialized yet
|
||||||
ot = objw.Uintptr(lsym, ot, uint64(len(deps)))
|
ot = objw.Uintptr(lsym, ot, uint64(len(deps)))
|
||||||
|
@ -140,7 +140,7 @@ func (o *InitOrder) processAssign(n ir.Node) {
|
|||||||
defn := dep.Defn
|
defn := dep.Defn
|
||||||
// Skip dependencies on functions (PFUNC) and
|
// Skip dependencies on functions (PFUNC) and
|
||||||
// variables already initialized (InitDone).
|
// variables already initialized (InitDone).
|
||||||
if dep.Class_ != ir.PEXTERN || o.order[defn] == orderDone {
|
if dep.Class != ir.PEXTERN || o.order[defn] == orderDone {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
o.order[n]++
|
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
|
// There might be multiple loops involving n; by sorting
|
||||||
// references, we deterministically pick the one reported.
|
// 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())
|
return ni.Pos().Before(nj.Pos())
|
||||||
})
|
})
|
||||||
|
|
||||||
*path = append(*path, n)
|
*path = append(*path, n)
|
||||||
for _, ref := range refers {
|
for _, ref := range refers {
|
||||||
// Short-circuit variables that were initialized.
|
// 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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +221,7 @@ func reportInitLoopAndExit(l []*ir.Name) {
|
|||||||
// the start.
|
// the start.
|
||||||
i := -1
|
i := -1
|
||||||
for j, n := range l {
|
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
|
i = j
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,7 +291,7 @@ func (d *initDeps) visit(n ir.Node) {
|
|||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PEXTERN, ir.PFUNC:
|
case ir.PEXTERN, ir.PFUNC:
|
||||||
d.foundDep(n)
|
d.foundDep(n)
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ func (d *initDeps) foundDep(n *ir.Name) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.seen.Add(n)
|
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)
|
d.inspectList(n.Defn.(*ir.Func).Body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ func genhash(t *types.Type) *obj.LSym {
|
|||||||
// For other sizes of plain memory, we build a closure
|
// For other sizes of plain memory, we build a closure
|
||||||
// that calls memhash_varlen. The size of the memory is
|
// that calls memhash_varlen. The size of the memory is
|
||||||
// encoded in the first slot of the closure.
|
// 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
|
if len(closure.P) > 0 { // already generated
|
||||||
return closure
|
return closure
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ func genhash(t *types.Type) *obj.LSym {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
closure := TypeSymPrefix(".hashfunc", t).Linksym()
|
closure := TypeLinksymPrefix(".hashfunc", t)
|
||||||
if len(closure.P) > 0 { // already generated
|
if len(closure.P) > 0 { // already generated
|
||||||
return closure
|
return closure
|
||||||
}
|
}
|
||||||
@ -255,7 +255,7 @@ func genhash(t *types.Type) *obj.LSym {
|
|||||||
|
|
||||||
// Build closure. It doesn't close over any variables, so
|
// Build closure. It doesn't close over any variables, so
|
||||||
// it contains just the function pointer.
|
// 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)
|
objw.Global(closure, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
|
||||||
|
|
||||||
return closure
|
return closure
|
||||||
@ -347,7 +347,7 @@ func geneq(t *types.Type) *obj.LSym {
|
|||||||
case types.AMEM:
|
case types.AMEM:
|
||||||
// make equality closure. The size of the type
|
// make equality closure. The size of the type
|
||||||
// is encoded in the closure.
|
// 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 {
|
if len(closure.P) != 0 {
|
||||||
return closure
|
return closure
|
||||||
}
|
}
|
||||||
@ -363,7 +363,7 @@ func geneq(t *types.Type) *obj.LSym {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
closure := TypeSymPrefix(".eqfunc", t).Linksym()
|
closure := TypeLinksymPrefix(".eqfunc", t)
|
||||||
if len(closure.P) > 0 { // already generated
|
if len(closure.P) > 0 { // already generated
|
||||||
return closure
|
return closure
|
||||||
}
|
}
|
||||||
@ -634,7 +634,7 @@ func geneq(t *types.Type) *obj.LSym {
|
|||||||
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
|
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
|
||||||
|
|
||||||
// Generate a closure which points at the function we just generated.
|
// 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)
|
objw.Global(closure, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
|
||||||
return closure
|
return closure
|
||||||
}
|
}
|
||||||
|
@ -52,13 +52,13 @@ var (
|
|||||||
signatslice []*types.Type
|
signatslice []*types.Type
|
||||||
|
|
||||||
itabs []itabEntry
|
itabs []itabEntry
|
||||||
ptabs []ptabEntry
|
ptabs []*ir.Name
|
||||||
)
|
)
|
||||||
|
|
||||||
type typeSig struct {
|
type typeSig struct {
|
||||||
name *types.Sym
|
name *types.Sym
|
||||||
isym *types.Sym
|
isym *obj.LSym
|
||||||
tsym *types.Sym
|
tsym *obj.LSym
|
||||||
type_ *types.Type
|
type_ *types.Type
|
||||||
mtype *types.Type
|
mtype *types.Type
|
||||||
}
|
}
|
||||||
@ -327,21 +327,19 @@ func methods(t *types.Type) []*typeSig {
|
|||||||
// generating code if necessary.
|
// generating code if necessary.
|
||||||
var ms []*typeSig
|
var ms []*typeSig
|
||||||
for _, f := range mt.AllMethods().Slice() {
|
for _, f := range mt.AllMethods().Slice() {
|
||||||
|
if f.Sym == nil {
|
||||||
|
base.Fatalf("method with no sym on %v", mt)
|
||||||
|
}
|
||||||
if !f.IsMethod() {
|
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 {
|
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() {
|
if f.Nointerface() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
method := f.Sym
|
|
||||||
if method == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// get receiver type for this particular method.
|
// get receiver type for this particular method.
|
||||||
// if pointer receiver but non-pointer t and
|
// if pointer receiver but non-pointer t and
|
||||||
// this is not an embedded pointer inside a struct,
|
// this is not an embedded pointer inside a struct,
|
||||||
@ -351,29 +349,13 @@ func methods(t *types.Type) []*typeSig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sig := &typeSig{
|
sig := &typeSig{
|
||||||
name: method,
|
name: f.Sym,
|
||||||
isym: ir.MethodSym(it, method),
|
isym: methodWrapper(it, f),
|
||||||
tsym: ir.MethodSym(t, method),
|
tsym: methodWrapper(t, f),
|
||||||
type_: typecheck.NewMethodType(f.Type, t),
|
type_: typecheck.NewMethodType(f.Type, t),
|
||||||
mtype: typecheck.NewMethodType(f.Type, nil),
|
mtype: typecheck.NewMethodType(f.Type, nil),
|
||||||
}
|
}
|
||||||
ms = append(ms, sig)
|
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
|
return ms
|
||||||
@ -407,11 +389,7 @@ func imethods(t *types.Type) []*typeSig {
|
|||||||
// IfaceType.Method is not in the reflect data.
|
// IfaceType.Method is not in the reflect data.
|
||||||
// Generate the method body, so that compiled
|
// Generate the method body, so that compiled
|
||||||
// code can refer to it.
|
// code can refer to it.
|
||||||
isym := ir.MethodSym(t, f.Sym)
|
methodWrapper(t, f)
|
||||||
if !isym.Siggen() {
|
|
||||||
isym.SetSiggen(true)
|
|
||||||
genwrapper(t, f, isym)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return methods
|
return methods
|
||||||
@ -636,8 +614,8 @@ func dextratypeData(lsym *obj.LSym, ot int, t *types.Type) int {
|
|||||||
|
|
||||||
ot = objw.SymPtrOff(lsym, ot, nsym)
|
ot = objw.SymPtrOff(lsym, ot, nsym)
|
||||||
ot = dmethodptrOff(lsym, ot, WriteType(a.mtype))
|
ot = dmethodptrOff(lsym, ot, WriteType(a.mtype))
|
||||||
ot = dmethodptrOff(lsym, ot, a.isym.Linksym())
|
ot = dmethodptrOff(lsym, ot, a.isym)
|
||||||
ot = dmethodptrOff(lsym, ot, a.tsym.Linksym())
|
ot = dmethodptrOff(lsym, ot, a.tsym)
|
||||||
}
|
}
|
||||||
return ot
|
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
|
// TrackSym returns the symbol for tracking use of field/method f, assumed
|
||||||
// to be a member of struct/interface type t.
|
// to be a member of struct/interface type t.
|
||||||
func TrackSym(t *types.Type, f *types.Field) *types.Sym {
|
func TrackSym(t *types.Type, f *types.Field) *obj.LSym {
|
||||||
return ir.Pkgs.Track.Lookup(t.ShortString() + "." + f.Sym.Name)
|
return ir.Pkgs.Track.Lookup(t.ShortString() + "." + f.Sym.Name).Linksym()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
|
func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
|
||||||
@ -845,12 +823,24 @@ func TypeSym(t *types.Type) *types.Sym {
|
|||||||
return s
|
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 {
|
func TypePtr(t *types.Type) *ir.AddrExpr {
|
||||||
s := TypeSym(t)
|
s := TypeSym(t)
|
||||||
if s.Def == nil {
|
if s.Def == nil {
|
||||||
n := ir.NewNameAt(src.NoXPos, s)
|
n := ir.NewNameAt(src.NoXPos, s)
|
||||||
n.SetType(types.Types[types.TUINT8])
|
n.SetType(types.Types[types.TUINT8])
|
||||||
n.Class_ = ir.PEXTERN
|
n.Class = ir.PEXTERN
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
s.Def = n
|
s.Def = n
|
||||||
}
|
}
|
||||||
@ -869,10 +859,10 @@ func ITabAddr(t, itype *types.Type) *ir.AddrExpr {
|
|||||||
if s.Def == nil {
|
if s.Def == nil {
|
||||||
n := typecheck.NewName(s)
|
n := typecheck.NewName(s)
|
||||||
n.SetType(types.Types[types.TUINT8])
|
n.SetType(types.Types[types.TUINT8])
|
||||||
n.Class_ = ir.PEXTERN
|
n.Class = ir.PEXTERN
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
s.Def = n
|
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))
|
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
|
// so we can find the intersect in a single pass
|
||||||
for _, m := range methods {
|
for _, m := range methods {
|
||||||
if m.name == sigs[0].name {
|
if m.name == sigs[0].name {
|
||||||
out = append(out, m.isym.Linksym())
|
out = append(out, m.isym)
|
||||||
sigs = sigs[1:]
|
sigs = sigs[1:]
|
||||||
if len(sigs) == 0 {
|
if len(sigs) == 0 {
|
||||||
break
|
break
|
||||||
@ -1378,8 +1368,12 @@ func WriteTabs() {
|
|||||||
// name nameOff
|
// name nameOff
|
||||||
// typ typeOff // pointer to symbol
|
// typ typeOff // pointer to symbol
|
||||||
// }
|
// }
|
||||||
nsym := dname(p.s.Name, "", nil, true)
|
nsym := dname(p.Sym().Name, "", nil, true)
|
||||||
tsym := WriteType(p.t)
|
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, nsym)
|
||||||
ot = objw.SymPtrOff(s, ot, tsym)
|
ot = objw.SymPtrOff(s, ot, tsym)
|
||||||
// Plugin exports symbols as interfaces. Mark their types
|
// Plugin exports symbols as interfaces. Mark their types
|
||||||
@ -1391,7 +1385,7 @@ func WriteTabs() {
|
|||||||
ot = 0
|
ot = 0
|
||||||
s = base.Ctxt.Lookup("go.plugin.exports")
|
s = base.Ctxt.Lookup("go.plugin.exports")
|
||||||
for _, p := range ptabs {
|
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))
|
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 {
|
if t.Width == types.BADWIDTH {
|
||||||
base.Fatalf("dgcprog: %v badwidth", t)
|
base.Fatalf("dgcprog: %v badwidth", t)
|
||||||
}
|
}
|
||||||
lsym := TypeSymPrefix(".gcprog", t).Linksym()
|
lsym := TypeLinksymPrefix(".gcprog", t)
|
||||||
var p gcProg
|
var p gcProg
|
||||||
p.init(lsym)
|
p.init(lsym)
|
||||||
p.emit(t, 0)
|
p.emit(t, 0)
|
||||||
@ -1680,7 +1674,7 @@ func ZeroAddr(size int64) ir.Node {
|
|||||||
if s.Def == nil {
|
if s.Def == nil {
|
||||||
x := typecheck.NewName(s)
|
x := typecheck.NewName(s)
|
||||||
x.SetType(types.Types[types.TUINT8])
|
x.SetType(types.Types[types.TUINT8])
|
||||||
x.Class_ = ir.PEXTERN
|
x.Class = ir.PEXTERN
|
||||||
x.SetTypecheck(1)
|
x.SetTypecheck(1)
|
||||||
s.Def = x
|
s.Def = x
|
||||||
}
|
}
|
||||||
@ -1710,13 +1704,7 @@ func CollectPTabs() {
|
|||||||
if s.Pkg.Name != "main" {
|
if s.Pkg.Name != "main" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.Type().Kind() == types.TFUNC && n.Class_ == ir.PFUNC {
|
ptabs = append(ptabs, n)
|
||||||
// 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())})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1740,22 +1728,28 @@ func CollectPTabs() {
|
|||||||
//
|
//
|
||||||
// rcvr - U
|
// rcvr - U
|
||||||
// method - M func (t T)(), a TFIELD type struct
|
// method - M func (t T)(), a TFIELD type struct
|
||||||
// newnam - the eventual mangled name of this function
|
func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym {
|
||||||
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
newnam := ir.MethodSym(rcvr, method.Sym)
|
||||||
if false && base.Flag.LowerR != 0 {
|
lsym := newnam.Linksym()
|
||||||
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
|
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.
|
// Only generate (*T).M wrappers for T.M in T's own package.
|
||||||
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
|
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
|
||||||
rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg {
|
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
|
// Only generate I.M wrappers for I in I's own package
|
||||||
// but keep doing it for error.Error (was issue #29304).
|
// but keep doing it for error.Error (was issue #29304).
|
||||||
if rcvr.IsInterface() && rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && rcvr != types.ErrorType {
|
if rcvr.IsInterface() && rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && rcvr != types.ErrorType {
|
||||||
return
|
return lsym
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Pos = base.AutogeneratedPos
|
base.Pos = base.AutogeneratedPos
|
||||||
@ -1804,7 +1798,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
|||||||
} else {
|
} else {
|
||||||
fn.SetWrapper(true) // ignore frame for panic+recover matching
|
fn.SetWrapper(true) // ignore frame for panic+recover matching
|
||||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
|
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()
|
call.IsDDD = tfn.Type().IsVariadic()
|
||||||
if method.Type.NumResults() > 0 {
|
if method.Type.NumResults() > 0 {
|
||||||
ret := ir.NewReturnStmt(base.Pos, nil)
|
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()
|
typecheck.FinishFuncBody()
|
||||||
if base.Debug.DclStack != 0 {
|
if base.Debug.DclStack != 0 {
|
||||||
types.CheckDclstack()
|
types.CheckDclstack()
|
||||||
@ -1838,6 +1828,8 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
|||||||
|
|
||||||
ir.CurFunc = nil
|
ir.CurFunc = nil
|
||||||
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
|
typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
|
||||||
|
|
||||||
|
return lsym
|
||||||
}
|
}
|
||||||
|
|
||||||
var ZeroSize int64
|
var ZeroSize int64
|
||||||
@ -1845,7 +1837,7 @@ var ZeroSize int64
|
|||||||
// MarkTypeUsedInInterface marks that type t is converted to an interface.
|
// MarkTypeUsedInInterface marks that type t is converted to an interface.
|
||||||
// This information is used in the linker in dead method elimination.
|
// This information is used in the linker in dead method elimination.
|
||||||
func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {
|
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
|
// Emit a marker relocation. The linker will know the type is converted
|
||||||
// to an interface if "from" is reachable.
|
// to an interface if "from" is reachable.
|
||||||
r := obj.Addrel(from)
|
r := obj.Addrel(from)
|
||||||
@ -1858,7 +1850,7 @@ func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {
|
|||||||
func MarkUsedIfaceMethod(n *ir.CallExpr) {
|
func MarkUsedIfaceMethod(n *ir.CallExpr) {
|
||||||
dot := n.X.(*ir.SelectorExpr)
|
dot := n.X.(*ir.SelectorExpr)
|
||||||
ityp := dot.X.Type()
|
ityp := dot.X.Type()
|
||||||
tsym := TypeSym(ityp).Linksym()
|
tsym := TypeLinksym(ityp)
|
||||||
r := obj.Addrel(ir.CurFunc.LSym)
|
r := obj.Addrel(ir.CurFunc.LSym)
|
||||||
r.Sym = tsym
|
r.Sym = tsym
|
||||||
// dot.Xoffset is the method index * Widthptr (the offset of code pointer
|
// dot.Xoffset is the method index * Widthptr (the offset of code pointer
|
||||||
|
@ -148,7 +148,7 @@ func elimDeadAutosGeneric(f *Func) {
|
|||||||
case OpAddr, OpLocalAddr:
|
case OpAddr, OpLocalAddr:
|
||||||
// Propagate the address if it points to an auto.
|
// Propagate the address if it points to an auto.
|
||||||
n, ok := v.Aux.(*ir.Name)
|
n, ok := v.Aux.(*ir.Name)
|
||||||
if !ok || n.Class() != ir.PAUTO {
|
if !ok || n.Class != ir.PAUTO {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if addr[v] == nil {
|
if addr[v] == nil {
|
||||||
@ -159,7 +159,7 @@ func elimDeadAutosGeneric(f *Func) {
|
|||||||
case OpVarDef, OpVarKill:
|
case OpVarDef, OpVarKill:
|
||||||
// v should be eliminated if we eliminate the auto.
|
// v should be eliminated if we eliminate the auto.
|
||||||
n, ok := v.Aux.(*ir.Name)
|
n, ok := v.Aux.(*ir.Name)
|
||||||
if !ok || n.Class() != ir.PAUTO {
|
if !ok || n.Class != ir.PAUTO {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if elim[v] == nil {
|
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
|
// may not be used by the inline code, but will be used by
|
||||||
// panic processing).
|
// panic processing).
|
||||||
n, ok := v.Aux.(*ir.Name)
|
n, ok := v.Aux.(*ir.Name)
|
||||||
if !ok || n.Class() != ir.PAUTO {
|
if !ok || n.Class != ir.PAUTO {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !used[n] {
|
if !used[n] {
|
||||||
@ -307,7 +307,7 @@ func elimUnreadAutos(f *Func) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.Class() != ir.PAUTO {
|
if n.Class != ir.PAUTO {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ func (TestFrontend) StringData(s string) *obj.LSym {
|
|||||||
}
|
}
|
||||||
func (TestFrontend) Auto(pos src.XPos, t *types.Type) *ir.Name {
|
func (TestFrontend) Auto(pos src.XPos, t *types.Type) *ir.Name {
|
||||||
n := ir.NewNameAt(pos, &types.Sym{Name: "aFakeAuto"})
|
n := ir.NewNameAt(pos, &types.Sym{Name: "aFakeAuto"})
|
||||||
n.SetClass(ir.PAUTO)
|
n.Class = ir.PAUTO
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
func (d TestFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
|
func (d TestFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmd/compile/internal/reflectdata"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
@ -270,11 +271,11 @@ func writebarrier(f *Func) {
|
|||||||
case OpMoveWB:
|
case OpMoveWB:
|
||||||
fn = typedmemmove
|
fn = typedmemmove
|
||||||
val = w.Args[1]
|
val = w.Args[1]
|
||||||
typ = w.Aux.(*types.Type).Symbol()
|
typ = reflectdata.TypeLinksym(w.Aux.(*types.Type))
|
||||||
nWBops--
|
nWBops--
|
||||||
case OpZeroWB:
|
case OpZeroWB:
|
||||||
fn = typedmemclr
|
fn = typedmemclr
|
||||||
typ = w.Aux.(*types.Type).Symbol()
|
typ = reflectdata.TypeLinksym(w.Aux.(*types.Type))
|
||||||
nWBops--
|
nWBops--
|
||||||
case OpVarDef, OpVarLive, OpVarKill:
|
case OpVarDef, OpVarLive, OpVarKill:
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:generate go run mkbuiltin.go
|
|
||||||
|
|
||||||
package ssagen
|
package ssagen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -168,7 +166,7 @@ func selectLSym(f *ir.Func, hasBody bool) {
|
|||||||
f.LSym = nam.Sym().LinksymABI0()
|
f.LSym = nam.Sym().LinksymABI0()
|
||||||
needABIWrapper, wrapperABI = true, obj.ABIInternal
|
needABIWrapper, wrapperABI = true, obj.ABIInternal
|
||||||
} else {
|
} else {
|
||||||
f.LSym = nam.Sym().Linksym()
|
f.LSym = nam.Linksym()
|
||||||
// No ABI override. Check that the symbol is
|
// No ABI override. Check that the symbol is
|
||||||
// using the expected ABI.
|
// using the expected ABI.
|
||||||
want := obj.ABIInternal
|
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())
|
tail = ir.NewBranchStmt(base.Pos, ir.ORETJMP, f.Nname.Sym())
|
||||||
} else {
|
} else {
|
||||||
call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
|
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()
|
call.IsDDD = tfn.Type().IsVariadic()
|
||||||
tail = call
|
tail = call
|
||||||
if tfn.Type().NumResults() > 0 {
|
if tfn.Type().NumResults() > 0 {
|
||||||
|
@ -76,7 +76,7 @@ func (c *nowritebarrierrecChecker) findExtraCalls(nn ir.Node) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
fn := n.X.(*ir.Name)
|
fn := n.X.(*ir.Name)
|
||||||
if fn.Class_ != ir.PFUNC || fn.Name().Defn == nil {
|
if fn.Class != ir.PFUNC || fn.Defn == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !types.IsRuntimePkg(fn.Sym().Pkg) || fn.Sym().Name != "systemstack" {
|
if !types.IsRuntimePkg(fn.Sym().Pkg) || fn.Sym().Name != "systemstack" {
|
||||||
@ -88,7 +88,7 @@ func (c *nowritebarrierrecChecker) findExtraCalls(nn ir.Node) {
|
|||||||
switch arg.Op() {
|
switch arg.Op() {
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
arg := arg.(*ir.Name)
|
arg := arg.(*ir.Name)
|
||||||
callee = arg.Name().Defn.(*ir.Func)
|
callee = arg.Defn.(*ir.Func)
|
||||||
case ir.OCLOSURE:
|
case ir.OCLOSURE:
|
||||||
arg := arg.(*ir.ClosureExpr)
|
arg := arg.(*ir.ClosureExpr)
|
||||||
callee = arg.Func
|
callee = arg.Func
|
||||||
|
@ -34,11 +34,11 @@ import (
|
|||||||
// the top of the stack and increasing in size.
|
// the top of the stack and increasing in size.
|
||||||
// Non-autos sort on offset.
|
// Non-autos sort on offset.
|
||||||
func cmpstackvarlt(a, b *ir.Name) bool {
|
func cmpstackvarlt(a, b *ir.Name) bool {
|
||||||
if (a.Class_ == ir.PAUTO) != (b.Class_ == ir.PAUTO) {
|
if (a.Class == ir.PAUTO) != (b.Class == ir.PAUTO) {
|
||||||
return b.Class_ == ir.PAUTO
|
return b.Class == ir.PAUTO
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.Class_ != ir.PAUTO {
|
if a.Class != ir.PAUTO {
|
||||||
return a.FrameOffset() < b.FrameOffset()
|
return a.FrameOffset() < b.FrameOffset()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,14 +79,14 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
|
|||||||
|
|
||||||
// Mark the PAUTO's unused.
|
// Mark the PAUTO's unused.
|
||||||
for _, ln := range fn.Dcl {
|
for _, ln := range fn.Dcl {
|
||||||
if ln.Class_ == ir.PAUTO {
|
if ln.Class == ir.PAUTO {
|
||||||
ln.SetUsed(false)
|
ln.SetUsed(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, l := range f.RegAlloc {
|
for _, l := range f.RegAlloc {
|
||||||
if ls, ok := l.(ssa.LocalSlot); ok {
|
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 _, b := range f.Blocks {
|
||||||
for _, v := range b.Values {
|
for _, v := range b.Values {
|
||||||
if n, ok := v.Aux.(*ir.Name); ok {
|
if n, ok := v.Aux.(*ir.Name); ok {
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PPARAM, ir.PPARAMOUT:
|
case ir.PPARAM, ir.PPARAMOUT:
|
||||||
// Don't modify nodfp; it is a global.
|
// Don't modify nodfp; it is a global.
|
||||||
if n != ir.RegFP {
|
if n != ir.RegFP {
|
||||||
n.Name().SetUsed(true)
|
n.SetUsed(true)
|
||||||
}
|
}
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
n.Name().SetUsed(true)
|
n.SetUsed(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !scratchUsed {
|
if !scratchUsed {
|
||||||
@ -120,7 +120,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
|
|||||||
// Reassign stack offsets of the locals that are used.
|
// Reassign stack offsets of the locals that are used.
|
||||||
lastHasPtr := false
|
lastHasPtr := false
|
||||||
for i, n := range fn.Dcl {
|
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
|
continue
|
||||||
}
|
}
|
||||||
if !n.Used() {
|
if !n.Used() {
|
||||||
@ -207,7 +207,7 @@ func init() {
|
|||||||
func StackOffset(slot ssa.LocalSlot) int32 {
|
func StackOffset(slot ssa.LocalSlot) int32 {
|
||||||
n := slot.N
|
n := slot.N
|
||||||
var off int64
|
var off int64
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
off = n.FrameOffset()
|
off = n.FrameOffset()
|
||||||
if base.Ctxt.FixedFrameSize() == 0 {
|
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
|
// fieldtrack adds R_USEFIELD relocations to fnsym to record any
|
||||||
// struct fields that it used.
|
// 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 {
|
if fnsym == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -233,24 +233,18 @@ func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
trackSyms := make([]*types.Sym, 0, len(tracked))
|
trackSyms := make([]*obj.LSym, 0, len(tracked))
|
||||||
for sym := range tracked {
|
for sym := range tracked {
|
||||||
trackSyms = append(trackSyms, sym)
|
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 {
|
for _, sym := range trackSyms {
|
||||||
r := obj.Addrel(fnsym)
|
r := obj.Addrel(fnsym)
|
||||||
r.Sym = sym.Linksym()
|
r.Sym = sym
|
||||||
r.Type = objabi.R_USEFIELD
|
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).
|
// largeStack is info about a function whose stack frame is too large (rare).
|
||||||
type largeStack struct {
|
type largeStack struct {
|
||||||
locals int64
|
locals int64
|
||||||
|
@ -46,7 +46,7 @@ func TestCmpstackvar(t *testing.T) {
|
|||||||
n := typecheck.NewName(s)
|
n := typecheck.NewName(s)
|
||||||
n.SetType(t)
|
n.SetType(t)
|
||||||
n.SetFrameOffset(xoffset)
|
n.SetFrameOffset(xoffset)
|
||||||
n.Class_ = cl
|
n.Class = cl
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
testdata := []struct {
|
testdata := []struct {
|
||||||
@ -161,7 +161,7 @@ func TestStackvarSort(t *testing.T) {
|
|||||||
n := typecheck.NewName(s)
|
n := typecheck.NewName(s)
|
||||||
n.SetType(t)
|
n.SetType(t)
|
||||||
n.SetFrameOffset(xoffset)
|
n.SetFrameOffset(xoffset)
|
||||||
n.Class_ = cl
|
n.Class = cl
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
inp := []*ir.Name{
|
inp := []*ir.Name{
|
||||||
|
@ -436,7 +436,7 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
|
|||||||
var args []ssa.Param
|
var args []ssa.Param
|
||||||
var results []ssa.Param
|
var results []ssa.Param
|
||||||
for _, n := range fn.Dcl {
|
for _, n := range fn.Dcl {
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PPARAM:
|
case ir.PPARAM:
|
||||||
s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type()), n, s.sp, s.startmem)
|
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())})
|
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:
|
case ir.PFUNC:
|
||||||
// local function - already handled by frontend
|
// local function - already handled by frontend
|
||||||
default:
|
default:
|
||||||
s.Fatalf("local variable with class %v unimplemented", n.Class_)
|
s.Fatalf("local variable with class %v unimplemented", n.Class)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate SSAable arguments.
|
// Populate SSAable arguments.
|
||||||
for _, n := range fn.Dcl {
|
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)
|
v := s.newValue0A(ssa.OpArg, n.Type(), n)
|
||||||
s.vars[n] = v
|
s.vars[n] = v
|
||||||
s.addNamedValue(n, v) // This helps with debugging information, not needed for compilation itself.
|
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:
|
case ir.OCALLINTER:
|
||||||
n := n.(*ir.CallExpr)
|
n := n.(*ir.CallExpr)
|
||||||
s.callResult(n, callNormal)
|
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" ||
|
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") {
|
n.X.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap") {
|
||||||
m := s.mem()
|
m := s.mem()
|
||||||
@ -1242,7 +1242,7 @@ func (s *state) stmt(n ir.Node) {
|
|||||||
|
|
||||||
case ir.ODCL:
|
case ir.ODCL:
|
||||||
n := n.(*ir.Decl)
|
n := n.(*ir.Decl)
|
||||||
if n.X.(*ir.Name).Class_ == ir.PAUTOHEAP {
|
if n.X.Class == ir.PAUTOHEAP {
|
||||||
s.Fatalf("DCL %v", n)
|
s.Fatalf("DCL %v", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1634,7 +1634,7 @@ func (s *state) stmt(n ir.Node) {
|
|||||||
if !v.Addrtaken() {
|
if !v.Addrtaken() {
|
||||||
s.Fatalf("VARLIVE variable %v must have Addrtaken set", v)
|
s.Fatalf("VARLIVE variable %v must have Addrtaken set", v)
|
||||||
}
|
}
|
||||||
switch v.Class_ {
|
switch v.Class {
|
||||||
case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
|
case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
|
||||||
default:
|
default:
|
||||||
s.Fatalf("VARLIVE variable %v must be Auto or Arg", v)
|
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)
|
return s.newValue3(ssa.OpSliceMake, n.Type(), ptr, len, len)
|
||||||
case ir.OCFUNC:
|
case ir.OCFUNC:
|
||||||
n := n.(*ir.UnaryExpr)
|
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)
|
return s.entryNewValue1A(ssa.OpAddr, n.Type(), aux, s.sb)
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
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
|
// "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)
|
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type()), sym, s.sb)
|
||||||
}
|
}
|
||||||
if s.canSSA(n) {
|
if s.canSSA(n) {
|
||||||
@ -3003,7 +3003,7 @@ func (s *state) append(n *ir.CallExpr, inplace bool) *ssa.Value {
|
|||||||
if inplace {
|
if inplace {
|
||||||
if sn.Op() == ir.ONAME {
|
if sn.Op() == ir.ONAME {
|
||||||
sn := sn.(*ir.Name)
|
sn := sn.(*ir.Name)
|
||||||
if sn.Class_ != ir.PEXTERN {
|
if sn.Class != ir.PEXTERN {
|
||||||
// Tell liveness we're about to build a new slice
|
// Tell liveness we're about to build a new slice
|
||||||
s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
|
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
|
// If this assignment clobbers an entire local variable, then emit
|
||||||
// OpVarDef so liveness analysis knows the variable is redefined.
|
// 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))
|
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)
|
closureVal := s.expr(fn)
|
||||||
closure := s.openDeferSave(nil, fn.Type(), closureVal)
|
closure := s.openDeferSave(nil, fn.Type(), closureVal)
|
||||||
opendefer.closureNode = closure.Aux.(*ir.Name)
|
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
|
opendefer.closure = closure
|
||||||
}
|
}
|
||||||
} else if n.Op() == ir.OCALLMETH {
|
} 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())
|
call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, aux, codeptr, v, s.mem())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
aux := ssa.StaticAuxCall(fn.Sym().Linksym(), ACArgs, ACResults)
|
aux := ssa.StaticAuxCall(fn.(*ir.Name).Linksym(), ACArgs, ACResults)
|
||||||
if testLateExpansion {
|
if testLateExpansion {
|
||||||
callArgs = append(callArgs, s.mem())
|
callArgs = append(callArgs, s.mem())
|
||||||
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
|
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() {
|
switch n.Op() {
|
||||||
case ir.OCALLFUNC:
|
case ir.OCALLFUNC:
|
||||||
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
|
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)
|
fn := fn.(*ir.Name)
|
||||||
sym = fn.Sym()
|
sym = fn.Sym()
|
||||||
break
|
break
|
||||||
@ -4867,7 +4867,9 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
|
|||||||
s.vars[memVar] = call
|
s.vars[memVar] = call
|
||||||
}
|
}
|
||||||
// Insert OVARLIVE nodes
|
// 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
|
// Finish block for defers
|
||||||
if k == callDefer || k == callDeferStack {
|
if k == callDefer || k == callDeferStack {
|
||||||
@ -4956,10 +4958,10 @@ func (s *state) addr(n ir.Node) *ssa.Value {
|
|||||||
fallthrough
|
fallthrough
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PEXTERN:
|
case ir.PEXTERN:
|
||||||
// global variable
|
// 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.
|
// TODO: Make OpAddr use AuxInt as well as Aux.
|
||||||
if offset != 0 {
|
if offset != 0 {
|
||||||
v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, offset, v)
|
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
|
// that cse works on their addresses
|
||||||
return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
|
return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true)
|
||||||
default:
|
default:
|
||||||
s.Fatalf("variable address class %v not implemented", n.Class_)
|
s.Fatalf("variable address class %v not implemented", n.Class)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case ir.ORESULT:
|
case ir.ORESULT:
|
||||||
@ -5094,10 +5096,10 @@ func (s *state) canSSAName(name *ir.Name) bool {
|
|||||||
if ir.IsParamHeapCopy(name) {
|
if ir.IsParamHeapCopy(name) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if name.Class_ == ir.PAUTOHEAP {
|
if name.Class == ir.PAUTOHEAP {
|
||||||
s.Fatalf("canSSA of PAUTOHEAP %v", name)
|
s.Fatalf("canSSA of PAUTOHEAP %v", name)
|
||||||
}
|
}
|
||||||
switch name.Class_ {
|
switch name.Class {
|
||||||
case ir.PEXTERN:
|
case ir.PEXTERN:
|
||||||
return false
|
return false
|
||||||
case ir.PPARAMOUT:
|
case ir.PPARAMOUT:
|
||||||
@ -5115,7 +5117,7 @@ func (s *state) canSSAName(name *ir.Name) bool {
|
|||||||
return false
|
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
|
// wrappers generated by genwrapper need to update
|
||||||
// the .this pointer in place.
|
// the .this pointer in place.
|
||||||
// TODO: treat as a PPARAMOUT?
|
// 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.
|
// commaok indicates whether to panic or return a bool.
|
||||||
// If commaok is false, resok will be nil.
|
// If commaok is false, resok will be nil.
|
||||||
func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
|
func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Value) {
|
||||||
iface := s.expr(n.X) // input interface
|
iface := s.expr(n.X) // input interface
|
||||||
target := s.expr(n.Ntype) // target type
|
target := s.expr(n.DstType) // target type
|
||||||
byteptr := s.f.Config.Types.BytePtr
|
byteptr := s.f.Config.Types.BytePtr
|
||||||
|
|
||||||
if n.Type().IsInterface() {
|
if n.Type().IsInterface() {
|
||||||
@ -6086,7 +6088,7 @@ func (s *state) dottype(n *ir.TypeAssertExpr, commaok bool) (res, resok *ssa.Val
|
|||||||
targetITab = target
|
targetITab = target
|
||||||
} else {
|
} else {
|
||||||
// Looking for pointer to itab for target type and source interface.
|
// 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
|
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 {
|
if !commaok {
|
||||||
// on failure, panic by calling panicdottype
|
// on failure, panic by calling panicdottype
|
||||||
s.startBlock(bFail)
|
s.startBlock(bFail)
|
||||||
taddr := s.expr(n.Ntype.(*ir.AddrExpr).Alloc)
|
taddr := s.expr(n.SrcType)
|
||||||
if n.X.Type().IsEmptyInterface() {
|
if n.X.Type().IsEmptyInterface() {
|
||||||
s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
|
s.rtcall(ir.Syms.PanicdottypeE, false, nil, itab, target, taddr)
|
||||||
} else {
|
} else {
|
||||||
@ -6208,7 +6210,7 @@ func (s *state) mem() *ssa.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) addNamedValue(n *ir.Name, v *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.).
|
// Don't track our marker nodes (memVar etc.).
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -6216,12 +6218,12 @@ func (s *state) addNamedValue(n *ir.Name, v *ssa.Value) {
|
|||||||
// Don't track temporary variables.
|
// Don't track temporary variables.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if n.Class_ == ir.PPARAMOUT {
|
if n.Class == ir.PPARAMOUT {
|
||||||
// Don't track named output values. This prevents return values
|
// Don't track named output values. This prevents return values
|
||||||
// from being assigned too early. See #14591 and #14762. TODO: allow this.
|
// from being assigned too early. See #14591 and #14762. TODO: allow this.
|
||||||
return
|
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]
|
values, ok := s.f.NamedValues[loc]
|
||||||
if !ok {
|
if !ok {
|
||||||
s.f.Names = append(s.f.Names, loc)
|
s.f.Names = append(s.f.Names, loc)
|
||||||
@ -6739,8 +6741,8 @@ func defframe(s *State, e *ssafn) {
|
|||||||
if !n.Needzero() {
|
if !n.Needzero() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.Class_ != ir.PAUTO {
|
if n.Class != ir.PAUTO {
|
||||||
e.Fatalf(n.Pos(), "needzero class %d", n.Class_)
|
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 {
|
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_)
|
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.Name = obj.NAME_EXTERN
|
||||||
a.Sym = n
|
a.Sym = n
|
||||||
case *ir.Name:
|
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.Name = obj.NAME_PARAM
|
||||||
a.Sym = ir.Orig(n).Sym().Linksym()
|
a.Sym = ir.Orig(n).(*ir.Name).Linksym()
|
||||||
a.Offset += n.FrameOffset()
|
a.Offset += n.FrameOffset()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
a.Name = obj.NAME_AUTO
|
a.Name = obj.NAME_AUTO
|
||||||
a.Sym = n.Sym().Linksym()
|
a.Sym = n.Linksym()
|
||||||
a.Offset += n.FrameOffset()
|
a.Offset += n.FrameOffset()
|
||||||
default:
|
default:
|
||||||
v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
|
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) {
|
func AddrAuto(a *obj.Addr, v *ssa.Value) {
|
||||||
n, off := ssa.AutoVar(v)
|
n, off := ssa.AutoVar(v)
|
||||||
a.Type = obj.TYPE_MEM
|
a.Type = obj.TYPE_MEM
|
||||||
a.Sym = n.Sym().Linksym()
|
a.Sym = n.Linksym()
|
||||||
a.Reg = int16(Arch.REGSP)
|
a.Reg = int16(Arch.REGSP)
|
||||||
a.Offset = n.FrameOffset() + off
|
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
|
a.Name = obj.NAME_PARAM
|
||||||
} else {
|
} else {
|
||||||
a.Name = obj.NAME_AUTO
|
a.Name = obj.NAME_AUTO
|
||||||
@ -6979,7 +6981,7 @@ func (s *State) AddrScratch(a *obj.Addr) {
|
|||||||
}
|
}
|
||||||
a.Type = obj.TYPE_MEM
|
a.Type = obj.TYPE_MEM
|
||||||
a.Name = obj.NAME_AUTO
|
a.Name = obj.NAME_AUTO
|
||||||
a.Sym = s.ScratchFpMem.Sym().Linksym()
|
a.Sym = s.ScratchFpMem.Linksym()
|
||||||
a.Reg = int16(Arch.REGSP)
|
a.Reg = int16(Arch.REGSP)
|
||||||
a.Offset = s.ScratchFpMem.Offset_
|
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 {
|
func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
|
||||||
node := parent.N
|
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)
|
// 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}
|
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
|
s.Def = n
|
||||||
ir.AsNode(s.Def).Name().SetUsed(true)
|
ir.AsNode(s.Def).Name().SetUsed(true)
|
||||||
n.SetType(t)
|
n.SetType(t)
|
||||||
n.Class_ = ir.PAUTO
|
n.Class = ir.PAUTO
|
||||||
n.SetEsc(ir.EscNever)
|
n.SetEsc(ir.EscNever)
|
||||||
n.Curfn = e.curfn
|
n.Curfn = e.curfn
|
||||||
e.curfn.Dcl = append(e.curfn.Dcl, n)
|
e.curfn.Dcl = append(e.curfn.Dcl, n)
|
||||||
|
@ -37,8 +37,8 @@ func InitAddr(n *ir.Name, noff int64, a *ir.Name, aoff int64) {
|
|||||||
if a.Op() != ir.ONAME {
|
if a.Op() != ir.ONAME {
|
||||||
base.Fatalf("addrsym a op %v", a.Op())
|
base.Fatalf("addrsym a op %v", a.Op())
|
||||||
}
|
}
|
||||||
s := n.Sym().Linksym()
|
s := n.Linksym()
|
||||||
s.WriteAddr(base.Ctxt, noff, types.PtrSize, a.Sym().Linksym(), aoff)
|
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.
|
// 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 {
|
if n.Sym() == nil {
|
||||||
base.Fatalf("pfuncsym nil n sym")
|
base.Fatalf("pfuncsym nil n sym")
|
||||||
}
|
}
|
||||||
if f.Class_ != ir.PFUNC {
|
if f.Class != ir.PFUNC {
|
||||||
base.Fatalf("pfuncsym class not PFUNC %d", f.Class_)
|
base.Fatalf("pfuncsym class not PFUNC %d", f.Class)
|
||||||
}
|
}
|
||||||
s := n.Sym().Linksym()
|
s := n.Linksym()
|
||||||
s.WriteAddr(base.Ctxt, noff, types.PtrSize, FuncSym(f.Sym()).Linksym(), 0)
|
s.WriteAddr(base.Ctxt, noff, types.PtrSize, FuncLinksym(f), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitSlice writes a static slice symbol {&arr, lencap, lencap} to n+noff.
|
// InitSlice writes a static slice symbol {&arr, lencap, lencap} to n+noff.
|
||||||
// InitSlice does not modify n.
|
// InitSlice does not modify n.
|
||||||
func InitSlice(n *ir.Name, noff int64, arr *ir.Name, lencap int64) {
|
func InitSlice(n *ir.Name, noff int64, arr *ir.Name, lencap int64) {
|
||||||
s := n.Sym().Linksym()
|
s := n.Linksym()
|
||||||
if arr.Op() != ir.ONAME {
|
if arr.Op() != ir.ONAME {
|
||||||
base.Fatalf("slicesym non-name arr %v", arr)
|
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.SliceLenOffset, types.PtrSize, lencap)
|
||||||
s.WriteInt(base.Ctxt, noff+types.SliceCapOffset, 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 {
|
if readonly {
|
||||||
sym = StringSym(pos, string(data))
|
sym = StringSym(pos, string(data))
|
||||||
} else {
|
} else {
|
||||||
sym = slicedata(pos, string(data)).Sym().Linksym()
|
sym = slicedata(pos, string(data)).Linksym()
|
||||||
}
|
}
|
||||||
if len(hash) > 0 {
|
if len(hash) > 0 {
|
||||||
sum := sha256.Sum256(data)
|
sum := sha256.Sum256(data)
|
||||||
@ -189,7 +189,7 @@ func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.
|
|||||||
} else {
|
} else {
|
||||||
// Emit a zero-length data symbol
|
// Emit a zero-length data symbol
|
||||||
// and then fix up length and content to use file.
|
// and then fix up length and content to use file.
|
||||||
symdata = slicedata(pos, "").Sym().Linksym()
|
symdata = slicedata(pos, "").Linksym()
|
||||||
symdata.Size = size
|
symdata.Size = size
|
||||||
symdata.Type = objabi.SNOPTRDATA
|
symdata.Type = objabi.SNOPTRDATA
|
||||||
info := symdata.NewFileInfo()
|
info := symdata.NewFileInfo()
|
||||||
@ -209,7 +209,7 @@ func slicedata(pos src.XPos, s string) *ir.Name {
|
|||||||
symnode := typecheck.NewName(sym)
|
symnode := typecheck.NewName(sym)
|
||||||
sym.Def = symnode
|
sym.Def = symnode
|
||||||
|
|
||||||
lsym := sym.Linksym()
|
lsym := symnode.Linksym()
|
||||||
off := dstringdata(lsym, 0, s, pos, "slice")
|
off := dstringdata(lsym, 0, s, pos, "slice")
|
||||||
objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL)
|
objw.Global(lsym, int32(off), obj.NOPTR|obj.LOCAL)
|
||||||
|
|
||||||
@ -258,6 +258,13 @@ func FuncSym(s *types.Sym) *types.Sym {
|
|||||||
return sf
|
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.
|
// NeedFuncSym ensures that s·f is exported.
|
||||||
// It is only used with -dynlink.
|
// It is only used with -dynlink.
|
||||||
// When not compiling for dynamic linking,
|
// 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 {
|
if c.Op() != ir.OLITERAL {
|
||||||
base.Fatalf("litsym c op %v", c.Op())
|
base.Fatalf("litsym c op %v", c.Op())
|
||||||
}
|
}
|
||||||
s := n.Sym().Linksym()
|
s := n.Linksym()
|
||||||
switch u := c.Val(); u.Kind() {
|
switch u := c.Val(); u.Kind() {
|
||||||
case constant.Bool:
|
case constant.Bool:
|
||||||
i := int64(obj.Bool2int(constant.BoolVal(u)))
|
i := int64(obj.Bool2int(constant.BoolVal(u)))
|
||||||
|
@ -145,7 +145,7 @@ func WriteEmbed(v *ir.Name) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
base.ErrorfAt(v.Pos(), "embed %s: %v", file, err)
|
base.ErrorfAt(v.Pos(), "embed %s: %v", file, err)
|
||||||
}
|
}
|
||||||
sym := v.Sym().Linksym()
|
sym := v.Linksym()
|
||||||
off := 0
|
off := 0
|
||||||
off = objw.SymPtr(sym, off, fsym, 0) // data string
|
off = objw.SymPtr(sym, off, fsym, 0) // data string
|
||||||
off = objw.Uintptr(sym, off, uint64(size)) // len
|
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)
|
objw.Global(slicedata, int32(off), obj.RODATA|obj.LOCAL)
|
||||||
sym := v.Sym().Linksym()
|
sym := v.Linksym()
|
||||||
objw.SymPtr(sym, 0, slicedata, 0)
|
objw.SymPtr(sym, 0, slicedata, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,15 +78,12 @@ func (s *Schedule) tryStaticInit(nn ir.Node) bool {
|
|||||||
// like staticassign but we are copying an already
|
// like staticassign but we are copying an already
|
||||||
// initialized value r.
|
// initialized value r.
|
||||||
func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Type) bool {
|
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 }
|
// TODO if roff != 0 { panic }
|
||||||
staticdata.InitFunc(l, loff, rn)
|
staticdata.InitFunc(l, loff, rn)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if rn.Class_ != ir.PEXTERN || rn.Sym().Pkg != types.LocalPkg {
|
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
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if rn.Defn.Op() != ir.OAS {
|
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)
|
if rn.Type().IsString() { // perhaps overwritten by cmd/link -X (#34675)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if rn.Embed != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
orig := rn
|
orig := rn
|
||||||
r := rn.Defn.(*ir.AssignStmt).Y
|
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) {
|
for r.Op() == ir.OCONVNOP && !types.Identical(r.Type(), typ) {
|
||||||
r = r.(*ir.ConvExpr).X
|
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() {
|
switch r.Op() {
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
r = r.(*ir.MethodExpr).FuncName()
|
r = r.(*ir.SelectorExpr).FuncName()
|
||||||
fallthrough
|
fallthrough
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
r := r.(*ir.Name)
|
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
|
x := e.Expr
|
||||||
if x.Op() == ir.OMETHEXPR {
|
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) {
|
if x.Op() == ir.ONAME && s.staticcopy(l, loff+e.Xoffset, x.(*ir.Name), typ) {
|
||||||
continue
|
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 {
|
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 {
|
for r.Op() == ir.OCONVNOP {
|
||||||
r = r.(*ir.ConvExpr).X
|
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)
|
return s.staticcopy(l, loff, r, typ)
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
r := r.(*ir.MethodExpr)
|
r := r.(*ir.SelectorExpr)
|
||||||
return s.staticcopy(l, loff, r.FuncName(), typ)
|
return s.staticcopy(l, loff, r.FuncName(), typ)
|
||||||
|
|
||||||
case ir.ONIL:
|
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:
|
case ir.OSTR2BYTES:
|
||||||
r := r.(*ir.ConvExpr)
|
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)
|
sval := ir.StringVal(r.X)
|
||||||
staticdata.InitSliceBytes(l, loff, sval)
|
staticdata.InitSliceBytes(l, loff, sval)
|
||||||
return true
|
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
|
return val.Op() == ir.ONIL
|
||||||
}
|
}
|
||||||
|
|
||||||
reflectdata.MarkTypeUsedInInterface(val.Type(), l.Sym().Linksym())
|
reflectdata.MarkTypeUsedInInterface(val.Type(), l.Linksym())
|
||||||
|
|
||||||
var itab *ir.AddrExpr
|
var itab *ir.AddrExpr
|
||||||
if typ.IsEmptyInterface() {
|
if typ.IsEmptyInterface() {
|
||||||
@ -445,7 +455,7 @@ func StaticName(t *types.Type) *ir.Name {
|
|||||||
statuniqgen++
|
statuniqgen++
|
||||||
typecheck.Declare(n, ir.PEXTERN)
|
typecheck.Declare(n, ir.PEXTERN)
|
||||||
n.SetType(t)
|
n.SetType(t)
|
||||||
n.Sym().Linksym().Set(obj.AttrLocal, true)
|
n.Linksym().Set(obj.AttrLocal, true)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,7 +471,7 @@ func StaticLoc(n ir.Node) (name *ir.Name, offset int64, ok bool) {
|
|||||||
return n, 0, true
|
return n, 0, true
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
n := n.(*ir.MethodExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
return StaticLoc(n.FuncName())
|
return StaticLoc(n.FuncName())
|
||||||
|
|
||||||
case ir.ODOT:
|
case ir.ODOT:
|
||||||
|
@ -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
|
package syntax
|
||||||
|
|
||||||
import "strconv"
|
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 = ":!<-||&&==!=<<=>>=+-|^*/%&&^<<>>"
|
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}
|
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}
|
||||||
|
@ -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
|
package syntax
|
||||||
|
|
||||||
import "strconv"
|
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"
|
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}
|
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}
|
||||||
|
@ -6,7 +6,7 @@ package syntax
|
|||||||
|
|
||||||
type token uint
|
type token uint
|
||||||
|
|
||||||
//go:generate stringer -type token -linecomment
|
//go:generate stringer -type token -linecomment tokens.go
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_ token = iota
|
_ token = iota
|
||||||
@ -105,7 +105,7 @@ const (
|
|||||||
|
|
||||||
type Operator uint
|
type Operator uint
|
||||||
|
|
||||||
//go:generate stringer -type Operator -linecomment
|
//go:generate stringer -type Operator -linecomment tokens.go
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_ Operator = iota
|
_ Operator = iota
|
||||||
|
@ -509,7 +509,7 @@ func EvalConst(n ir.Node) ir.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nl := ir.Copy(n).(*ir.AddStringExpr)
|
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, ""))))
|
newList = append(newList, OrigConst(nl, constant.MakeString(strings.Join(strs, ""))))
|
||||||
i = i2 - 1
|
i = i2 - 1
|
||||||
} else {
|
} else {
|
||||||
@ -518,7 +518,7 @@ func EvalConst(n ir.Node) ir.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nn := ir.Copy(n).(*ir.AddStringExpr)
|
nn := ir.Copy(n).(*ir.AddStringExpr)
|
||||||
nn.List.Set(newList)
|
nn.List = newList
|
||||||
return nn
|
return nn
|
||||||
|
|
||||||
case ir.OCAP, ir.OLEN:
|
case ir.OCAP, ir.OLEN:
|
||||||
@ -564,20 +564,11 @@ func EvalConst(n ir.Node) ir.Node {
|
|||||||
return n
|
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 {
|
func makeFloat64(f float64) constant.Value {
|
||||||
if math.IsInf(f, 0) {
|
if math.IsInf(f, 0) {
|
||||||
base.Fatalf("infinity is not a valid constant")
|
base.Fatalf("infinity is not a valid constant")
|
||||||
}
|
}
|
||||||
v := constant.MakeFloat64(f)
|
return constant.MakeFloat64(f)
|
||||||
v = constant.ToFloat(v) // workaround #42641 (MakeFloat64(0).Kind() returns Int, not Float)
|
|
||||||
return v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeComplex(real, imag constant.Value) constant.Value {
|
func makeComplex(real, imag constant.Value) constant.Value {
|
||||||
|
@ -15,64 +15,7 @@ import (
|
|||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DeclContext ir.Class // PEXTERN/PAUTO
|
var DeclContext ir.Class = ir.PEXTERN // 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
|
|
||||||
}
|
|
||||||
|
|
||||||
func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
|
func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
|
||||||
if tfn.Op() != ir.OTFUNC {
|
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 := 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.Defn = fn
|
||||||
fn.Nname.Ntype = tfn
|
fn.Nname.Ntype = tfn
|
||||||
ir.MarkFunc(fn.Nname)
|
ir.MarkFunc(fn.Nname)
|
||||||
@ -89,60 +33,6 @@ func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
|
|||||||
return fn
|
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
|
// Declare records that Node n declares symbol n.Sym in the specified
|
||||||
// declaration context.
|
// declaration context.
|
||||||
func Declare(n *ir.Name, ctxt ir.Class) {
|
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.Lastlineno = base.Pos
|
||||||
s.Def = n
|
s.Def = n
|
||||||
n.Vargen = int32(gen)
|
n.Vargen = int32(gen)
|
||||||
n.Class_ = ctxt
|
n.Class = ctxt
|
||||||
if ctxt == ir.PFUNC {
|
if ctxt == ir.PFUNC {
|
||||||
n.Sym().SetFunc(true)
|
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)
|
n := ir.NewNameAt(pos, s)
|
||||||
s.Def = n
|
s.Def = n
|
||||||
n.SetType(t)
|
n.SetType(t)
|
||||||
n.Class_ = ir.PAUTO
|
n.Class = ir.PAUTO
|
||||||
n.SetEsc(ir.EscNever)
|
n.SetEsc(ir.EscNever)
|
||||||
n.Curfn = curfn
|
n.Curfn = curfn
|
||||||
n.SetUsed(true)
|
n.SetUsed(true)
|
||||||
@ -596,6 +486,9 @@ func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
|
|||||||
nrecvs++
|
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())
|
params := make([]*types.Field, nrecvs+sig.Params().Fields().Len())
|
||||||
if recv != nil {
|
if recv != nil {
|
||||||
params[0] = types.NewField(base.Pos, nil, recv)
|
params[0] = types.NewField(base.Pos, nil, recv)
|
||||||
|
@ -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
|
// ipkg is the package being imported
|
||||||
func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
|
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)
|
n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t)
|
||||||
|
n.Func = ir.NewFunc(pos)
|
||||||
fn := ir.NewFunc(pos)
|
n.Func.Nname = n
|
||||||
fn.SetType(t)
|
|
||||||
n.SetFunc(fn)
|
|
||||||
fn.Nname = n
|
|
||||||
|
|
||||||
return 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 := 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.SetPkgDef(n)
|
||||||
s.Importdef = ipkg
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,14 +35,6 @@ func tcAddr(n *ir.AddrExpr) ir.Node {
|
|||||||
if ir.Orig(r) != r {
|
if ir.Orig(r) != r {
|
||||||
base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
|
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)
|
n.X = DefaultLit(n.X, nil)
|
||||||
if n.X.Type() == nil {
|
if n.X.Type() == nil {
|
||||||
@ -55,103 +47,50 @@ func tcAddr(n *ir.AddrExpr) ir.Node {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// tcArith typechecks a binary arithmetic expression.
|
func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) {
|
||||||
func tcArith(n ir.Node) ir.Node {
|
if l.Type() == nil || l.Type() == nil {
|
||||||
var l, r ir.Node
|
return l, r, nil
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For "x == x && len(s)", it's better to report that "len(s)" (type int)
|
r = DefaultLit(r, types.Types[types.TUINT])
|
||||||
// can't be used with "&&" than to report that "x == x" (type untyped bool)
|
t := r.Type()
|
||||||
// can't be converted to int (see issue #41500).
|
if !t.IsInteger() {
|
||||||
if n.Op() == ir.OANDAND || n.Op() == ir.OOROR {
|
base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
|
||||||
n := n.(*ir.LogicalExpr)
|
return l, r, nil
|
||||||
if !n.X.Type().IsBoolean() {
|
}
|
||||||
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.X.Type()))
|
if t.IsSigned() && !types.AllowsGoVersion(curpkg(), 1, 13) {
|
||||||
n.SetType(nil)
|
base.ErrorfVers("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type())
|
||||||
return n
|
return l, r, nil
|
||||||
}
|
}
|
||||||
if !n.Y.Type().IsBoolean() {
|
t = l.Type()
|
||||||
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Y.Type()))
|
if t != nil && t.Kind() != types.TIDEAL && !t.IsInteger() {
|
||||||
n.SetType(nil)
|
base.Errorf("invalid operation: %v (shift of type %v)", n, t)
|
||||||
return n
|
return l, r, nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ideal mixed with non-ideal
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
l, r = defaultlit2(l, r, false)
|
||||||
setLR()
|
|
||||||
|
|
||||||
if l.Type() == nil || r.Type() == nil {
|
if l.Type() == nil || r.Type() == nil {
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
t := l.Type()
|
t := l.Type()
|
||||||
if t.Kind() == types.TIDEAL {
|
if t.Kind() == types.TIDEAL {
|
||||||
t = r.Type()
|
t = r.Type()
|
||||||
}
|
}
|
||||||
et := t.Kind()
|
|
||||||
if et == types.TIDEAL {
|
|
||||||
et = types.TINT
|
|
||||||
}
|
|
||||||
aop := ir.OXXX
|
aop := ir.OXXX
|
||||||
if iscmp[n.Op()] && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
|
if iscmp[n.Op()] && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
|
||||||
// comparison is okay as long as one side is
|
// 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 aop != ir.OXXX {
|
||||||
if r.Type().IsInterface() && !l.Type().IsInterface() && !types.IsComparable(l.Type()) {
|
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()))
|
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type()))
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
types.CalcSize(l.Type())
|
types.CalcSize(l.Type())
|
||||||
if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
|
if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
|
||||||
l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
|
l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
|
||||||
l.SetTypecheck(1)
|
l.SetTypecheck(1)
|
||||||
setLR()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t = r.Type()
|
t = r.Type()
|
||||||
@ -188,34 +125,28 @@ func tcArith(n ir.Node) ir.Node {
|
|||||||
if aop != ir.OXXX {
|
if aop != ir.OXXX {
|
||||||
if l.Type().IsInterface() && !r.Type().IsInterface() && !types.IsComparable(r.Type()) {
|
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()))
|
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type()))
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
types.CalcSize(r.Type())
|
types.CalcSize(r.Type())
|
||||||
if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
|
if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
|
||||||
r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
|
r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
|
||||||
r.SetTypecheck(1)
|
r.SetTypecheck(1)
|
||||||
setLR()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t = l.Type()
|
t = l.Type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
et = t.Kind()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
|
if t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
|
||||||
l, r = defaultlit2(l, r, true)
|
l, r = defaultlit2(l, r, true)
|
||||||
if l.Type() == nil || r.Type() == nil {
|
if l.Type() == nil || r.Type() == nil {
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
if l.Type().IsInterface() == r.Type().IsInterface() || aop == 0 {
|
if l.Type().IsInterface() == r.Type().IsInterface() || aop == 0 {
|
||||||
base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
|
base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,85 +155,46 @@ func tcArith(n ir.Node) ir.Node {
|
|||||||
}
|
}
|
||||||
if dt := defaultType(t); !okfor[op][dt.Kind()] {
|
if dt := defaultType(t); !okfor[op][dt.Kind()] {
|
||||||
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
|
base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// okfor allows any array == array, map == map, func == func.
|
// okfor allows any array == array, map == map, func == func.
|
||||||
// restrict to slice/map/func == nil and nil == slice/map/func.
|
// restrict to slice/map/func == nil and nil == slice/map/func.
|
||||||
if l.Type().IsArray() && !types.IsComparable(l.Type()) {
|
if l.Type().IsArray() && !types.IsComparable(l.Type()) {
|
||||||
base.Errorf("invalid operation: %v (%v cannot be compared)", n, l.Type())
|
base.Errorf("invalid operation: %v (%v cannot be compared)", n, l.Type())
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.Type().IsSlice() && !ir.IsNil(l) && !ir.IsNil(r) {
|
if l.Type().IsSlice() && !ir.IsNil(l) && !ir.IsNil(r) {
|
||||||
base.Errorf("invalid operation: %v (slice can only be compared to nil)", n)
|
base.Errorf("invalid operation: %v (slice can only be compared to nil)", n)
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.Type().IsMap() && !ir.IsNil(l) && !ir.IsNil(r) {
|
if l.Type().IsMap() && !ir.IsNil(l) && !ir.IsNil(r) {
|
||||||
base.Errorf("invalid operation: %v (map can only be compared to nil)", n)
|
base.Errorf("invalid operation: %v (map can only be compared to nil)", n)
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.Type().Kind() == types.TFUNC && !ir.IsNil(l) && !ir.IsNil(r) {
|
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)
|
base.Errorf("invalid operation: %v (func can only be compared to nil)", n)
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.Type().IsStruct() {
|
if l.Type().IsStruct() {
|
||||||
if f := types.IncomparableField(l.Type()); f != nil {
|
if f := types.IncomparableField(l.Type()); f != nil {
|
||||||
base.Errorf("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
|
base.Errorf("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
|
||||||
n.SetType(nil)
|
return l, r, 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)
|
|
||||||
}
|
|
||||||
add.SetType(t)
|
|
||||||
return add
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
|
if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
|
||||||
if constant.Sign(r.Val()) == 0 {
|
if constant.Sign(r.Val()) == 0 {
|
||||||
base.Errorf("division by zero")
|
base.Errorf("division by zero")
|
||||||
n.SetType(nil)
|
return l, r, nil
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n.SetType(t)
|
return l, r, t
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The result of tcCompLit MUST be assigned back to n, e.g.
|
// 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.
|
// Need to handle [...]T arrays specially.
|
||||||
if array, ok := n.Ntype.(*ir.ArrayType); ok && array.Elem != nil && array.Len == nil {
|
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()
|
elemType := array.Elem.Type()
|
||||||
if elemType == nil {
|
if elemType == nil {
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
@ -343,7 +235,7 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Ntype = ir.Node(typecheck(n.Ntype, ctxType)).(ir.Ntype)
|
n.Ntype = typecheckNtype(n.Ntype)
|
||||||
t := n.Ntype.Type()
|
t := n.Ntype.Type()
|
||||||
if t == nil {
|
if t == nil {
|
||||||
n.SetType(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 {
|
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
|
||||||
// Create top-level function.
|
n.SetOp(ir.OCALLPART)
|
||||||
fn := makepartialcall(n)
|
n.SetType(MethodValueWrapper(n).Type())
|
||||||
|
|
||||||
return ir.NewCallPartExpr(n.Pos(), n.X, n.Selection, fn)
|
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
@ -651,7 +541,7 @@ func tcDotType(n *ir.TypeAssertExpr) ir.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n.Ntype != nil {
|
if n.Ntype != nil {
|
||||||
n.Ntype = typecheck(n.Ntype, ctxType)
|
n.Ntype = typecheckNtype(n.Ntype)
|
||||||
n.SetType(n.Ntype.Type())
|
n.SetType(n.Ntype.Type())
|
||||||
n.Ntype = nil
|
n.Ntype = nil
|
||||||
if n.Type() == nil {
|
if n.Type() == nil {
|
||||||
|
@ -21,7 +21,7 @@ func MakeDotArgs(typ *types.Type, args []ir.Node) ir.Node {
|
|||||||
n = NodNil()
|
n = NodNil()
|
||||||
n.SetType(typ)
|
n.SetType(typ)
|
||||||
} else {
|
} 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.List.Append(args...)
|
||||||
lit.SetImplicit(true)
|
lit.SetImplicit(true)
|
||||||
n = lit
|
n = lit
|
||||||
@ -52,7 +52,7 @@ func FixVariadicCall(call *ir.CallExpr) {
|
|||||||
extra[i] = nil // allow GC
|
extra[i] = nil // allow GC
|
||||||
}
|
}
|
||||||
|
|
||||||
call.Args.Set(append(args[:vi], slice))
|
call.Args = append(args[:vi], slice)
|
||||||
call.IsDDD = true
|
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
|
// PartialCallType returns the struct type used to hold all the information
|
||||||
// needed in the closure for n (n must be a OCALLPART node).
|
// 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.
|
// 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{
|
t := types.NewStruct(types.NoPkg, []*types.Field{
|
||||||
types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
|
types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
|
||||||
types.NewField(base.Pos, Lookup("R"), n.X.Type()),
|
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
|
// We use value capturing for values <= 128 bytes that are never reassigned
|
||||||
// after capturing (effectively constant).
|
// after capturing (effectively constant).
|
||||||
func CaptureVars(fn *ir.Func) {
|
func CaptureVars(fn *ir.Func) {
|
||||||
lno := base.Pos
|
for _, v := range fn.ClosureVars {
|
||||||
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
|
|
||||||
outermost := v.Defn.(*ir.Name)
|
outermost := v.Defn.(*ir.Name)
|
||||||
|
|
||||||
// out parameters will be assigned to implicitly upon return.
|
// out parameters will be assigned to implicitly upon return.
|
||||||
if outermost.Class_ != ir.PPARAMOUT && !outermost.Name().Addrtaken() && !outermost.Name().Assigned() && v.Type().Width <= 128 {
|
if outermost.Class != ir.PPARAMOUT && !outermost.Addrtaken() && !outermost.Assigned() && outermost.Type().Size() <= 128 {
|
||||||
v.SetByval(true)
|
outermost.SetByval(true)
|
||||||
} else {
|
} else {
|
||||||
outermost.Name().SetAddrtaken(true)
|
outermost.SetAddrtaken(true)
|
||||||
outer = NodAddr(outer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if base.Flag.LowerM > 1 {
|
if base.Flag.LowerM > 1 {
|
||||||
var name *types.Sym
|
|
||||||
if v.Curfn != nil && v.Curfn.Nname != nil {
|
|
||||||
name = v.Curfn.Sym()
|
|
||||||
}
|
|
||||||
how := "ref"
|
how := "ref"
|
||||||
if v.Byval() {
|
if v.Byval() {
|
||||||
how = "value"
|
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
|
// 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) {
|
func ImportedBody(fn *ir.Func) {
|
||||||
lno := ir.SetPos(fn.Nname)
|
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)
|
ImportBody(fn)
|
||||||
|
|
||||||
// typecheckinl is only for imported functions;
|
// 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.
|
// globClosgen is like Func.Closgen, but for the global scope.
|
||||||
var globClosgen int32
|
var globClosgen int32
|
||||||
|
|
||||||
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
|
// MethodValueWrapper returns the DCLFUNC node representing the
|
||||||
// for partial calls.
|
// wrapper function (*-fm) needed for the given method value. If the
|
||||||
func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
|
// 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()
|
t0 := dot.Type()
|
||||||
meth := dot.Sel
|
meth := dot.Sel
|
||||||
rcvrtype := dot.X.Type()
|
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 := 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()
|
call.IsDDD = tfn.Type().IsVariadic()
|
||||||
if t0.NumResults() != 0 {
|
if t0.NumResults() != 0 {
|
||||||
ret := ir.NewReturnStmt(base.Pos, nil)
|
ret := ir.NewReturnStmt(base.Pos, nil)
|
||||||
@ -306,7 +297,7 @@ func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
|
|||||||
body = append(body, call)
|
body = append(body, call)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn.Body.Set(body)
|
fn.Body = body
|
||||||
FinishFuncBody()
|
FinishFuncBody()
|
||||||
|
|
||||||
Func(fn)
|
Func(fn)
|
||||||
@ -334,7 +325,7 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
|
|||||||
fn.Iota = x
|
fn.Iota = x
|
||||||
}
|
}
|
||||||
|
|
||||||
fn.ClosureType = typecheck(fn.ClosureType, ctxType)
|
fn.ClosureType = typecheckNtype(fn.ClosureType)
|
||||||
clo.SetType(fn.ClosureType.Type())
|
clo.SetType(fn.ClosureType.Type())
|
||||||
fn.SetClosureCalled(top&ctxCallee != 0)
|
fn.SetClosureCalled(top&ctxCallee != 0)
|
||||||
|
|
||||||
@ -379,6 +370,25 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
|
|||||||
ir.CurFunc = oldfn
|
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)
|
Target.Decls = append(Target.Decls, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +401,7 @@ func tcFunc(n *ir.Func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, ln := range n.Dcl {
|
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
|
ln.Decldepth = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,7 +411,6 @@ func tcFunc(n *ir.Func) {
|
|||||||
if t == nil {
|
if t == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
n.SetType(t)
|
|
||||||
rcvr := t.Recv()
|
rcvr := t.Recv()
|
||||||
if rcvr != nil && n.Shortname != nil {
|
if rcvr != nil && n.Shortname != nil {
|
||||||
m := addmethod(n, n.Shortname, t, true, n.Pragma&ir.Nointerface != 0)
|
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
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Args.Set(nil)
|
n.Args = nil
|
||||||
l := args[0]
|
l := args[0]
|
||||||
l = typecheck(l, ctxType)
|
l = typecheck(l, ctxType)
|
||||||
t := l.Type()
|
t := l.Type()
|
||||||
|
@ -430,7 +430,7 @@ func (p *iexporter) doDecl(n *ir.Name) {
|
|||||||
|
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
switch n.Class_ {
|
switch n.Class {
|
||||||
case ir.PEXTERN:
|
case ir.PEXTERN:
|
||||||
// Variable.
|
// Variable.
|
||||||
w.tag('V')
|
w.tag('V')
|
||||||
@ -450,7 +450,7 @@ func (p *iexporter) doDecl(n *ir.Name) {
|
|||||||
w.funcExt(n)
|
w.funcExt(n)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
base.Fatalf("unexpected class: %v, %v", n, n.Class_)
|
base.Fatalf("unexpected class: %v, %v", n, n.Class)
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OLITERAL:
|
case ir.OLITERAL:
|
||||||
@ -574,6 +574,11 @@ func (w *exportWriter) pos(pos src.XPos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *exportWriter) pkg(pkg *types.Pkg) {
|
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.
|
// Ensure any referenced packages are declared in the main index.
|
||||||
w.p.allPkgs[pkg] = true
|
w.p.allPkgs[pkg] = true
|
||||||
|
|
||||||
@ -936,7 +941,7 @@ func (w *exportWriter) mpfloat(v constant.Value, typ *types.Type) {
|
|||||||
if acc != big.Exact {
|
if acc != big.Exact {
|
||||||
base.Fatalf("mantissa scaling failed for %f (%s)", f, acc)
|
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 {
|
if manti.Sign() != 0 {
|
||||||
w.int64(exp)
|
w.int64(exp)
|
||||||
}
|
}
|
||||||
@ -1067,7 +1072,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
|||||||
n := n.(*ir.Decl)
|
n := n.(*ir.Decl)
|
||||||
w.op(ir.ODCL)
|
w.op(ir.ODCL)
|
||||||
w.pos(n.X.Pos())
|
w.pos(n.X.Pos())
|
||||||
w.localName(n.X.(*ir.Name))
|
w.localName(n.X)
|
||||||
w.typ(n.X.Type())
|
w.typ(n.X.Type())
|
||||||
|
|
||||||
case ir.OAS:
|
case ir.OAS:
|
||||||
@ -1187,7 +1192,7 @@ func (w *exportWriter) caseList(cases []*ir.CaseClause, namedTypeSwitch bool) {
|
|||||||
w.pos(cas.Pos())
|
w.pos(cas.Pos())
|
||||||
w.stmtList(cas.List)
|
w.stmtList(cas.List)
|
||||||
if namedTypeSwitch {
|
if namedTypeSwitch {
|
||||||
w.localName(cas.Var.(*ir.Name))
|
w.localName(cas.Var)
|
||||||
}
|
}
|
||||||
w.stmtList(cas.Body)
|
w.stmtList(cas.Body)
|
||||||
}
|
}
|
||||||
@ -1252,21 +1257,10 @@ func (w *exportWriter) expr(n ir.Node) {
|
|||||||
w.pos(n.Pos())
|
w.pos(n.Pos())
|
||||||
w.value(n.Type(), n.Val())
|
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:
|
case ir.ONAME:
|
||||||
// Package scope name.
|
// Package scope name.
|
||||||
n := n.(*ir.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.op(ir.ONONAME)
|
||||||
w.qualifiedIdent(n)
|
w.qualifiedIdent(n)
|
||||||
break
|
break
|
||||||
@ -1336,15 +1330,7 @@ func (w *exportWriter) expr(n ir.Node) {
|
|||||||
// case OSTRUCTKEY:
|
// case OSTRUCTKEY:
|
||||||
// unreachable - handled in case OSTRUCTLIT by elemList
|
// unreachable - handled in case OSTRUCTLIT by elemList
|
||||||
|
|
||||||
case ir.OCALLPART:
|
case ir.OXDOT, ir.ODOT, ir.ODOTPTR, ir.ODOTINTER, ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
|
||||||
// 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:
|
|
||||||
n := n.(*ir.SelectorExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
w.op(ir.OXDOT)
|
w.op(ir.OXDOT)
|
||||||
w.pos(n.Pos())
|
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
|
// PPARAM/PPARAMOUT, because we only want to include vargen in
|
||||||
// non-param names.
|
// non-param names.
|
||||||
var v int32
|
var v int32
|
||||||
if n.Class_ == ir.PAUTO || (n.Class_ == ir.PAUTOHEAP && n.Name().Stackcopy == nil) {
|
if n.Class == ir.PAUTO || (n.Class == ir.PAUTOHEAP && n.Stackcopy == nil) {
|
||||||
v = n.Name().Vargen
|
v = n.Vargen
|
||||||
}
|
}
|
||||||
|
|
||||||
w.localIdent(n.Sym(), v)
|
w.localIdent(n.Sym(), v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *exportWriter) localIdent(s *types.Sym, v int32) {
|
func (w *exportWriter) localIdent(s *types.Sym, v int32) {
|
||||||
|
if w.currPkg == nil {
|
||||||
|
base.Fatalf("missing currPkg")
|
||||||
|
}
|
||||||
|
|
||||||
// Anonymous parameters.
|
// Anonymous parameters.
|
||||||
if s == nil {
|
if s == nil {
|
||||||
w.string("")
|
w.string("")
|
||||||
@ -1572,8 +1562,8 @@ func (w *exportWriter) localIdent(s *types.Sym, v int32) {
|
|||||||
name = fmt.Sprintf("%s·%d", name, v)
|
name = fmt.Sprintf("%s·%d", name, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !types.IsExported(name) && s.Pkg != w.currPkg {
|
if s.Pkg != w.currPkg {
|
||||||
base.Fatalf("weird package in name: %v => %v, not %q", s, name, w.currPkg.Path)
|
base.Fatalf("weird package in name: %v => %v from %q, not %q", s, name, s.Pkg.Path, w.currPkg.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.string(name)
|
w.string(name)
|
||||||
|
@ -327,16 +327,17 @@ func (r *importReader) doDecl(sym *types.Sym) *ir.Name {
|
|||||||
ms := make([]*types.Field, r.uint64())
|
ms := make([]*types.Field, r.uint64())
|
||||||
for i := range ms {
|
for i := range ms {
|
||||||
mpos := r.pos()
|
mpos := r.pos()
|
||||||
msym := r.ident()
|
msym := r.selector()
|
||||||
recv := r.param()
|
recv := r.param()
|
||||||
mtyp := r.signature(recv)
|
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.
|
// 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 := types.NewField(mpos, msym, mtyp)
|
||||||
f.Nname = m
|
f.Nname = m
|
||||||
@ -372,7 +373,7 @@ func (p *importReader) value(typ *types.Type) constant.Value {
|
|||||||
case constant.Int:
|
case constant.Int:
|
||||||
var i big.Int
|
var i big.Int
|
||||||
p.mpint(&i, typ)
|
p.mpint(&i, typ)
|
||||||
return makeInt(&i)
|
return constant.Make(&i)
|
||||||
case constant.Float:
|
case constant.Float:
|
||||||
return p.float(typ)
|
return p.float(typ)
|
||||||
case constant.Complex:
|
case constant.Complex:
|
||||||
@ -433,18 +434,21 @@ func (p *importReader) float(typ *types.Type) constant.Value {
|
|||||||
return constant.Make(&f)
|
return constant.Make(&f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *importReader) ident() *types.Sym {
|
func (r *importReader) ident(selector bool) *types.Sym {
|
||||||
name := r.string()
|
name := r.string()
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
pkg := r.currPkg
|
pkg := r.currPkg
|
||||||
if types.IsExported(name) {
|
if selector && types.IsExported(name) {
|
||||||
pkg = types.LocalPkg
|
pkg = types.LocalPkg
|
||||||
}
|
}
|
||||||
return pkg.Lookup(name)
|
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 {
|
func (r *importReader) qualifiedIdent() *ir.Ident {
|
||||||
name := r.string()
|
name := r.string()
|
||||||
pkg := r.pkg()
|
pkg := r.pkg()
|
||||||
@ -533,7 +537,7 @@ func (r *importReader) typ1() *types.Type {
|
|||||||
fs := make([]*types.Field, r.uint64())
|
fs := make([]*types.Field, r.uint64())
|
||||||
for i := range fs {
|
for i := range fs {
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
sym := r.ident()
|
sym := r.selector()
|
||||||
typ := r.typ()
|
typ := r.typ()
|
||||||
emb := r.bool()
|
emb := r.bool()
|
||||||
note := r.string()
|
note := r.string()
|
||||||
@ -562,7 +566,7 @@ func (r *importReader) typ1() *types.Type {
|
|||||||
methods := make([]*types.Field, r.uint64())
|
methods := make([]*types.Field, r.uint64())
|
||||||
for i := range methods {
|
for i := range methods {
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
sym := r.ident()
|
sym := r.selector()
|
||||||
typ := r.signature(fakeRecvField())
|
typ := r.signature(fakeRecvField())
|
||||||
|
|
||||||
methods[i] = types.NewField(pos, sym, typ)
|
methods[i] = types.NewField(pos, sym, typ)
|
||||||
@ -598,7 +602,7 @@ func (r *importReader) paramList() []*types.Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *importReader) param() *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 {
|
func (r *importReader) bool() bool {
|
||||||
@ -778,17 +782,17 @@ func (r *importReader) caseList(switchExpr ir.Node) []*ir.CaseClause {
|
|||||||
cases := make([]*ir.CaseClause, r.uint64())
|
cases := make([]*ir.CaseClause, r.uint64())
|
||||||
for i := range cases {
|
for i := range cases {
|
||||||
cas := ir.NewCaseStmt(r.pos(), nil, nil)
|
cas := ir.NewCaseStmt(r.pos(), nil, nil)
|
||||||
cas.List.Set(r.stmtList())
|
cas.List = r.stmtList()
|
||||||
if namedTypeSwitch {
|
if namedTypeSwitch {
|
||||||
// Note: per-case variables will have distinct, dotted
|
// Note: per-case variables will have distinct, dotted
|
||||||
// names after import. That's okay: swt.go only needs
|
// names after import. That's okay: swt.go only needs
|
||||||
// Sym for diagnostics anyway.
|
// Sym for diagnostics anyway.
|
||||||
caseVar := ir.NewNameAt(cas.Pos(), r.ident())
|
caseVar := ir.NewNameAt(cas.Pos(), r.localIdent())
|
||||||
Declare(caseVar, DeclContext)
|
Declare(caseVar, DeclContext)
|
||||||
cas.Var = caseVar
|
cas.Var = caseVar
|
||||||
caseVar.Defn = switchExpr
|
caseVar.Defn = switchExpr
|
||||||
}
|
}
|
||||||
cas.Body.Set(r.stmtList())
|
cas.Body = r.stmtList()
|
||||||
cases[i] = cas
|
cases[i] = cas
|
||||||
}
|
}
|
||||||
return cases
|
return cases
|
||||||
@ -850,7 +854,7 @@ func (r *importReader) node() ir.Node {
|
|||||||
return r.qualifiedIdent()
|
return r.qualifiedIdent()
|
||||||
|
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
return r.ident().Def.(*ir.Name)
|
return r.localIdent().Def.(*ir.Name)
|
||||||
|
|
||||||
// case OPACK, ONONAME:
|
// case OPACK, ONONAME:
|
||||||
// unreachable - should have been resolved by typechecking
|
// unreachable - should have been resolved by typechecking
|
||||||
@ -861,7 +865,7 @@ func (r *importReader) node() ir.Node {
|
|||||||
case ir.OTYPESW:
|
case ir.OTYPESW:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
var tag *ir.Ident
|
var tag *ir.Ident
|
||||||
if s := r.ident(); s != nil {
|
if s := r.localIdent(); s != nil {
|
||||||
tag = ir.NewIdent(pos, s)
|
tag = ir.NewIdent(pos, s)
|
||||||
}
|
}
|
||||||
return ir.NewTypeSwitchGuard(pos, tag, r.expr())
|
return ir.NewTypeSwitchGuard(pos, tag, r.expr())
|
||||||
@ -898,7 +902,7 @@ func (r *importReader) node() ir.Node {
|
|||||||
|
|
||||||
case ir.OXDOT:
|
case ir.OXDOT:
|
||||||
// see parser.new_dotname
|
// 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:
|
// case ODOTTYPE, ODOTTYPE2:
|
||||||
// unreachable - mapped to case ODOTTYPE below by exporter
|
// 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:
|
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 := builtinCall(r.pos(), op)
|
||||||
n.Args.Set(r.exprList())
|
n.Args = r.exprList()
|
||||||
if op == ir.OAPPEND {
|
if op == ir.OAPPEND {
|
||||||
n.IsDDD = r.bool()
|
n.IsDDD = r.bool()
|
||||||
}
|
}
|
||||||
@ -944,7 +948,7 @@ func (r *importReader) node() ir.Node {
|
|||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
init := r.stmtList()
|
init := r.stmtList()
|
||||||
n := ir.NewCallExpr(pos, ir.OCALL, r.expr(), r.exprList())
|
n := ir.NewCallExpr(pos, ir.OCALL, r.expr(), r.exprList())
|
||||||
n.PtrInit().Set(init)
|
*n.PtrInit() = init
|
||||||
n.IsDDD = r.bool()
|
n.IsDDD = r.bool()
|
||||||
return n
|
return n
|
||||||
|
|
||||||
@ -988,7 +992,7 @@ func (r *importReader) node() ir.Node {
|
|||||||
// statements
|
// statements
|
||||||
case ir.ODCL:
|
case ir.ODCL:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
lhs := ir.NewDeclNameAt(pos, ir.ONAME, r.ident())
|
lhs := ir.NewDeclNameAt(pos, ir.ONAME, r.localIdent())
|
||||||
lhs.SetType(r.typ())
|
lhs.SetType(r.typ())
|
||||||
|
|
||||||
Declare(lhs, ir.PAUTO)
|
Declare(lhs, ir.PAUTO)
|
||||||
@ -1032,14 +1036,14 @@ func (r *importReader) node() ir.Node {
|
|||||||
case ir.OIF:
|
case ir.OIF:
|
||||||
pos, init := r.pos(), r.stmtList()
|
pos, init := r.pos(), r.stmtList()
|
||||||
n := ir.NewIfStmt(pos, r.expr(), r.stmtList(), r.stmtList())
|
n := ir.NewIfStmt(pos, r.expr(), r.stmtList(), r.stmtList())
|
||||||
n.PtrInit().Set(init)
|
*n.PtrInit() = init
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OFOR:
|
case ir.OFOR:
|
||||||
pos, init := r.pos(), r.stmtList()
|
pos, init := r.pos(), r.stmtList()
|
||||||
cond, post := r.exprsOrNil()
|
cond, post := r.exprsOrNil()
|
||||||
n := ir.NewForStmt(pos, nil, cond, post, r.stmtList())
|
n := ir.NewForStmt(pos, nil, cond, post, r.stmtList())
|
||||||
n.PtrInit().Set(init)
|
*n.PtrInit() = init
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.ORANGE:
|
case ir.ORANGE:
|
||||||
@ -1051,7 +1055,7 @@ func (r *importReader) node() ir.Node {
|
|||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
init := r.stmtList()
|
init := r.stmtList()
|
||||||
n := ir.NewSelectStmt(pos, r.commList())
|
n := ir.NewSelectStmt(pos, r.commList())
|
||||||
n.PtrInit().Set(init)
|
*n.PtrInit() = init
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OSWITCH:
|
case ir.OSWITCH:
|
||||||
@ -1059,7 +1063,7 @@ func (r *importReader) node() ir.Node {
|
|||||||
init := r.stmtList()
|
init := r.stmtList()
|
||||||
x, _ := r.exprsOrNil()
|
x, _ := r.exprsOrNil()
|
||||||
n := ir.NewSwitchStmt(pos, x, r.caseList(x))
|
n := ir.NewSwitchStmt(pos, x, r.caseList(x))
|
||||||
n.PtrInit().Set(init)
|
*n.PtrInit() = init
|
||||||
return n
|
return n
|
||||||
|
|
||||||
// case OCASE:
|
// case OCASE:
|
||||||
@ -1099,7 +1103,7 @@ func (r *importReader) op() ir.Op {
|
|||||||
func (r *importReader) fieldList() []ir.Node {
|
func (r *importReader) fieldList() []ir.Node {
|
||||||
list := make([]ir.Node, r.uint64())
|
list := make([]ir.Node, r.uint64())
|
||||||
for i := range list {
|
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
|
return list
|
||||||
}
|
}
|
||||||
|
@ -631,7 +631,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
|
|||||||
nvar := ncase.Var
|
nvar := ncase.Var
|
||||||
nvar.SetType(vt)
|
nvar.SetType(vt)
|
||||||
if vt != nil {
|
if vt != nil {
|
||||||
nvar = AssignExpr(nvar)
|
nvar = AssignExpr(nvar).(*ir.Name)
|
||||||
} else {
|
} else {
|
||||||
// Clause variable is broken; prevent typechecking.
|
// Clause variable is broken; prevent typechecking.
|
||||||
nvar.SetTypecheck(1)
|
nvar.SetTypecheck(1)
|
||||||
|
@ -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
|
// invent a name so that we can refer to it in the trampoline
|
||||||
s = LookupNum(".anon", gen)
|
s = LookupNum(".anon", gen)
|
||||||
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 := ir.NewField(base.Pos, s, nil, t.Type)
|
||||||
a.Pos = t.Pos
|
a.Pos = t.Pos
|
||||||
@ -67,9 +70,57 @@ func NodAddr(n ir.Node) *ir.AddrExpr {
|
|||||||
|
|
||||||
// nodAddrPos returns a node representing &n at position pos.
|
// nodAddrPos returns a node representing &n at position pos.
|
||||||
func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
|
func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
|
||||||
|
n = markAddrOf(n)
|
||||||
return ir.NewAddrExpr(pos, 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 {
|
func NodNil() ir.Node {
|
||||||
n := ir.NewNilExpr(base.Pos)
|
n := ir.NewNilExpr(base.Pos)
|
||||||
n.SetType(types.Types[types.TNIL])
|
n.SetType(types.Types[types.TNIL])
|
||||||
|
@ -26,12 +26,12 @@ func LookupRuntime(name string) *ir.Name {
|
|||||||
// The result of SubstArgTypes MUST be assigned back to old, e.g.
|
// The result of SubstArgTypes MUST be assigned back to old, e.g.
|
||||||
// n.Left = SubstArgTypes(n.Left, t1, t2)
|
// n.Left = SubstArgTypes(n.Left, t1, t2)
|
||||||
func SubstArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
|
func SubstArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
|
||||||
n := old.CloneName()
|
|
||||||
|
|
||||||
for _, t := range types_ {
|
for _, t := range types_ {
|
||||||
types.CalcSize(t)
|
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 {
|
if len(types_) > 0 {
|
||||||
base.Fatalf("substArgTypes: too many argument types")
|
base.Fatalf("substArgTypes: too many argument types")
|
||||||
}
|
}
|
||||||
@ -61,15 +61,13 @@ func Lookup(name string) *types.Sym {
|
|||||||
return types.LocalPkg.Lookup(name)
|
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,
|
// so that the compiler can generate calls to them,
|
||||||
// but does not make them visible to user code.
|
// but does not make them visible to user code.
|
||||||
func loadsys() {
|
func InitRuntime() {
|
||||||
|
base.Timer.Start("fe", "loadsys")
|
||||||
types.Block = 1
|
types.Block = 1
|
||||||
|
|
||||||
inimport = true
|
|
||||||
TypecheckAllowed = true
|
|
||||||
|
|
||||||
typs := runtimeTypes()
|
typs := runtimeTypes()
|
||||||
for _, d := range &runtimeDecls {
|
for _, d := range &runtimeDecls {
|
||||||
sym := ir.Pkgs.Runtime.Lookup(d.name)
|
sym := ir.Pkgs.Runtime.Lookup(d.name)
|
||||||
@ -83,9 +81,6 @@ func loadsys() {
|
|||||||
base.Fatalf("unhandled declaration tag %v", d.tag)
|
base.Fatalf("unhandled declaration tag %v", d.tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TypecheckAllowed = false
|
|
||||||
inimport = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupRuntimeFunc looks up Go function name in package runtime. This function
|
// LookupRuntimeFunc looks up Go function name in package runtime. This function
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
// tcArrayType typechecks an OTARRAY node.
|
// tcArrayType typechecks an OTARRAY node.
|
||||||
func tcArrayType(n *ir.ArrayType) ir.Node {
|
func tcArrayType(n *ir.ArrayType) ir.Node {
|
||||||
n.Elem = typecheck(n.Elem, ctxType)
|
n.Elem = typecheckNtype(n.Elem)
|
||||||
if n.Elem.Type() == nil {
|
if n.Elem.Type() == nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ func tcArrayType(n *ir.ArrayType) ir.Node {
|
|||||||
|
|
||||||
// tcChanType typechecks an OTCHAN node.
|
// tcChanType typechecks an OTCHAN node.
|
||||||
func tcChanType(n *ir.ChanType) ir.Node {
|
func tcChanType(n *ir.ChanType) ir.Node {
|
||||||
n.Elem = typecheck(n.Elem, ctxType)
|
n.Elem = typecheckNtype(n.Elem)
|
||||||
l := n.Elem
|
l := n.Elem
|
||||||
if l.Type() == nil {
|
if l.Type() == nil {
|
||||||
return n
|
return n
|
||||||
@ -103,7 +103,7 @@ func tcInterfaceType(n *ir.InterfaceType) ir.Node {
|
|||||||
n.SetOTYPE(types.Types[types.TINTER])
|
n.SetOTYPE(types.Types[types.TINTER])
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
lno := base.Pos
|
lno := base.Pos
|
||||||
methods := tcFields(n.Methods, nil)
|
methods := tcFields(n.Methods, nil)
|
||||||
base.Pos = lno
|
base.Pos = lno
|
||||||
@ -114,8 +114,8 @@ func tcInterfaceType(n *ir.InterfaceType) ir.Node {
|
|||||||
|
|
||||||
// tcMapType typechecks an OTMAP node.
|
// tcMapType typechecks an OTMAP node.
|
||||||
func tcMapType(n *ir.MapType) ir.Node {
|
func tcMapType(n *ir.MapType) ir.Node {
|
||||||
n.Key = typecheck(n.Key, ctxType)
|
n.Key = typecheckNtype(n.Key)
|
||||||
n.Elem = typecheck(n.Elem, ctxType)
|
n.Elem = typecheckNtype(n.Elem)
|
||||||
l := n.Key
|
l := n.Key
|
||||||
r := n.Elem
|
r := n.Elem
|
||||||
if l.Type() == nil || r.Type() == nil {
|
if l.Type() == nil || r.Type() == nil {
|
||||||
@ -134,7 +134,7 @@ func tcMapType(n *ir.MapType) ir.Node {
|
|||||||
|
|
||||||
// tcSliceType typechecks an OTSLICE node.
|
// tcSliceType typechecks an OTSLICE node.
|
||||||
func tcSliceType(n *ir.SliceType) ir.Node {
|
func tcSliceType(n *ir.SliceType) ir.Node {
|
||||||
n.Elem = typecheck(n.Elem, ctxType)
|
n.Elem = typecheckNtype(n.Elem)
|
||||||
if n.Elem.Type() == nil {
|
if n.Elem.Type() == nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
@ -31,97 +31,6 @@ var (
|
|||||||
NeedRuntimeType = func(*types.Type) {}
|
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 AssignExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxAssign) }
|
||||||
func Expr(n ir.Node) ir.Node { return typecheck(n, ctxExpr) }
|
func Expr(n ir.Node) ir.Node { return typecheck(n, ctxExpr) }
|
||||||
func Stmt(n ir.Node) ir.Node { return typecheck(n, ctxStmt) }
|
func Stmt(n ir.Node) ir.Node { return typecheck(n, ctxStmt) }
|
||||||
@ -152,13 +61,11 @@ func FuncBody(n *ir.Func) {
|
|||||||
decldepth = 1
|
decldepth = 1
|
||||||
errorsBefore := base.Errors()
|
errorsBefore := base.Errors()
|
||||||
Stmts(n.Body)
|
Stmts(n.Body)
|
||||||
|
CheckUnused(n)
|
||||||
CheckReturn(n)
|
CheckReturn(n)
|
||||||
if base.Errors() > errorsBefore {
|
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
|
var importlist []*ir.Func
|
||||||
@ -230,7 +137,7 @@ const (
|
|||||||
// marks variables that escape the local frame.
|
// marks variables that escape the local frame.
|
||||||
// rewrites n.Op to be more specific in some cases.
|
// rewrites n.Op to be more specific in some cases.
|
||||||
|
|
||||||
var typecheckdefstack []ir.Node
|
var typecheckdefstack []*ir.Name
|
||||||
|
|
||||||
// Resolve ONONAME to definition, if any.
|
// Resolve ONONAME to definition, if any.
|
||||||
func Resolve(n ir.Node) (res ir.Node) {
|
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.
|
// typecheck1 should ONLY be called from typecheck.
|
||||||
func typecheck1(n ir.Node, top int) ir.Node {
|
func typecheck1(n ir.Node, top int) ir.Node {
|
||||||
switch n.Op() {
|
if n, ok := n.(*ir.Name); ok {
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typecheckdef(n)
|
typecheckdef(n)
|
||||||
if n.Op() == ir.ONONAME {
|
|
||||||
n.SetType(nil)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
@ -595,22 +484,37 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
|||||||
base.Fatalf("typecheck %v", n.Op())
|
base.Fatalf("typecheck %v", n.Op())
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
|
|
||||||
// names
|
|
||||||
case ir.OLITERAL:
|
case ir.OLITERAL:
|
||||||
if n.Type() == nil && n.Val().Kind() == constant.String {
|
if n.Sym() == nil && n.Type() == nil {
|
||||||
base.Fatalf("string literal missing type")
|
base.Fatalf("literal missing type: %v", n)
|
||||||
}
|
}
|
||||||
return 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
|
return n
|
||||||
|
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
n := n.(*ir.Name)
|
||||||
if n.Name().Decldepth == 0 {
|
if n.Decldepth == 0 {
|
||||||
n.Name().Decldepth = decldepth
|
n.Decldepth = decldepth
|
||||||
}
|
}
|
||||||
if n.BuiltinOp != 0 {
|
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
|
return n
|
||||||
}
|
}
|
||||||
if top&ctxAssign == 0 {
|
if top&ctxAssign == 0 {
|
||||||
@ -620,7 +524,7 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
|||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
n.Name().SetUsed(true)
|
n.SetUsed(true)
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
|
||||||
@ -636,9 +540,6 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
|||||||
|
|
||||||
// types (ODEREF is with exprs)
|
// types (ODEREF is with exprs)
|
||||||
case ir.OTYPE:
|
case ir.OTYPE:
|
||||||
if n.Type() == nil {
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OTSLICE:
|
case ir.OTSLICE:
|
||||||
@ -672,28 +573,98 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
|||||||
case ir.ODEREF:
|
case ir.ODEREF:
|
||||||
n := n.(*ir.StarExpr)
|
n := n.(*ir.StarExpr)
|
||||||
return tcStar(n, top)
|
return tcStar(n, top)
|
||||||
// arithmetic exprs
|
|
||||||
case ir.OASOP,
|
// x op= y
|
||||||
ir.OADD,
|
case ir.OASOP:
|
||||||
ir.OAND,
|
n := n.(*ir.AssignOpStmt)
|
||||||
ir.OANDAND,
|
n.X, n.Y = Expr(n.X), Expr(n.Y)
|
||||||
ir.OANDNOT,
|
checkassign(n, n.X)
|
||||||
ir.ODIV,
|
if n.IncDec && !okforarith[n.X.Type().Kind()] {
|
||||||
ir.OEQ,
|
base.Errorf("invalid operation: %v (non-numeric type %v)", n, n.X.Type())
|
||||||
ir.OGE,
|
return n
|
||||||
ir.OGT,
|
}
|
||||||
ir.OLE,
|
switch n.AsOp {
|
||||||
ir.OLT,
|
case ir.OLSH, ir.ORSH:
|
||||||
ir.OLSH,
|
n.X, n.Y, _ = tcShift(n, n.X, n.Y)
|
||||||
ir.ORSH,
|
case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD, ir.OMUL, ir.OOR, ir.OSUB, ir.OXOR:
|
||||||
ir.OMOD,
|
n.X, n.Y, _ = tcArith(n, n.AsOp, n.X, n.Y)
|
||||||
ir.OMUL,
|
default:
|
||||||
ir.ONE,
|
base.Fatalf("invalid assign op: %v", n.AsOp)
|
||||||
ir.OOR,
|
}
|
||||||
ir.OOROR,
|
return n
|
||||||
ir.OSUB,
|
|
||||||
ir.OXOR:
|
// logical operators
|
||||||
return tcArith(n)
|
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:
|
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
|
||||||
n := n.(*ir.UnaryExpr)
|
n := n.(*ir.UnaryExpr)
|
||||||
@ -925,12 +896,12 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
|||||||
|
|
||||||
case ir.ODCLCONST:
|
case ir.ODCLCONST:
|
||||||
n := n.(*ir.Decl)
|
n := n.(*ir.Decl)
|
||||||
n.X = Expr(n.X)
|
n.X = Expr(n.X).(*ir.Name)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.ODCLTYPE:
|
case ir.ODCLTYPE:
|
||||||
n := n.(*ir.Decl)
|
n := n.(*ir.Decl)
|
||||||
n.X = typecheck(n.X, ctxType)
|
n.X = typecheck(n.X, ctxType).(*ir.Name)
|
||||||
types.CheckSize(n.X.Type())
|
types.CheckSize(n.X.Type())
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
@ -940,7 +911,7 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
|||||||
// Each must execute its own return n.
|
// Each must execute its own return n.
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckargs(n ir.Node) {
|
func typecheckargs(n ir.InitNode) {
|
||||||
var list []ir.Node
|
var list []ir.Node
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
default:
|
default:
|
||||||
@ -997,9 +968,9 @@ func typecheckargs(n ir.Node) {
|
|||||||
|
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
case *ir.CallExpr:
|
case *ir.CallExpr:
|
||||||
n.Args.Set(list)
|
n.Args = list
|
||||||
case *ir.ReturnStmt:
|
case *ir.ReturnStmt:
|
||||||
n.Results.Set(list)
|
n.Results = list
|
||||||
}
|
}
|
||||||
|
|
||||||
n.PtrInit().Append(Stmt(as))
|
n.PtrInit().Append(Stmt(as))
|
||||||
@ -1176,19 +1147,16 @@ func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
me := ir.NewMethodExpr(n.Pos(), n.X.Type(), m)
|
n.SetOp(ir.OMETHEXPR)
|
||||||
me.SetType(NewMethodType(m.Type, n.X.Type()))
|
n.Selection = m
|
||||||
f := NewName(ir.MethodSym(t, m.Sym))
|
n.SetType(NewMethodType(m.Type, n.X.Type()))
|
||||||
f.Class_ = ir.PFUNC
|
|
||||||
f.SetType(me.Type())
|
|
||||||
me.FuncName_ = f
|
|
||||||
|
|
||||||
// Issue 25065. Make sure that we emit the symbol for a local method.
|
// 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) {
|
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 {
|
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.
|
// Already in the process of diagnosing an error.
|
||||||
return f2
|
return f2
|
||||||
}
|
}
|
||||||
|
orig := n.X
|
||||||
tt := n.X.Type()
|
tt := n.X.Type()
|
||||||
types.CalcSize(tt)
|
types.CalcSize(tt)
|
||||||
rcvr := f2.Type.Recv().Type
|
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
|
// Check that we haven't implicitly dereferenced any defined pointer types.
|
||||||
for ll != nil && (ll.Op() == ir.ODOT || ll.Op() == ir.ODOTPTR || ll.Op() == ir.ODEREF) {
|
for x := n.X; ; {
|
||||||
switch l := ll.(type) {
|
var inner ir.Node
|
||||||
|
implicit := false
|
||||||
|
switch x := x.(type) {
|
||||||
|
case *ir.AddrExpr:
|
||||||
|
inner, implicit = x.X, x.Implicit()
|
||||||
case *ir.SelectorExpr:
|
case *ir.SelectorExpr:
|
||||||
implicit, ll = l.Implicit(), l.X
|
inner, implicit = x.X, x.Implicit()
|
||||||
case *ir.StarExpr:
|
case *ir.StarExpr:
|
||||||
implicit, ll = l.Implicit(), l.X
|
inner, implicit = x.X, x.Implicit()
|
||||||
}
|
}
|
||||||
}
|
if !implicit {
|
||||||
if implicit && ll.Type().IsPtr() && ll.Type().Sym() != nil && ll.Type().Sym().Def != nil && ir.AsNode(ll.Type().Sym().Def).Op() == ir.OTYPE {
|
break
|
||||||
// It is invalid to automatically dereference a named pointer type when selecting a method.
|
}
|
||||||
// Make n.Left == ll to clarify error message.
|
if inner.Type().Sym() != nil && (x.Op() == ir.ODEREF || x.Op() == ir.ODOTPTR) {
|
||||||
n.X = ll
|
// Found an implicit dereference of a defined pointer type.
|
||||||
return nil
|
// Restore n.X for better error message.
|
||||||
|
n.X = orig
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
x = inner
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Selection = f2
|
n.Selection = f2
|
||||||
@ -1422,7 +1399,7 @@ notenough:
|
|||||||
// Method expressions have the form T.M, and the compiler has
|
// Method expressions have the form T.M, and the compiler has
|
||||||
// rewritten those to ONAME nodes but left T in Left.
|
// rewritten those to ONAME nodes but left T in Left.
|
||||||
if call.Op() == ir.OMETHEXPR {
|
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)
|
base.Errorf("not enough arguments in call to method expression %v%s", call, details)
|
||||||
} else {
|
} else {
|
||||||
base.Errorf("not enough arguments in call to %v%s", call, details)
|
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) {
|
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.
|
// Variables declared in ORANGE are assigned on every iteration.
|
||||||
if !ir.DeclaredBy(n, stmt) || stmt.Op() == ir.ORANGE {
|
if !ir.DeclaredBy(n, stmt) || stmt.Op() == ir.ORANGE {
|
||||||
r := ir.OuterValue(n)
|
r := ir.OuterValue(n)
|
||||||
if r.Op() == ir.ONAME {
|
if r.Op() == ir.ONAME {
|
||||||
r := r.(*ir.Name)
|
r := r.(*ir.Name)
|
||||||
r.Name().SetAssigned(true)
|
r.SetAssigned(true)
|
||||||
if r.Name().IsClosureVar() {
|
if r.IsClosureVar() {
|
||||||
r.Name().Defn.Name().SetAssigned(true)
|
r.Defn.Name().SetAssigned(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1656,11 +1641,6 @@ func checkassign(stmt ir.Node, n ir.Node) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// have already complained about n being invalid
|
|
||||||
if n.Type() == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case n.Op() == ir.ODOT && n.(*ir.SelectorExpr).X.Op() == ir.OINDEXMAP:
|
case n.Op() == ir.ODOT && n.(*ir.SelectorExpr).X.Op() == ir.OINDEXMAP:
|
||||||
base.Errorf("cannot assign to struct field %v in map", n)
|
base.Errorf("cannot assign to struct field %v in map", n)
|
||||||
@ -1706,8 +1686,8 @@ func stringtoruneslit(n *ir.ConvExpr) ir.Node {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(n.Type()).(ir.Ntype), nil)
|
nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(n.Type()), nil)
|
||||||
nn.List.Set(l)
|
nn.List = l
|
||||||
return Expr(nn)
|
return Expr(nn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1755,30 +1735,26 @@ func typecheckdeftype(n *ir.Name) {
|
|||||||
types.ResumeCheckSize()
|
types.ResumeCheckSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckdef(n ir.Node) {
|
func typecheckdef(n *ir.Name) {
|
||||||
if base.EnableTrace && base.Flag.LowerT {
|
if base.EnableTrace && base.Flag.LowerT {
|
||||||
defer tracePrint("typecheckdef", n)(nil)
|
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
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if n.Walkdef() == 1 {
|
if n.Walkdef() == 1 {
|
||||||
base.Pos = lno
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
typecheckdefstack = append(typecheckdefstack, n)
|
||||||
if n.Walkdef() == 2 {
|
if n.Walkdef() == 2 {
|
||||||
base.FlushErrors()
|
base.FlushErrors()
|
||||||
@ -1793,27 +1769,23 @@ func typecheckdef(n ir.Node) {
|
|||||||
|
|
||||||
n.SetWalkdef(2)
|
n.SetWalkdef(2)
|
||||||
|
|
||||||
if n.Type() != nil || n.Sym() == nil { // builtin or no name
|
|
||||||
goto ret
|
|
||||||
}
|
|
||||||
|
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
default:
|
default:
|
||||||
base.Fatalf("typecheckdef %v", n.Op())
|
base.Fatalf("typecheckdef %v", n.Op())
|
||||||
|
|
||||||
case ir.OLITERAL:
|
case ir.OLITERAL:
|
||||||
if n.Name().Ntype != nil {
|
if n.Ntype != nil {
|
||||||
n.Name().Ntype = typecheckNtype(n.Name().Ntype)
|
n.Ntype = typecheckNtype(n.Ntype)
|
||||||
n.SetType(n.Name().Ntype.Type())
|
n.SetType(n.Ntype.Type())
|
||||||
n.Name().Ntype = nil
|
n.Ntype = nil
|
||||||
if n.Type() == nil {
|
if n.Type() == nil {
|
||||||
n.SetDiag(true)
|
n.SetDiag(true)
|
||||||
goto ret
|
goto ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e := n.Name().Defn
|
e := n.Defn
|
||||||
n.Name().Defn = nil
|
n.Defn = nil
|
||||||
if e == nil {
|
if e == nil {
|
||||||
ir.Dump("typecheckdef nil defn", n)
|
ir.Dump("typecheckdef nil defn", n)
|
||||||
base.ErrorfAt(n.Pos(), "xxx")
|
base.ErrorfAt(n.Pos(), "xxx")
|
||||||
@ -1856,10 +1828,9 @@ func typecheckdef(n ir.Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
if n.Ntype != nil {
|
||||||
if n.Name().Ntype != nil {
|
n.Ntype = typecheckNtype(n.Ntype)
|
||||||
n.Name().Ntype = typecheckNtype(n.Name().Ntype)
|
n.SetType(n.Ntype.Type())
|
||||||
n.SetType(n.Name().Ntype.Type())
|
|
||||||
if n.Type() == nil {
|
if n.Type() == nil {
|
||||||
n.SetDiag(true)
|
n.SetDiag(true)
|
||||||
goto ret
|
goto ret
|
||||||
@ -1869,7 +1840,7 @@ func typecheckdef(n ir.Node) {
|
|||||||
if n.Type() != nil {
|
if n.Type() != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if n.Name().Defn == nil {
|
if n.Defn == nil {
|
||||||
if n.BuiltinOp != 0 { // like OPRINTN
|
if n.BuiltinOp != 0 { // like OPRINTN
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1884,16 +1855,15 @@ func typecheckdef(n ir.Node) {
|
|||||||
base.Fatalf("var without type, init: %v", n.Sym())
|
base.Fatalf("var without type, init: %v", n.Sym())
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Name().Defn.Op() == ir.ONAME {
|
if n.Defn.Op() == ir.ONAME {
|
||||||
n.Name().Defn = Expr(n.Name().Defn)
|
n.Defn = Expr(n.Defn)
|
||||||
n.SetType(n.Name().Defn.Type())
|
n.SetType(n.Defn.Type())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Name().Defn = Stmt(n.Name().Defn) // fills in n.Type
|
n.Defn = Stmt(n.Defn) // fills in n.Type
|
||||||
|
|
||||||
case ir.OTYPE:
|
case ir.OTYPE:
|
||||||
n := n.(*ir.Name)
|
|
||||||
if n.Alias() {
|
if n.Alias() {
|
||||||
// Type alias declaration: Simply use the rhs type - no need
|
// Type alias declaration: Simply use the rhs type - no need
|
||||||
// to create a new type.
|
// to create a new type.
|
||||||
@ -1970,8 +1940,8 @@ func markBreak(fn *ir.Func) {
|
|||||||
var labels map[*types.Sym]ir.Node
|
var labels map[*types.Sym]ir.Node
|
||||||
var implicit ir.Node
|
var implicit ir.Node
|
||||||
|
|
||||||
var mark func(ir.Node) error
|
var mark func(ir.Node) bool
|
||||||
mark = func(n ir.Node) error {
|
mark = func(n ir.Node) bool {
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
default:
|
default:
|
||||||
ir.DoChildren(n, mark)
|
ir.DoChildren(n, mark)
|
||||||
@ -2011,7 +1981,7 @@ func markBreak(fn *ir.Func) {
|
|||||||
}
|
}
|
||||||
implicit = old
|
implicit = old
|
||||||
}
|
}
|
||||||
return nil
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
mark(fn)
|
mark(fn)
|
||||||
@ -2122,6 +2092,39 @@ func isTermNode(n ir.Node) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ln := range fn.Dcl {
|
||||||
|
if ln.Op() != ir.ONAME || ln.Class != ir.PAUTO || 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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckReturn makes sure that fn terminates appropriately.
|
// CheckReturn makes sure that fn terminates appropriately.
|
||||||
func CheckReturn(fn *ir.Func) {
|
func CheckReturn(fn *ir.Func) {
|
||||||
if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
|
if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
|
||||||
@ -2132,150 +2135,12 @@ func CheckReturn(fn *ir.Func) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deadcode(fn *ir.Func) {
|
|
||||||
deadcodeslice(&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.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 {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// getIotaValue returns the current value for "iota",
|
// getIotaValue returns the current value for "iota",
|
||||||
// or -1 if not within a ConstSpec.
|
// or -1 if not within a ConstSpec.
|
||||||
func getIotaValue() int64 {
|
func getIotaValue() int64 {
|
||||||
if i := len(typecheckdefstack); i > 0 {
|
if i := len(typecheckdefstack); i > 0 {
|
||||||
if x := typecheckdefstack[i-1]; x.Op() == ir.OLITERAL {
|
if x := typecheckdefstack[i-1]; x.Op() == ir.OLITERAL {
|
||||||
return x.(*ir.Name).Iota()
|
return x.Iota()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,8 +90,8 @@ var unsafeFuncs = [...]struct {
|
|||||||
{"Sizeof", ir.OSIZEOF},
|
{"Sizeof", ir.OSIZEOF},
|
||||||
}
|
}
|
||||||
|
|
||||||
// initUniverse initializes the universe block.
|
// InitUniverse initializes the universe block.
|
||||||
func initUniverse() {
|
func InitUniverse() {
|
||||||
if types.PtrSize == 0 {
|
if types.PtrSize == 0 {
|
||||||
base.Fatalf("typeinit before betypeinit")
|
base.Fatalf("typeinit before betypeinit")
|
||||||
}
|
}
|
||||||
@ -336,8 +336,8 @@ func makeErrorInterface() *types.Type {
|
|||||||
return types.NewInterface(types.NoPkg, []*types.Field{method})
|
return types.NewInterface(types.NoPkg, []*types.Field{method})
|
||||||
}
|
}
|
||||||
|
|
||||||
// declareUniverse makes the universe block visible within the current package.
|
// DeclareUniverse makes the universe block visible within the current package.
|
||||||
func declareUniverse() {
|
func DeclareUniverse() {
|
||||||
// Operationally, this is similar to a dot import of builtinpkg, except
|
// Operationally, this is similar to a dot import of builtinpkg, except
|
||||||
// that we silently skip symbols that are already declared in the
|
// that we silently skip symbols that are already declared in the
|
||||||
// package block rather than emitting a redeclared symbol error.
|
// package block rather than emitting a redeclared symbol error.
|
||||||
@ -357,6 +357,6 @@ func declareUniverse() {
|
|||||||
|
|
||||||
ir.RegFP = NewName(Lookup(".fp"))
|
ir.RegFP = NewName(Lookup(".fp"))
|
||||||
ir.RegFP.SetType(types.Types[types.TINT32])
|
ir.RegFP.SetType(types.Types[types.TINT32])
|
||||||
ir.RegFP.Class_ = ir.PPARAM
|
ir.RegFP.Class = ir.PPARAM
|
||||||
ir.RegFP.SetUsed(true)
|
ir.RegFP.SetUsed(true)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) {
|
|||||||
_32bit uintptr // size on 32bit platforms
|
_32bit uintptr // size on 32bit platforms
|
||||||
_64bit uintptr // size on 64bit platforms
|
_64bit uintptr // size on 64bit platforms
|
||||||
}{
|
}{
|
||||||
{Sym{}, 48, 80},
|
{Sym{}, 44, 72},
|
||||||
{Type{}, 56, 96},
|
{Type{}, 56, 96},
|
||||||
{Map{}, 20, 40},
|
{Map{}, 20, 40},
|
||||||
{Forward{}, 20, 32},
|
{Forward{}, 20, 32},
|
||||||
|
@ -27,8 +27,7 @@ import (
|
|||||||
// NOTE: In practice, things can be messier than the description above
|
// NOTE: In practice, things can be messier than the description above
|
||||||
// for various reasons (historical, convenience).
|
// for various reasons (historical, convenience).
|
||||||
type Sym struct {
|
type Sym struct {
|
||||||
Importdef *Pkg // where imported definition was found
|
Linkname string // link name
|
||||||
Linkname string // link name
|
|
||||||
|
|
||||||
Pkg *Pkg
|
Pkg *Pkg
|
||||||
Name string // object name
|
Name string // object name
|
||||||
@ -75,6 +74,10 @@ func (sym *Sym) LinksymName() string {
|
|||||||
return sym.Pkg.Prefix + "." + sym.Name
|
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 {
|
func (sym *Sym) Linksym() *obj.LSym {
|
||||||
if sym == nil {
|
if sym == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -6,7 +6,6 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
"cmd/internal/obj"
|
|
||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
@ -1532,10 +1531,6 @@ func (t *Type) HasPointers() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Type) Symbol() *obj.LSym {
|
|
||||||
return TypeLinkSym(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tie returns 'T' if t is a concrete type,
|
// 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.
|
// '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.
|
// It is used to build calls to the conv* and assert* runtime routines.
|
||||||
|
@ -4,19 +4,8 @@
|
|||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
|
||||||
"cmd/internal/obj"
|
|
||||||
)
|
|
||||||
|
|
||||||
const BADWIDTH = -1000000000
|
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
|
type bitset8 uint8
|
||||||
|
|
||||||
func (f *bitset8) set(mask uint8, b bool) {
|
func (f *bitset8) set(mask uint8, b bool) {
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
|
|
||||||
// walkAssign walks an OAS (AssignExpr) or OASOP (AssignOpExpr) node.
|
// walkAssign walks an OAS (AssignExpr) or OASOP (AssignOpExpr) node.
|
||||||
func walkAssign(init *ir.Nodes, n ir.Node) ir.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
|
var left, right ir.Node
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
@ -124,7 +124,7 @@ func walkAssignDotType(n *ir.AssignListStmt, init *ir.Nodes) ir.Node {
|
|||||||
|
|
||||||
// walkAssignFunc walks an OAS2FUNC node.
|
// walkAssignFunc walks an OAS2FUNC node.
|
||||||
func walkAssignFunc(init *ir.Nodes, n *ir.AssignListStmt) ir.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]
|
r := n.Rhs[0]
|
||||||
walkExprListSafe(n.Lhs, init)
|
walkExprListSafe(n.Lhs, init)
|
||||||
@ -142,15 +142,13 @@ func walkAssignFunc(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
|
|||||||
|
|
||||||
// walkAssignList walks an OAS2 node.
|
// walkAssignList walks an OAS2 node.
|
||||||
func walkAssignList(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
|
func walkAssignList(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
|
||||||
init.Append(n.PtrInit().Take()...)
|
init.Append(ir.TakeInit(n)...)
|
||||||
walkExprListSafe(n.Lhs, init)
|
return ir.NewBlockStmt(src.NoXPos, ascompatee(ir.OAS, n.Lhs, n.Rhs))
|
||||||
walkExprListSafe(n.Rhs, init)
|
|
||||||
return ir.NewBlockStmt(src.NoXPos, ascompatee(ir.OAS, n.Lhs, n.Rhs, init))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// walkAssignMapRead walks an OAS2MAPR node.
|
// walkAssignMapRead walks an OAS2MAPR node.
|
||||||
func walkAssignMapRead(init *ir.Nodes, n *ir.AssignListStmt) ir.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)
|
r := n.Rhs[0].(*ir.IndexExpr)
|
||||||
walkExprListSafe(n.Lhs, init)
|
walkExprListSafe(n.Lhs, init)
|
||||||
@ -213,7 +211,7 @@ func walkAssignMapRead(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
|
|||||||
|
|
||||||
// walkAssignRecv walks an OAS2RECV node.
|
// walkAssignRecv walks an OAS2RECV node.
|
||||||
func walkAssignRecv(init *ir.Nodes, n *ir.AssignListStmt) ir.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
|
r := n.Rhs[0].(*ir.UnaryExpr) // recv
|
||||||
walkExprListSafe(n.Lhs, init)
|
walkExprListSafe(n.Lhs, init)
|
||||||
@ -232,56 +230,21 @@ func walkAssignRecv(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
|
|||||||
|
|
||||||
// walkReturn walks an ORETURN node.
|
// walkReturn walks an ORETURN node.
|
||||||
func walkReturn(n *ir.ReturnStmt) ir.Node {
|
func walkReturn(n *ir.ReturnStmt) ir.Node {
|
||||||
ir.CurFunc.NumReturns++
|
fn := ir.CurFunc
|
||||||
|
|
||||||
|
fn.NumReturns++
|
||||||
if len(n.Results) == 0 {
|
if len(n.Results) == 0 {
|
||||||
return n
|
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 {
|
results := fn.Type().Results().FieldSlice()
|
||||||
cl := ln.Class_
|
dsts := make([]ir.Node, len(results))
|
||||||
if cl == ir.PAUTO || cl == ir.PAUTOHEAP {
|
for i, v := range results {
|
||||||
break
|
// TODO(mdempsky): typecheck should have already checked the result variables.
|
||||||
}
|
dsts[i] = typecheck.AssignExpr(v.Nname.(*ir.Name))
|
||||||
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
|
|
||||||
}
|
}
|
||||||
walkExprList(n.Results, n.PtrInit())
|
|
||||||
|
|
||||||
// For each return parameter (lhs), assign the corresponding result (rhs).
|
n.Results = ascompatee(n.Op(), dsts, n.Results)
|
||||||
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)
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,20 +305,12 @@ func ascompatet(nl ir.Nodes, nr *types.Type) []ir.Node {
|
|||||||
// check assign expression list to
|
// check assign expression list to
|
||||||
// an expression list. called in
|
// an expression list. called in
|
||||||
// expr-list = expr-list
|
// 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
|
// cannot happen: should have been rejected during type checking
|
||||||
if len(nl) != len(nr) {
|
if len(nl) != len(nr) {
|
||||||
base.Fatalf("assignment operands mismatch: %+v / %+v", ir.Nodes(nl), ir.Nodes(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 assigned ir.NameSet
|
||||||
var memWrite bool
|
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
|
// If a needed expression may be affected by an
|
||||||
// earlier assignment, make an early copy of that
|
// earlier assignment, make an early copy of that
|
||||||
// expression and use the copy instead.
|
// expression and use the copy instead.
|
||||||
var early []ir.Node
|
var early ir.Nodes
|
||||||
save := func(np *ir.Node) {
|
save := func(np *ir.Node) {
|
||||||
if n := *np; affected(n) {
|
if n := *np; affected(n) {
|
||||||
tmp := ir.Node(typecheck.Temp(n.Type()))
|
*np = copyExpr(n, n.Type(), &early)
|
||||||
as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, tmp, n))
|
|
||||||
early = append(early, as)
|
|
||||||
*np = tmp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var late []ir.Node
|
var late ir.Nodes
|
||||||
for i, l := range nl {
|
for i, lorig := range nl {
|
||||||
r := nr[i]
|
l, r := lorig, nr[i]
|
||||||
|
|
||||||
// Do not generate 'x = x' during return. See issue 4014.
|
// Do not generate 'x = x' during return. See issue 4014.
|
||||||
if op == ir.ORETURN && ir.SameSafeExpr(l, r) {
|
if op == ir.ORETURN && ir.SameSafeExpr(l, r) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
as := ir.NewAssignStmt(base.Pos, l, r)
|
|
||||||
|
|
||||||
// Save subexpressions needed on left side.
|
// Save subexpressions needed on left side.
|
||||||
// Drill through non-dereferences.
|
// Drill through non-dereferences.
|
||||||
for {
|
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 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
|
memWrite = true
|
||||||
continue
|
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.
|
// We can ignore assignments to blank.
|
||||||
continue
|
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)
|
assigned.Add(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(early, late...)
|
early.Append(late.Take()...)
|
||||||
|
return early
|
||||||
}
|
}
|
||||||
|
|
||||||
// readsMemory reports whether the evaluation n directly reads from
|
// readsMemory reports whether the evaluation n directly reads from
|
||||||
@ -462,7 +418,7 @@ func readsMemory(n ir.Node) bool {
|
|||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
n := n.(*ir.Name)
|
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,
|
case ir.OADD,
|
||||||
ir.OAND,
|
ir.OAND,
|
||||||
|
@ -206,7 +206,7 @@ func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
|
|||||||
|
|
||||||
// walkDelete walks an ODELETE node.
|
// walkDelete walks an ODELETE node.
|
||||||
func walkDelete(init *ir.Nodes, n *ir.CallExpr) ir.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]
|
map_ := n.Args[0]
|
||||||
key := n.Args[1]
|
key := n.Args[1]
|
||||||
map_ = walkExpr(map_, init)
|
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, n)
|
||||||
}
|
}
|
||||||
t = append(t, ir.NewString("\n"))
|
t = append(t, ir.NewString("\n"))
|
||||||
nn.Args.Set(t)
|
nn.Args = t
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collapse runs of constant strings.
|
// Collapse runs of constant strings.
|
||||||
@ -551,7 +551,7 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nn.Args.Set(t)
|
nn.Args = t
|
||||||
|
|
||||||
calls := []ir.Node{mkcall("printlock", nil, init)}
|
calls := []ir.Node{mkcall("printlock", nil, init)}
|
||||||
for i, n := range nn.Args {
|
for i, n := range nn.Args {
|
||||||
@ -653,7 +653,7 @@ func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
|
|||||||
walkExprList(calls, init)
|
walkExprList(calls, init)
|
||||||
|
|
||||||
r := ir.NewBlockStmt(base.Pos, nil)
|
r := ir.NewBlockStmt(base.Pos, nil)
|
||||||
r.List.Set(calls)
|
r.List = calls
|
||||||
return walkStmt(typecheck.Stmt(r))
|
return walkStmt(typecheck.Stmt(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ func Closure(fn *ir.Func) {
|
|||||||
v = addr
|
v = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
v.Class_ = ir.PPARAM
|
v.Class = ir.PPARAM
|
||||||
decls = append(decls, v)
|
decls = append(decls, v)
|
||||||
|
|
||||||
fld := types.NewField(src.NoXPos, v.Sym(), v.Type())
|
fld := types.NewField(src.NoXPos, v.Sym(), v.Type())
|
||||||
@ -67,7 +67,7 @@ func Closure(fn *ir.Func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
types.CalcSize(f.Type())
|
types.CalcSize(f.Type())
|
||||||
fn.SetType(f.Type()) // update type of ODCLFUNC
|
fn.Nname.SetType(f.Type()) // update type of ODCLFUNC
|
||||||
} else {
|
} else {
|
||||||
// The closure is not called, so it is going to stay as closure.
|
// The closure is not called, so it is going to stay as closure.
|
||||||
var body []ir.Node
|
var body []ir.Node
|
||||||
@ -84,7 +84,7 @@ func Closure(fn *ir.Func) {
|
|||||||
|
|
||||||
if v.Byval() && v.Type().Width <= int64(2*types.PtrSize) {
|
if v.Byval() && v.Type().Width <= int64(2*types.PtrSize) {
|
||||||
// If it is a small variable captured by value, downgrade it to PAUTO.
|
// 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)
|
fn.Dcl = append(fn.Dcl, v)
|
||||||
body = append(body, ir.NewAssignStmt(base.Pos, v, cr))
|
body = append(body, ir.NewAssignStmt(base.Pos, v, cr))
|
||||||
} else {
|
} else {
|
||||||
@ -92,7 +92,7 @@ func Closure(fn *ir.Func) {
|
|||||||
// and initialize in entry prologue.
|
// and initialize in entry prologue.
|
||||||
addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
|
addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
|
||||||
addr.SetType(types.NewPtr(v.Type()))
|
addr.SetType(types.NewPtr(v.Type()))
|
||||||
addr.Class_ = ir.PAUTO
|
addr.Class = ir.PAUTO
|
||||||
addr.SetUsed(true)
|
addr.SetUsed(true)
|
||||||
addr.Curfn = fn
|
addr.Curfn = fn
|
||||||
fn.Dcl = append(fn.Dcl, addr)
|
fn.Dcl = append(fn.Dcl, addr)
|
||||||
@ -107,7 +107,7 @@ func Closure(fn *ir.Func) {
|
|||||||
|
|
||||||
if len(body) > 0 {
|
if len(body) > 0 {
|
||||||
typecheck.Stmts(body)
|
typecheck.Stmts(body)
|
||||||
fn.Enter.Set(body)
|
fn.Enter = body
|
||||||
fn.SetNeedctxt(true)
|
fn.SetNeedctxt(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,9 +129,9 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
|
|||||||
|
|
||||||
typ := typecheck.ClosureType(clo)
|
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.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 := typecheck.NodAddr(clos)
|
||||||
addr.SetEsc(clo.Esc())
|
addr.SetEsc(clo.Esc())
|
||||||
@ -144,14 +144,34 @@ func walkClosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
|
|||||||
if !types.Identical(typ, x.Type()) {
|
if !types.Identical(typ, x.Type()) {
|
||||||
panic("closure type does not match order's assigned type")
|
panic("closure type does not match order's assigned type")
|
||||||
}
|
}
|
||||||
addr.Alloc = x
|
addr.Prealloc = x
|
||||||
clo.Prealloc = nil
|
clo.Prealloc = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return walkExpr(cfn, init)
|
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.
|
// Create closure in the form of a composite literal.
|
||||||
// For x.M with receiver (x) type T, the generated code looks like:
|
// 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)
|
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.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 := typecheck.NodAddr(clos)
|
||||||
addr.SetEsc(n.Esc())
|
addr.SetEsc(n.Esc())
|
||||||
@ -189,7 +209,7 @@ func walkCallPart(n *ir.CallPartExpr, init *ir.Nodes) ir.Node {
|
|||||||
if !types.Identical(typ, x.Type()) {
|
if !types.Identical(typ, x.Type()) {
|
||||||
panic("partial call type does not match order's assigned type")
|
panic("partial call type does not match order's assigned type")
|
||||||
}
|
}
|
||||||
addr.Alloc = x
|
addr.Prealloc = x
|
||||||
n.Prealloc = nil
|
n.Prealloc = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ func (c initContext) String() string {
|
|||||||
func readonlystaticname(t *types.Type) *ir.Name {
|
func readonlystaticname(t *types.Type) *ir.Name {
|
||||||
n := staticinit.StaticName(t)
|
n := staticinit.StaticName(t)
|
||||||
n.MarkReadonly()
|
n.MarkReadonly()
|
||||||
n.Sym().Linksym().Set(obj.AttrContentAddressable, true)
|
n.Linksym().Set(obj.AttrContentAddressable, true)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ func isSimpleName(nn ir.Node) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
n := nn.(*ir.Name)
|
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) {
|
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
|
// copy static to slice
|
||||||
var_ = typecheck.AssignExpr(var_)
|
var_ = typecheck.AssignExpr(var_)
|
||||||
name, offset, ok := staticinit.StaticLoc(var_)
|
name, offset, ok := staticinit.StaticLoc(var_)
|
||||||
if !ok || name.Class_ != ir.PEXTERN {
|
if !ok || name.Class != ir.PEXTERN {
|
||||||
base.Fatalf("slicelit: %v", var_)
|
base.Fatalf("slicelit: %v", var_)
|
||||||
}
|
}
|
||||||
staticdata.InitSlice(name, offset, vstat, t.NumElem())
|
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))
|
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
|
||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
n := n.(*ir.MethodExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
anylit(n.FuncName(), var_, init)
|
anylit(n.FuncName(), var_, init)
|
||||||
|
|
||||||
case ir.OPTRLIT:
|
case ir.OPTRLIT:
|
||||||
@ -549,10 +549,10 @@ func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var r ir.Node
|
var r ir.Node
|
||||||
if n.Alloc != nil {
|
if n.Prealloc != nil {
|
||||||
// n.Right is stack temporary used as backing store.
|
// 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)
|
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n.Prealloc, nil)) // zero backing store, just in case (#18410)
|
||||||
r = typecheck.NodAddr(n.Alloc)
|
r = typecheck.NodAddr(n.Prealloc)
|
||||||
} else {
|
} else {
|
||||||
r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
|
r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
|
||||||
r.SetEsc(n.Esc())
|
r.SetEsc(n.Esc())
|
||||||
@ -657,7 +657,7 @@ func genAsStatic(as *ir.AssignStmt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
name, offset, ok := staticinit.StaticLoc(as.X)
|
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)
|
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))
|
staticdata.InitConst(name, offset, r, int(r.Type().Width))
|
||||||
return
|
return
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
r := r.(*ir.MethodExpr)
|
r := r.(*ir.SelectorExpr)
|
||||||
staticdata.InitFunc(name, offset, r.FuncName())
|
staticdata.InitFunc(name, offset, r.FuncName())
|
||||||
return
|
return
|
||||||
case ir.ONAME:
|
case ir.ONAME:
|
||||||
@ -674,7 +674,7 @@ func genAsStatic(as *ir.AssignStmt) {
|
|||||||
if r.Offset_ != 0 {
|
if r.Offset_ != 0 {
|
||||||
base.Fatalf("genAsStatic %+v", as)
|
base.Fatalf("genAsStatic %+v", as)
|
||||||
}
|
}
|
||||||
if r.Class_ == ir.PFUNC {
|
if r.Class == ir.PFUNC {
|
||||||
staticdata.InitFunc(name, offset, r)
|
staticdata.InitFunc(name, offset, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -68,12 +68,12 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
|
|||||||
|
|
||||||
if ir.Names.Staticuint64s == nil {
|
if ir.Names.Staticuint64s == nil {
|
||||||
ir.Names.Staticuint64s = typecheck.NewName(ir.Pkgs.Runtime.Lookup("staticuint64s"))
|
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
|
// The actual type is [256]uint64, but we use [256*8]uint8 so we can address
|
||||||
// individual bytes.
|
// individual bytes.
|
||||||
ir.Names.Staticuint64s.SetType(types.NewArray(types.Types[types.TUINT8], 256*8))
|
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 = 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])
|
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 := ir.NewIndexExpr(base.Pos, ir.Names.Staticuint64s, index)
|
||||||
xe.SetBounded(true)
|
xe.SetBounded(true)
|
||||||
value = xe
|
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.
|
// n.Left is a readonly global; use it directly.
|
||||||
value = n.X
|
value = n.X
|
||||||
case !fromType.IsInterface() && n.Esc() == ir.EscNone && fromType.Width <= 1024:
|
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 {
|
func walkCheckPtrArithmetic(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
|
||||||
// Calling cheapexpr(n, init) below leads to a recursive call
|
// Calling cheapexpr(n, init) below leads to a recursive call to
|
||||||
// to walkexpr, which leads us back here again. Use n.Opt to
|
// walkexpr, which leads us back here again. Use n.Checkptr to
|
||||||
// prevent infinite loops.
|
// prevent infinite loops.
|
||||||
if opt := n.Opt(); opt == &walkCheckPtrArithmeticMarker {
|
if n.CheckPtr() {
|
||||||
return n
|
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)
|
n.SetCheckPtr(true)
|
||||||
defer n.SetOpt(nil)
|
defer n.SetCheckPtr(false)
|
||||||
|
|
||||||
// TODO(mdempsky): Make stricter. We only need to exempt
|
// TODO(mdempsky): Make stricter. We only need to exempt
|
||||||
// reflect.Value.Pointer and reflect.Value.UnsafeAddr.
|
// reflect.Value.Pointer and reflect.Value.UnsafeAddr.
|
||||||
|
@ -26,7 +26,7 @@ func walkExpr(n ir.Node, init *ir.Nodes) ir.Node {
|
|||||||
return n
|
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,
|
// not okay to use n->ninit when walking n,
|
||||||
// because we might replace n with some other node
|
// because we might replace n with some other node
|
||||||
// and would lose the init list.
|
// 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 {
|
if len(n.Init()) != 0 {
|
||||||
walkStmtList(n.Init())
|
walkStmtList(n.Init())
|
||||||
init.Append(n.PtrInit().Take()...)
|
init.Append(ir.TakeInit(n)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
lno := ir.SetPos(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)
|
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)
|
n := n.(*ir.Name)
|
||||||
nn := ir.NewStarExpr(base.Pos, n.Name().Heapaddr)
|
nn := ir.NewStarExpr(base.Pos, n.Heapaddr)
|
||||||
nn.X.MarkNonNil()
|
nn.X.MarkNonNil()
|
||||||
return walkExpr(typecheck.Expr(nn), init)
|
return walkExpr(typecheck.Expr(nn), init)
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
|||||||
|
|
||||||
case ir.OMETHEXPR:
|
case ir.OMETHEXPR:
|
||||||
// TODO(mdempsky): Do this right after type checking.
|
// TODO(mdempsky): Do this right after type checking.
|
||||||
n := n.(*ir.MethodExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
return n.FuncName()
|
return n.FuncName()
|
||||||
|
|
||||||
case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA:
|
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)
|
return walkClosure(n.(*ir.ClosureExpr), init)
|
||||||
|
|
||||||
case ir.OCALLPART:
|
case ir.OCALLPART:
|
||||||
return walkCallPart(n.(*ir.CallPartExpr), init)
|
return walkCallPart(n.(*ir.SelectorExpr), init)
|
||||||
}
|
}
|
||||||
|
|
||||||
// No return! Each case must return (or panic),
|
// 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 {
|
if len(n.Init()) != 0 {
|
||||||
walkStmtList(n.Init())
|
walkStmtList(n.Init())
|
||||||
init.Append(n.PtrInit().Take()...)
|
init.Append(ir.TakeInit(n)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
@ -477,7 +477,7 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node {
|
|||||||
|
|
||||||
cat := typecheck.LookupRuntime(fn)
|
cat := typecheck.LookupRuntime(fn)
|
||||||
r := ir.NewCallExpr(base.Pos, ir.OCALL, cat, nil)
|
r := ir.NewCallExpr(base.Pos, ir.OCALL, cat, nil)
|
||||||
r.Args.Set(args)
|
r.Args = args
|
||||||
r1 := typecheck.Expr(r)
|
r1 := typecheck.Expr(r)
|
||||||
r1 = walkExpr(r1, init)
|
r1 = walkExpr(r1, init)
|
||||||
r1.SetType(n.Type())
|
r1.SetType(n.Type())
|
||||||
@ -498,8 +498,7 @@ func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
|||||||
|
|
||||||
// Prepend captured variables to argument list.
|
// Prepend captured variables to argument list.
|
||||||
clo := n.X.(*ir.ClosureExpr)
|
clo := n.X.(*ir.ClosureExpr)
|
||||||
n.Args.Prepend(clo.Func.ClosureEnter...)
|
n.Args.Prepend(closureArgs(clo)...)
|
||||||
clo.Func.ClosureEnter.Set(nil)
|
|
||||||
|
|
||||||
// Replace OCLOSURE with ONAME/PFUNC.
|
// Replace OCLOSURE with ONAME/PFUNC.
|
||||||
n.X = clo.Func.Nname
|
n.X = clo.Func.Nname
|
||||||
@ -563,8 +562,8 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Args.Set(tempAssigns)
|
n.Args = tempAssigns
|
||||||
n.Rargs.Set(args)
|
n.Rargs = args
|
||||||
}
|
}
|
||||||
|
|
||||||
// walkDivMod walks an ODIV or OMOD node.
|
// 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 {
|
func walkDotType(n *ir.TypeAssertExpr, init *ir.Nodes) ir.Node {
|
||||||
n.X = walkExpr(n.X, init)
|
n.X = walkExpr(n.X, init)
|
||||||
// Set up interface type addresses for back end.
|
// 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 {
|
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() {
|
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
|
return n
|
||||||
}
|
}
|
||||||
@ -974,7 +974,7 @@ func usefield(n *ir.SelectorExpr) {
|
|||||||
|
|
||||||
sym := reflectdata.TrackSym(outer, field)
|
sym := reflectdata.TrackSym(outer, field)
|
||||||
if ir.CurFunc.FieldTrack == nil {
|
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{}{}
|
ir.CurFunc.FieldTrack[sym] = struct{}{}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ func (o *orderState) newTemp(t *types.Type, clear bool) *ir.Name {
|
|||||||
|
|
||||||
// copyExpr behaves like newTemp but also emits
|
// copyExpr behaves like newTemp but also emits
|
||||||
// code to initialize the temporary to the value n.
|
// 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)
|
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
|
// because we emit explicit VARKILL instructions marking the end of those
|
||||||
// temporaries' lifetimes.
|
// temporaries' lifetimes.
|
||||||
func isaddrokay(n ir.Node) bool {
|
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.
|
// 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
|
// Create a new uint8 counter to be allocated in section
|
||||||
// __libfuzzer_extra_counters.
|
// __libfuzzer_extra_counters.
|
||||||
counter := staticinit.StaticName(types.Types[types.TUINT8])
|
counter := staticinit.StaticName(types.Types[types.TUINT8])
|
||||||
counter.Name().SetLibfuzzerExtraCounter(true)
|
counter.SetLibfuzzerExtraCounter(true)
|
||||||
|
|
||||||
// counter += 1
|
// counter += 1
|
||||||
incr := ir.NewAssignOpStmt(base.Pos, ir.OADD, counter, ir.NewInt(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.edge()
|
||||||
order.stmtList(*n)
|
order.stmtList(*n)
|
||||||
order.cleanTemp(mark)
|
order.cleanTemp(mark)
|
||||||
n.Set(order.out)
|
*n = order.out
|
||||||
}
|
}
|
||||||
|
|
||||||
// exprInPlace orders the side effects in *np and
|
// exprInPlace orders the side effects in *np and
|
||||||
@ -466,8 +466,7 @@ func (o *orderState) init(n ir.Node) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
o.stmtList(n.Init())
|
o.stmtList(ir.TakeInit(n))
|
||||||
n.PtrInit().Set(nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// call orders the call expression n.
|
// call orders the call expression n.
|
||||||
@ -517,8 +516,8 @@ func (o *orderState) call(nn ir.Node) {
|
|||||||
if arg.X.Type().IsUnsafePtr() {
|
if arg.X.Type().IsUnsafePtr() {
|
||||||
x := o.copyExpr(arg.X)
|
x := o.copyExpr(arg.X)
|
||||||
arg.X = x
|
arg.X = x
|
||||||
x.Name().SetAddrtaken(true) // ensure SSA keeps the x variable
|
x.SetAddrtaken(true) // ensure SSA keeps the x variable
|
||||||
n.Body.Append(typecheck.Stmt(ir.NewUnaryExpr(base.Pos, ir.OVARLIVE, x)))
|
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
|
// mapAssign appends n to o.out.
|
||||||
// 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.
|
|
||||||
func (o *orderState) mapAssign(n ir.Node) {
|
func (o *orderState) mapAssign(n ir.Node) {
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
default:
|
default:
|
||||||
@ -573,28 +558,7 @@ func (o *orderState) mapAssign(n ir.Node) {
|
|||||||
|
|
||||||
case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC:
|
case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2MAPR, ir.OAS2FUNC:
|
||||||
n := n.(*ir.AssignListStmt)
|
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, n)
|
||||||
o.out = append(o.out, post...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,8 +902,7 @@ func (o *orderState) stmt(n ir.Node) {
|
|||||||
if !ir.IsAutoTmp(recv.X) {
|
if !ir.IsAutoTmp(recv.X) {
|
||||||
recv.X = o.copyExpr(recv.X)
|
recv.X = o.copyExpr(recv.X)
|
||||||
}
|
}
|
||||||
init := *r.PtrInit()
|
init := ir.TakeInit(r)
|
||||||
r.PtrInit().Set(nil)
|
|
||||||
|
|
||||||
colas := r.Def
|
colas := r.Def
|
||||||
do := func(i int, t *types.Type) {
|
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 {
|
if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).X == n {
|
||||||
init = init[1:]
|
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)
|
ncas.PtrInit().Append(dcl)
|
||||||
}
|
}
|
||||||
tmp := o.newTemp(t, t.HasPointers())
|
tmp := o.newTemp(t, t.HasPointers())
|
||||||
@ -1000,8 +963,7 @@ func (o *orderState) stmt(n ir.Node) {
|
|||||||
|
|
||||||
// TODO(mdempsky): Is this actually necessary?
|
// TODO(mdempsky): Is this actually necessary?
|
||||||
// walkselect appears to walk Ninit.
|
// walkselect appears to walk Ninit.
|
||||||
cas.Body.Prepend(cas.Init()...)
|
cas.Body.Prepend(ir.TakeInit(cas)...)
|
||||||
cas.PtrInit().Set(nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
o.out = append(o.out, n)
|
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.
|
// If left-hand side doesn't cause a short-circuit, issue right-hand side.
|
||||||
nif := ir.NewIfStmt(base.Pos, r, nil, nil)
|
nif := ir.NewIfStmt(base.Pos, r, nil, nil)
|
||||||
if n.Op() == ir.OANDAND {
|
if n.Op() == ir.OANDAND {
|
||||||
nif.Body.Set(gen)
|
nif.Body = gen
|
||||||
} else {
|
} else {
|
||||||
nif.Else.Set(gen)
|
nif.Else = gen
|
||||||
}
|
}
|
||||||
o.out = append(o.out, nif)
|
o.out = append(o.out, nif)
|
||||||
return r
|
return r
|
||||||
@ -1310,7 +1272,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
|
|||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OCALLPART:
|
case ir.OCALLPART:
|
||||||
n := n.(*ir.CallPartExpr)
|
n := n.(*ir.SelectorExpr)
|
||||||
n.X = o.expr(n.X, nil)
|
n.X = o.expr(n.X, nil)
|
||||||
if n.Transient() {
|
if n.Transient() {
|
||||||
t := typecheck.PartialCallType(n)
|
t := typecheck.PartialCallType(n)
|
||||||
@ -1404,7 +1366,7 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
|
|||||||
|
|
||||||
statics = append(statics, r)
|
statics = append(statics, r)
|
||||||
}
|
}
|
||||||
n.List.Set(statics)
|
n.List = statics
|
||||||
|
|
||||||
if len(dynamics) == 0 {
|
if len(dynamics) == 0 {
|
||||||
return n
|
return n
|
||||||
@ -1451,8 +1413,8 @@ func (o *orderState) as2(n *ir.AssignListStmt) {
|
|||||||
o.out = append(o.out, n)
|
o.out = append(o.out, n)
|
||||||
|
|
||||||
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
|
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
|
||||||
as.Lhs.Set(left)
|
as.Lhs = left
|
||||||
as.Rhs.Set(tmplist)
|
as.Rhs = tmplist
|
||||||
o.stmt(typecheck.Stmt(as))
|
o.stmt(typecheck.Stmt(as))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,13 +8,14 @@ import (
|
|||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
"cmd/compile/internal/ir"
|
"cmd/compile/internal/ir"
|
||||||
"cmd/compile/internal/ssagen"
|
"cmd/compile/internal/ssagen"
|
||||||
|
"cmd/compile/internal/typecheck"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
)
|
)
|
||||||
|
|
||||||
func instrument(fn *ir.Func) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +37,10 @@ func instrument(fn *ir.Func) {
|
|||||||
// This only works for amd64. This will not
|
// This only works for amd64. This will not
|
||||||
// work on arm or others that might support
|
// work on arm or others that might support
|
||||||
// race in the future.
|
// 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.SetType(types.Types[types.TUINTPTR])
|
||||||
nodpc.SetFrameOffset(int64(-types.PtrSize))
|
nodpc.SetFrameOffset(int64(-types.PtrSize))
|
||||||
fn.Dcl = append(fn.Dcl, nodpc)
|
fn.Dcl = append(fn.Dcl, nodpc)
|
||||||
|
@ -210,7 +210,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
|
|||||||
a.SetTypecheck(1)
|
a.SetTypecheck(1)
|
||||||
a.Lhs = []ir.Node{hv1, hb}
|
a.Lhs = []ir.Node{hv1, hb}
|
||||||
a.Rhs = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.ORECV, ha)}
|
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 {
|
if v1 == nil {
|
||||||
body = nil
|
body = nil
|
||||||
} else {
|
} else {
|
||||||
@ -429,7 +429,7 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
|
|||||||
// i = len(a) - 1
|
// i = len(a) - 1
|
||||||
// }
|
// }
|
||||||
n := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
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))
|
n.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(0))
|
||||||
|
|
||||||
// hp = &a[0]
|
// hp = &a[0]
|
||||||
|
@ -17,13 +17,12 @@ func walkSelect(sel *ir.SelectStmt) {
|
|||||||
base.Fatalf("double walkselect")
|
base.Fatalf("double walkselect")
|
||||||
}
|
}
|
||||||
|
|
||||||
init := sel.Init()
|
init := ir.TakeInit(sel)
|
||||||
sel.PtrInit().Set(nil)
|
|
||||||
|
|
||||||
init = append(init, walkSelectCases(sel.Cases)...)
|
init = append(init, walkSelectCases(sel.Cases)...)
|
||||||
sel.Cases = nil
|
sel.Cases = nil
|
||||||
|
|
||||||
sel.Compiled.Set(init)
|
sel.Compiled = init
|
||||||
walkStmtList(sel.Compiled)
|
walkStmtList(sel.Compiled)
|
||||||
|
|
||||||
base.Pos = lno
|
base.Pos = lno
|
||||||
@ -45,8 +44,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node {
|
|||||||
l := cas.Init()
|
l := cas.Init()
|
||||||
if cas.Comm != nil { // not default:
|
if cas.Comm != nil { // not default:
|
||||||
n := cas.Comm
|
n := cas.Comm
|
||||||
l = append(l, n.Init()...)
|
l = append(l, ir.TakeInit(n)...)
|
||||||
n.PtrInit().Set(nil)
|
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
default:
|
default:
|
||||||
base.Fatalf("select %v", n.Op())
|
base.Fatalf("select %v", n.Op())
|
||||||
@ -106,7 +104,7 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node {
|
|||||||
n := cas.Comm
|
n := cas.Comm
|
||||||
ir.SetPos(n)
|
ir.SetPos(n)
|
||||||
r := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
r := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||||
r.PtrInit().Set(cas.Init())
|
*r.PtrInit() = cas.Init()
|
||||||
var call ir.Node
|
var call ir.Node
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
default:
|
default:
|
||||||
@ -138,8 +136,8 @@ func walkSelectCases(cases []*ir.CommClause) []ir.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.Cond = typecheck.Expr(call)
|
r.Cond = typecheck.Expr(call)
|
||||||
r.Body.Set(cas.Body)
|
r.Body = cas.Body
|
||||||
r.Else.Set(append(dflt.Init(), dflt.Body...))
|
r.Else = append(dflt.Init(), dflt.Body...)
|
||||||
return []ir.Node{r, ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)}
|
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 {
|
for _, cas := range cases {
|
||||||
ir.SetPos(cas)
|
ir.SetPos(cas)
|
||||||
|
|
||||||
init = append(init, cas.Init()...)
|
init = append(init, ir.TakeInit(cas)...)
|
||||||
cas.PtrInit().Set(nil)
|
|
||||||
|
|
||||||
n := cas.Comm
|
n := cas.Comm
|
||||||
if n == nil { // default:
|
if n == nil { // default:
|
||||||
|
@ -55,19 +55,18 @@ func walkStmt(n ir.Node) ir.Node {
|
|||||||
if n.Typecheck() == 0 {
|
if n.Typecheck() == 0 {
|
||||||
base.Fatalf("missing typecheck: %+v", n)
|
base.Fatalf("missing typecheck: %+v", n)
|
||||||
}
|
}
|
||||||
init := n.Init()
|
init := ir.TakeInit(n)
|
||||||
n.PtrInit().Set(nil)
|
|
||||||
n = walkExpr(n, &init)
|
n = walkExpr(n, &init)
|
||||||
if n.Op() == ir.ONAME {
|
if n.Op() == ir.ONAME {
|
||||||
// copy rewrote to a statement list and a temp for the length.
|
// copy rewrote to a statement list and a temp for the length.
|
||||||
// Throw away the temp to avoid plain values as statements.
|
// Throw away the temp to avoid plain values as statements.
|
||||||
n = ir.NewBlockStmt(n.Pos(), init)
|
n = ir.NewBlockStmt(n.Pos(), init)
|
||||||
init.Set(nil)
|
init = nil
|
||||||
}
|
}
|
||||||
if len(init) > 0 {
|
if len(init) > 0 {
|
||||||
switch n.Op() {
|
switch n.Op() {
|
||||||
case ir.OAS, ir.OAS2, ir.OBLOCK:
|
case ir.OAS, ir.OAS2, ir.OBLOCK:
|
||||||
n.PtrInit().Prepend(init...)
|
n.(ir.InitNode).PtrInit().Prepend(init...)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
init.Append(n)
|
init.Append(n)
|
||||||
@ -176,12 +175,12 @@ func walkStmtList(s []ir.Node) {
|
|||||||
|
|
||||||
// walkDecl walks an ODCL node.
|
// walkDecl walks an ODCL node.
|
||||||
func walkDecl(n *ir.Decl) ir.Node {
|
func walkDecl(n *ir.Decl) ir.Node {
|
||||||
v := n.X.(*ir.Name)
|
v := n.X
|
||||||
if v.Class_ == ir.PAUTOHEAP {
|
if v.Class == ir.PAUTOHEAP {
|
||||||
if base.Flag.CompilingRuntime {
|
if base.Flag.CompilingRuntime {
|
||||||
base.Errorf("%v escapes to heap, not allowed in runtime", v)
|
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
|
nn.Def = true
|
||||||
return walkStmt(typecheck.Stmt(nn))
|
return walkStmt(typecheck.Stmt(nn))
|
||||||
}
|
}
|
||||||
@ -191,9 +190,8 @@ func walkDecl(n *ir.Decl) ir.Node {
|
|||||||
// walkFor walks an OFOR or OFORUNTIL node.
|
// walkFor walks an OFOR or OFORUNTIL node.
|
||||||
func walkFor(n *ir.ForStmt) ir.Node {
|
func walkFor(n *ir.ForStmt) ir.Node {
|
||||||
if n.Cond != nil {
|
if n.Cond != nil {
|
||||||
walkStmtList(n.Cond.Init())
|
init := ir.TakeInit(n.Cond)
|
||||||
init := n.Cond.Init()
|
walkStmtList(init)
|
||||||
n.Cond.PtrInit().Set(nil)
|
|
||||||
n.Cond = walkExpr(n.Cond, &init)
|
n.Cond = walkExpr(n.Cond, &init)
|
||||||
n.Cond = ir.InitExpr(init, n.Cond)
|
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:
|
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
|
||||||
call := call.(*ir.CallExpr)
|
call := call.(*ir.CallExpr)
|
||||||
if len(call.Body) > 0 {
|
if len(call.KeepAlive) > 0 {
|
||||||
n.Call = wrapCall(call, &init)
|
n.Call = wrapCall(call, &init)
|
||||||
} else {
|
} else {
|
||||||
n.Call = walkExpr(call, &init)
|
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 {
|
func wrapCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||||
if len(n.Init()) != 0 {
|
if len(n.Init()) != 0 {
|
||||||
walkStmtList(n.Init())
|
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
|
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
|
last := len(n.Args) - 1
|
||||||
if va := n.Args[last]; va.Op() == ir.OSLICELIT {
|
if va := n.Args[last]; va.Op() == ir.OSLICELIT {
|
||||||
va := va.(*ir.CompLitExpr)
|
va := va.(*ir.CompLitExpr)
|
||||||
n.Args.Set(append(n.Args[:last], va.List...))
|
n.Args = append(n.Args[:last], va.List...)
|
||||||
n.IsDDD = false
|
n.IsDDD = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,10 +201,15 @@ func (s *exprSwitch) flush() {
|
|||||||
|
|
||||||
// Merge consecutive integer cases.
|
// Merge consecutive integer cases.
|
||||||
if s.exprname.Type().IsInteger() {
|
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]
|
merged := cc[:1]
|
||||||
for _, c := range cc[1:] {
|
for _, c := range cc[1:] {
|
||||||
last := &merged[len(merged)-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
|
last.hi = c.lo
|
||||||
} else {
|
} else {
|
||||||
merged = append(merged, c)
|
merged = append(merged, c)
|
||||||
@ -440,7 +445,7 @@ type typeClause struct {
|
|||||||
body ir.Nodes
|
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
|
var body ir.Nodes
|
||||||
if caseVar != nil {
|
if caseVar != nil {
|
||||||
l := []ir.Node{
|
l := []ir.Node{
|
||||||
@ -450,7 +455,7 @@ func (s *typeSwitch) Add(pos src.XPos, typ *types.Type, caseVar, jmp ir.Node) {
|
|||||||
typecheck.Stmts(l)
|
typecheck.Stmts(l)
|
||||||
body.Append(l...)
|
body.Append(l...)
|
||||||
} else {
|
} else {
|
||||||
caseVar = ir.BlankNode
|
caseVar = ir.BlankNode.(*ir.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cv, ok = iface.(type)
|
// cv, ok = iface.(type)
|
||||||
|
@ -37,36 +37,6 @@ func Walk(fn *ir.Func) {
|
|||||||
|
|
||||||
lno := base.Pos
|
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
|
base.Pos = lno
|
||||||
if base.Errors() > errorsBefore {
|
if base.Errors() > errorsBefore {
|
||||||
return
|
return
|
||||||
@ -91,7 +61,7 @@ func Walk(fn *ir.Func) {
|
|||||||
|
|
||||||
func paramoutheap(fn *ir.Func) bool {
|
func paramoutheap(fn *ir.Func) bool {
|
||||||
for _, ln := range fn.Dcl {
|
for _, ln := range fn.Dcl {
|
||||||
switch ln.Class_ {
|
switch ln.Class {
|
||||||
case ir.PPARAMOUT:
|
case ir.PPARAMOUT:
|
||||||
if ir.IsParamStackCopy(ln) || ln.Addrtaken() {
|
if ir.IsParamStackCopy(ln) || ln.Addrtaken() {
|
||||||
return true
|
return true
|
||||||
@ -111,8 +81,7 @@ func walkRecv(n *ir.UnaryExpr) ir.Node {
|
|||||||
if n.Typecheck() == 0 {
|
if n.Typecheck() == 0 {
|
||||||
base.Fatalf("missing typecheck: %+v", n)
|
base.Fatalf("missing typecheck: %+v", n)
|
||||||
}
|
}
|
||||||
init := n.Init()
|
init := ir.TakeInit(n)
|
||||||
n.PtrInit().Set(nil)
|
|
||||||
|
|
||||||
n.X = walkExpr(n.X, &init)
|
n.X = walkExpr(n.X, &init)
|
||||||
call := walkExpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, typecheck.NodNil()), &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 {
|
if stackcopy := v.Name().Stackcopy; stackcopy != nil {
|
||||||
nn = append(nn, walkStmt(ir.NewDecl(base.Pos, ir.ODCL, v)))
|
nn = append(nn, walkStmt(ir.NewDecl(base.Pos, ir.ODCL, v.(*ir.Name))))
|
||||||
if stackcopy.Class_ == ir.PPARAM {
|
if stackcopy.Class == ir.PPARAM {
|
||||||
nn = append(nn, walkStmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, v, stackcopy))))
|
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 {
|
if v == nil {
|
||||||
continue
|
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))))
|
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 wrapCall_prgen int
|
||||||
|
|
||||||
var walkCheckPtrArithmeticMarker byte
|
|
||||||
|
|
||||||
// appendWalkStmt typechecks and walks stmt and then appends it to init.
|
// appendWalkStmt typechecks and walks stmt and then appends it to init.
|
||||||
func appendWalkStmt(init *ir.Nodes, stmt ir.Node) {
|
func appendWalkStmt(init *ir.Nodes, stmt ir.Node) {
|
||||||
op := stmt.Op()
|
op := stmt.Op()
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
var never bool
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
{
|
{
|
||||||
type X struct {
|
type X struct {
|
||||||
@ -115,4 +117,16 @@ func main() {
|
|||||||
panic("g() != 2")
|
panic("g() != 2")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var g func() int
|
||||||
|
q := 0
|
||||||
|
q, g = 1, func() int { return q }
|
||||||
|
if never {
|
||||||
|
g = func() int { return 2 }
|
||||||
|
}
|
||||||
|
if g() != 1 {
|
||||||
|
panic("g() != 1")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ func main() {
|
|||||||
_ = string("a", "b", nil) // ERROR "too many arguments (to conversion to string: string\(.a., .b., nil\))?"
|
_ = string("a", "b", nil) // ERROR "too many arguments (to conversion to string: string\(.a., .b., nil\))?"
|
||||||
_ = []byte() // ERROR "missing argument (to conversion to \[\]byte: \(\[\]byte\)\(\))?"
|
_ = []byte() // ERROR "missing argument (to conversion to \[\]byte: \(\[\]byte\)\(\))?"
|
||||||
_ = string() // ERROR "missing argument (to conversion to string: string\(\))?"
|
_ = string() // ERROR "missing argument (to conversion to string: string\(\))?"
|
||||||
|
_ = *int() // ERROR "missing argument (to conversion to int: int\(\))?"
|
||||||
|
_ = (*int)() // ERROR "missing argument (to conversion to \*int: \(\*int\)\(\))?"
|
||||||
_ = name("a", 1, 3.3) // ERROR "too many arguments (to conversion to name: name\(.a., 1, 3.3\))?"
|
_ = name("a", 1, 3.3) // ERROR "too many arguments (to conversion to name: name\(.a., 1, 3.3\))?"
|
||||||
_ = map[string]string(nil, nil) // ERROR "too many arguments (to conversion to map\[string\]string: \(map\[string\]string\)\(nil, nil\))?"
|
_ = map[string]string(nil, nil) // ERROR "too many arguments (to conversion to map\[string\]string: \(map\[string\]string\)\(nil, nil\))?"
|
||||||
}
|
}
|
||||||
|
113
test/fixedbugs/issue23017.go
Normal file
113
test/fixedbugs/issue23017.go
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// run
|
||||||
|
|
||||||
|
// Copyright 2020 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.
|
||||||
|
|
||||||
|
// assignment order in multiple assignments.
|
||||||
|
// See issue #23017
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var m = map[int]int{}
|
||||||
|
var p *int
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
check(1, len(m))
|
||||||
|
check(42, m[2])
|
||||||
|
}()
|
||||||
|
m[2], *p = 42, 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var m = map[int]int{}
|
||||||
|
p := []int{}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
check(1, len(m))
|
||||||
|
check(2, m[2])
|
||||||
|
}()
|
||||||
|
m[2], p[1] = 2, 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
type P struct{ i int }
|
||||||
|
var m = map[int]int{}
|
||||||
|
var p *P
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
check(1, len(m))
|
||||||
|
check(3, m[2])
|
||||||
|
}()
|
||||||
|
m[2], p.i = 3, 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
type T struct{ i int }
|
||||||
|
var x T
|
||||||
|
p := &x
|
||||||
|
p, p.i = new(T), 4
|
||||||
|
check(4, x.i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var m map[int]int
|
||||||
|
var a int
|
||||||
|
var p = &a
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
check(5, *p)
|
||||||
|
}()
|
||||||
|
*p, m[2] = 5, 2
|
||||||
|
}
|
||||||
|
|
||||||
|
var g int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var m map[int]int
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
check(0, g)
|
||||||
|
}()
|
||||||
|
m[0], g = 1, 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
type T struct{ x struct{ y int } }
|
||||||
|
var x T
|
||||||
|
p := &x
|
||||||
|
p, p.x.y = new(T), 7
|
||||||
|
check(7, x.x.y)
|
||||||
|
check(0, p.x.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
type T *struct{ x struct{ y int } }
|
||||||
|
x := struct{ y int }{0}
|
||||||
|
var q T = &struct{ x struct{ y int } }{x}
|
||||||
|
p := q
|
||||||
|
p, p.x.y = nil, 7
|
||||||
|
check(7, q.x.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
x, y := 1, 2
|
||||||
|
x, y = y, x
|
||||||
|
check(2, x)
|
||||||
|
check(1, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(want, got int) {
|
||||||
|
if want != got {
|
||||||
|
panic(fmt.Sprintf("wanted %d, but got %d", want, got))
|
||||||
|
}
|
||||||
|
}
|
124
test/fixedbugs/issue43384.go
Normal file
124
test/fixedbugs/issue43384.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// errorcheck
|
||||||
|
|
||||||
|
// Copyright 2020 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 p
|
||||||
|
|
||||||
|
type T int
|
||||||
|
|
||||||
|
func (T) Mv() {}
|
||||||
|
func (*T) Mp() {}
|
||||||
|
|
||||||
|
type P1 struct{ T }
|
||||||
|
type P2 struct{ *T }
|
||||||
|
type P3 *struct{ T }
|
||||||
|
type P4 *struct{ *T }
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
{
|
||||||
|
var p P1
|
||||||
|
p.Mv()
|
||||||
|
(&p).Mv()
|
||||||
|
(*&p).Mv()
|
||||||
|
p.Mp()
|
||||||
|
(&p).Mp()
|
||||||
|
(*&p).Mp()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var p P2
|
||||||
|
p.Mv()
|
||||||
|
(&p).Mv()
|
||||||
|
(*&p).Mv()
|
||||||
|
p.Mp()
|
||||||
|
(&p).Mp()
|
||||||
|
(*&p).Mp()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var p P3
|
||||||
|
p.Mv() // ERROR "undefined"
|
||||||
|
(&p).Mv() // ERROR "undefined"
|
||||||
|
(*&p).Mv() // ERROR "undefined"
|
||||||
|
(**&p).Mv()
|
||||||
|
(*p).Mv()
|
||||||
|
(&*p).Mv()
|
||||||
|
p.Mp() // ERROR "undefined"
|
||||||
|
(&p).Mp() // ERROR "undefined"
|
||||||
|
(*&p).Mp() // ERROR "undefined"
|
||||||
|
(**&p).Mp()
|
||||||
|
(*p).Mp()
|
||||||
|
(&*p).Mp()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var p P4
|
||||||
|
p.Mv() // ERROR "undefined"
|
||||||
|
(&p).Mv() // ERROR "undefined"
|
||||||
|
(*&p).Mv() // ERROR "undefined"
|
||||||
|
(**&p).Mv()
|
||||||
|
(*p).Mv()
|
||||||
|
(&*p).Mv()
|
||||||
|
p.Mp() // ERROR "undefined"
|
||||||
|
(&p).Mp() // ERROR "undefined"
|
||||||
|
(*&p).Mp() // ERROR "undefined"
|
||||||
|
(**&p).Mp()
|
||||||
|
(*p).Mp()
|
||||||
|
(&*p).Mp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
type P5 struct{ T }
|
||||||
|
type P6 struct{ *T }
|
||||||
|
type P7 *struct{ T }
|
||||||
|
type P8 *struct{ *T }
|
||||||
|
|
||||||
|
{
|
||||||
|
var p P5
|
||||||
|
p.Mv()
|
||||||
|
(&p).Mv()
|
||||||
|
(*&p).Mv()
|
||||||
|
p.Mp()
|
||||||
|
(&p).Mp()
|
||||||
|
(*&p).Mp()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var p P6
|
||||||
|
p.Mv()
|
||||||
|
(&p).Mv()
|
||||||
|
(*&p).Mv()
|
||||||
|
p.Mp()
|
||||||
|
(&p).Mp()
|
||||||
|
(*&p).Mp()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var p P7
|
||||||
|
p.Mv() // ERROR "undefined"
|
||||||
|
(&p).Mv() // ERROR "undefined"
|
||||||
|
(*&p).Mv() // ERROR "undefined"
|
||||||
|
(**&p).Mv()
|
||||||
|
(*p).Mv()
|
||||||
|
(&*p).Mv()
|
||||||
|
p.Mp() // ERROR "undefined"
|
||||||
|
(&p).Mp() // ERROR "undefined"
|
||||||
|
(*&p).Mp() // ERROR "undefined"
|
||||||
|
(**&p).Mp()
|
||||||
|
(*p).Mp()
|
||||||
|
(&*p).Mp()
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var p P8
|
||||||
|
p.Mv() // ERROR "undefined"
|
||||||
|
(&p).Mv() // ERROR "undefined"
|
||||||
|
(*&p).Mv() // ERROR "undefined"
|
||||||
|
(**&p).Mv()
|
||||||
|
(*p).Mv()
|
||||||
|
(&*p).Mv()
|
||||||
|
p.Mp() // ERROR "undefined"
|
||||||
|
(&p).Mp() // ERROR "undefined"
|
||||||
|
(*&p).Mp() // ERROR "undefined"
|
||||||
|
(**&p).Mp()
|
||||||
|
(*p).Mp()
|
||||||
|
(&*p).Mp()
|
||||||
|
}
|
||||||
|
}
|
25
test/fixedbugs/issue43428.go
Normal file
25
test/fixedbugs/issue43428.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// errorcheck
|
||||||
|
|
||||||
|
// Copyright 2020 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 p
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type T int
|
||||||
|
|
||||||
|
func (T) Mv() {}
|
||||||
|
func (*T) Mp() {}
|
||||||
|
|
||||||
|
var _ = []int{
|
||||||
|
T.Mv, // ERROR "cannot use T\.Mv|incompatible type"
|
||||||
|
(*T).Mv, // ERROR "cannot use \(\*T\)\.Mv|incompatible type"
|
||||||
|
(*T).Mp, // ERROR "cannot use \(\*T\)\.Mp|incompatible type"
|
||||||
|
|
||||||
|
time.Time.GobEncode, // ERROR "cannot use time\.Time\.GobEncode|incompatible type"
|
||||||
|
(*time.Time).GobEncode, // ERROR "cannot use \(\*time\.Time\)\.GobEncode|incompatible type"
|
||||||
|
(*time.Time).GobDecode, // ERROR "cannot use \(\*time\.Time\)\.GobDecode|incompatible type"
|
||||||
|
|
||||||
|
}
|
28
test/fixedbugs/issue43444.go
Normal file
28
test/fixedbugs/issue43444.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// run
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
var sp = ""
|
||||||
|
|
||||||
|
func f(name string, _ ...interface{}) int {
|
||||||
|
print(sp, name)
|
||||||
|
sp = " "
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var a = f("a", x)
|
||||||
|
var b = f("b", y)
|
||||||
|
var c = f("c", z)
|
||||||
|
var d = func() int {
|
||||||
|
if false {
|
||||||
|
_ = z
|
||||||
|
}
|
||||||
|
return f("d")
|
||||||
|
}()
|
||||||
|
var e = f("e")
|
||||||
|
|
||||||
|
var x int
|
||||||
|
var y int = 42
|
||||||
|
var z int = func() int { return 42 }()
|
||||||
|
|
||||||
|
func main() { println() }
|
1
test/fixedbugs/issue43444.out
Normal file
1
test/fixedbugs/issue43444.out
Normal file
@ -0,0 +1 @@
|
|||||||
|
e a b c d
|
27
test/fixedbugs/issue43479.dir/a.go
Normal file
27
test/fixedbugs/issue43479.dir/a.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright 2020 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 a
|
||||||
|
|
||||||
|
type Here struct{ stuff int }
|
||||||
|
type Info struct{ Dir string }
|
||||||
|
|
||||||
|
func New() Here { return Here{} }
|
||||||
|
func (h Here) Dir(p string) (Info, error)
|
||||||
|
|
||||||
|
type I interface{ M(x string) }
|
||||||
|
|
||||||
|
type T = struct {
|
||||||
|
Here
|
||||||
|
I
|
||||||
|
}
|
||||||
|
|
||||||
|
var X T
|
||||||
|
|
||||||
|
var A = (*T).Dir
|
||||||
|
var B = T.Dir
|
||||||
|
var C = X.Dir
|
||||||
|
var D = (*T).M
|
||||||
|
var E = T.M
|
||||||
|
var F = X.M
|
38
test/fixedbugs/issue43479.dir/b.go
Normal file
38
test/fixedbugs/issue43479.dir/b.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2020 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 b
|
||||||
|
|
||||||
|
import "./a"
|
||||||
|
|
||||||
|
var Here = a.New()
|
||||||
|
var Dir = Here.Dir
|
||||||
|
|
||||||
|
type T = struct {
|
||||||
|
a.Here
|
||||||
|
a.I
|
||||||
|
}
|
||||||
|
|
||||||
|
var X T
|
||||||
|
|
||||||
|
// Test exporting the type of method values for anonymous structs with
|
||||||
|
// promoted methods.
|
||||||
|
var A = a.A
|
||||||
|
var B = a.B
|
||||||
|
var C = a.C
|
||||||
|
var D = a.D
|
||||||
|
var E = a.E
|
||||||
|
var F = a.F
|
||||||
|
var G = (*a.T).Dir
|
||||||
|
var H = a.T.Dir
|
||||||
|
var I = a.X.Dir
|
||||||
|
var J = (*a.T).M
|
||||||
|
var K = a.T.M
|
||||||
|
var L = a.X.M
|
||||||
|
var M = (*T).Dir
|
||||||
|
var N = T.Dir
|
||||||
|
var O = X.Dir
|
||||||
|
var P = (*T).M
|
||||||
|
var Q = T.M
|
||||||
|
var R = X.M
|
7
test/fixedbugs/issue43479.go
Normal file
7
test/fixedbugs/issue43479.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// compiledir
|
||||||
|
|
||||||
|
// Copyright 2020 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 ignored
|
33
test/fixedbugs/issue43480.go
Normal file
33
test/fixedbugs/issue43480.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// run
|
||||||
|
|
||||||
|
// Copyright 2020 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.
|
||||||
|
|
||||||
|
// Issue #43480: ICE on large uint64 constants in switch cases.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func isPow10(x uint64) bool {
|
||||||
|
switch x {
|
||||||
|
case 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
||||||
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var x uint64 = 1
|
||||||
|
|
||||||
|
for {
|
||||||
|
if !isPow10(x) || isPow10(x-1) || isPow10(x+1) {
|
||||||
|
panic(x)
|
||||||
|
}
|
||||||
|
next := x * 10
|
||||||
|
if next/10 != x {
|
||||||
|
break // overflow
|
||||||
|
}
|
||||||
|
x = next
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user