return loc.asHole()
}
-// canonicalNode returns the canonical *Node that n logically
-// represents.
-func canonicalNode(n ir.Node) ir.Node {
- if n != nil && n.Op() == ir.ONAME && n.Name().IsClosureVar() {
- n = n.Name().Defn
- if n.Name().IsClosureVar() {
- base.Fatalf("still closure var")
- }
- }
-
- return n
-}
-
func (e *escape) newLoc(n ir.Node, transient bool) *location {
if e.curfn == nil {
base.Fatalf("e.curfn isn't set")
base.ErrorfAt(n.Pos(), "%v is incomplete (or unallocatable); stack allocation disallowed", n.Type())
}
- n = canonicalNode(n)
+ if n != nil && n.Op() == ir.ONAME {
+ n = n.(*ir.Name).Canonical()
+ }
loc := &location{
n: n,
curfn: e.curfn,
}
func (b *batch) oldLoc(n *ir.Name) *location {
- n = canonicalNode(n).(*ir.Name)
- return n.Opt.(*location)
+ return n.Canonical().Opt.(*location)
}
func (l *location) asHole() hole {
// reassignment detection for use by inlining and devirtualization.
// isName reports whether n is a reference to name.
- isName := func(n Node) bool {
- if n, ok := n.(*Name); ok && n.Op() == ONAME {
- if n.IsClosureVar() && n.Defn != nil {
- n = n.Defn.(*Name)
- }
- return n == name
- }
- return false
+ isName := func(x Node) bool {
+ n, ok := x.(*Name)
+ return ok && n.Canonical() == name
}
var do func(n Node) bool
func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 }
func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 }
-func (n *Name) Byval() bool { return n.flags&nameByval != 0 }
func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 }
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
func (n *Name) Used() bool { return n.flags&nameUsed != 0 }
func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) }
func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) }
-func (n *Name) SetByval(b bool) { n.flags.set(nameByval, b) }
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
n.val = v
}
+// Canonical returns the logical declaration that n represents. If n
+// is a closure variable, then Canonical returns the original Name as
+// it appears in the function that immediately contains the
+// declaration. Otherwise, Canonical simply returns n itself.
+func (n *Name) Canonical() *Name {
+ if n.IsClosureVar() {
+ n = n.Defn.(*Name)
+ if n.IsClosureVar() {
+ base.Fatalf("recursive closure variable: %v", n)
+ }
+ }
+ return n
+}
+
+func (n *Name) SetByval(b bool) {
+ if n.Canonical() != n {
+ base.Fatalf("SetByval called on non-canonical variable: %v", n)
+ }
+ n.flags.set(nameByval, b)
+}
+
+func (n *Name) Byval() bool {
+ // We require byval to be set on the canonical variable, but we
+ // allow it to be accessed from any instance.
+ return n.Canonical().flags&nameByval != 0
+}
+
// SameSource reports whether two nodes refer to the same source
// element.
//
outermost := v.Defn.(*ir.Name)
// out parameters will be assigned to implicitly upon return.
- if outermost.Class != ir.PPARAMOUT && !outermost.Addrtaken() && !outermost.Assigned() && v.Type().Size() <= 128 {
- v.SetByval(true)
+ if outermost.Class != ir.PPARAMOUT && !outermost.Addrtaken() && !outermost.Assigned() && outermost.Type().Size() <= 128 {
+ outermost.SetByval(true)
} else {
outermost.SetAddrtaken(true)
}