mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a simple name to the right of the dot. Before this change this was represented by using an ONAME Node in the Right field. This ONAME node served no useful purpose. This CL changes these Node types to store the symbol in the Sym field instead, thus not requiring allocating a Node for each selector. When compiling x/tools/go/types this CL eliminates nearly 5000 calls to newname and reduces the total number of Nodes allocated by about 6.6%. It seems to cut compilation time by 1 to 2 percent. Getting this right was somewhat subtle, and I added two dubious changes to produce the exact same output as before. One is to ishairy in inl.go: the ONAME node increased the cost of ODOT and friends by 1, and I retained that, although really ODOT is not more expensive than any other node. The other is to varexpr in walk.go: because the ONAME in the Right field of an ODOT has no class, varexpr would always return false for an ODOT, although in fact for some ODOT's it seemingly ought to return true; I added an && false for now. I will send separate CLs, that will break toolstash -cmp, to clean these up. This CL passes toolstash -cmp. Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80 Reviewed-on: https://go-review.googlesource.com/20890 TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
fc6bcdee79
commit
5f525ca60d
22 changed files with 129 additions and 116 deletions
|
|
@ -112,7 +112,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
||||||
// A special case to make write barriers more efficient.
|
// A special case to make write barriers more efficient.
|
||||||
// Comparing the first field of a named struct can be done directly.
|
// Comparing the first field of a named struct can be done directly.
|
||||||
base := n1
|
base := n1
|
||||||
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Right.Sym {
|
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Sym {
|
||||||
base = n1.Left
|
base = n1.Left
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ func genhash(sym *Sym, t *Type) {
|
||||||
if algtype1(f.Type, nil) != AMEM {
|
if algtype1(f.Type, nil) != AMEM {
|
||||||
hashel := hashfor(f.Type)
|
hashel := hashfor(f.Type)
|
||||||
call := Nod(OCALL, hashel, nil)
|
call := Nod(OCALL, hashel, nil)
|
||||||
nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages?
|
nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
|
||||||
na := Nod(OADDR, nx, nil)
|
na := Nod(OADDR, nx, nil)
|
||||||
na.Etype = 1 // no escape to heap
|
na.Etype = 1 // no escape to heap
|
||||||
call.List.Append(na)
|
call.List.Append(na)
|
||||||
|
|
@ -258,7 +258,7 @@ func genhash(sym *Sym, t *Type) {
|
||||||
// h = hashel(&p.first, size, h)
|
// h = hashel(&p.first, size, h)
|
||||||
hashel := hashmem(f.Type)
|
hashel := hashmem(f.Type)
|
||||||
call := Nod(OCALL, hashel, nil)
|
call := Nod(OCALL, hashel, nil)
|
||||||
nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages?
|
nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
|
||||||
na := Nod(OADDR, nx, nil)
|
na := Nod(OADDR, nx, nil)
|
||||||
na.Etype = 1 // no escape to heap
|
na.Etype = 1 // no escape to heap
|
||||||
call.List.Append(na)
|
call.List.Append(na)
|
||||||
|
|
@ -436,7 +436,7 @@ func geneq(sym *Sym, t *Type) {
|
||||||
|
|
||||||
// Compare non-memory fields with field equality.
|
// Compare non-memory fields with field equality.
|
||||||
if algtype1(f.Type, nil) != AMEM {
|
if algtype1(f.Type, nil) != AMEM {
|
||||||
and(eqfield(np, nq, newname(f.Sym)))
|
and(eqfield(np, nq, f.Sym))
|
||||||
i++
|
i++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -449,11 +449,11 @@ func geneq(sym *Sym, t *Type) {
|
||||||
if s := fields[i:next]; len(s) <= 2 {
|
if s := fields[i:next]; len(s) <= 2 {
|
||||||
// Two or fewer fields: use plain field equality.
|
// Two or fewer fields: use plain field equality.
|
||||||
for _, f := range s {
|
for _, f := range s {
|
||||||
and(eqfield(np, nq, newname(f.Sym)))
|
and(eqfield(np, nq, f.Sym))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// More than two fields: use memequal.
|
// More than two fields: use memequal.
|
||||||
and(eqmem(np, nq, newname(f.Sym), size))
|
and(eqmem(np, nq, f.Sym, size))
|
||||||
}
|
}
|
||||||
i = next
|
i = next
|
||||||
}
|
}
|
||||||
|
|
@ -502,19 +502,19 @@ func geneq(sym *Sym, t *Type) {
|
||||||
|
|
||||||
// eqfield returns the node
|
// eqfield returns the node
|
||||||
// p.field == q.field
|
// p.field == q.field
|
||||||
func eqfield(p *Node, q *Node, field *Node) *Node {
|
func eqfield(p *Node, q *Node, field *Sym) *Node {
|
||||||
nx := Nod(OXDOT, p, field)
|
nx := NodSym(OXDOT, p, field)
|
||||||
ny := Nod(OXDOT, q, field)
|
ny := NodSym(OXDOT, q, field)
|
||||||
ne := Nod(OEQ, nx, ny)
|
ne := Nod(OEQ, nx, ny)
|
||||||
return ne
|
return ne
|
||||||
}
|
}
|
||||||
|
|
||||||
// eqmem returns the node
|
// eqmem returns the node
|
||||||
// memequal(&p.field, &q.field [, size])
|
// memequal(&p.field, &q.field [, size])
|
||||||
func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
|
func eqmem(p *Node, q *Node, field *Sym, size int64) *Node {
|
||||||
nx := Nod(OADDR, Nod(OXDOT, p, field), nil)
|
nx := Nod(OADDR, NodSym(OXDOT, p, field), nil)
|
||||||
nx.Etype = 1 // does not escape
|
nx.Etype = 1 // does not escape
|
||||||
ny := Nod(OADDR, Nod(OXDOT, q, field), nil)
|
ny := Nod(OADDR, NodSym(OXDOT, q, field), nil)
|
||||||
ny.Etype = 1 // does not escape
|
ny.Etype = 1 // does not escape
|
||||||
typecheck(&nx, Erv)
|
typecheck(&nx, Erv)
|
||||||
typecheck(&ny, Erv)
|
typecheck(&ny, Erv)
|
||||||
|
|
|
||||||
|
|
@ -890,7 +890,7 @@ func (p *exporter) node(n *Node) {
|
||||||
|
|
||||||
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
|
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
|
||||||
p.node(n.Left)
|
p.node(n.Left)
|
||||||
p.sym(n.Right.Sym)
|
p.sym(n.Sym)
|
||||||
|
|
||||||
case ODOTTYPE, ODOTTYPE2:
|
case ODOTTYPE, ODOTTYPE2:
|
||||||
p.node(n.Left)
|
p.node(n.Left)
|
||||||
|
|
|
||||||
|
|
@ -658,7 +658,7 @@ func (p *importer) node() *Node {
|
||||||
obj.Used = true
|
obj.Used = true
|
||||||
return oldname(s)
|
return oldname(s)
|
||||||
}
|
}
|
||||||
return Nod(OXDOT, obj, newname(sel))
|
return NodSym(OXDOT, obj, sel)
|
||||||
|
|
||||||
case ODOTTYPE, ODOTTYPE2:
|
case ODOTTYPE, ODOTTYPE2:
|
||||||
n.Left = p.node()
|
n.Left = p.node()
|
||||||
|
|
|
||||||
|
|
@ -802,7 +802,7 @@ func cgen_wbptr(n, res *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wbVar := syslook("writeBarrier")
|
wbVar := syslook("writeBarrier")
|
||||||
wbEnabled := Nod(ODOT, wbVar, newname(wbVar.Type.Field(0).Sym))
|
wbEnabled := NodSym(ODOT, wbVar, wbVar.Type.Field(0).Sym)
|
||||||
wbEnabled = typecheck(&wbEnabled, Erv)
|
wbEnabled = typecheck(&wbEnabled, Erv)
|
||||||
pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
|
pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
|
||||||
Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
|
Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
|
||||||
|
|
@ -2440,11 +2440,6 @@ func cgen_callinter(n *Node, res *Node, proc int) {
|
||||||
Fatalf("cgen_callinter: not ODOTINTER %v", Oconv(i.Op, 0))
|
Fatalf("cgen_callinter: not ODOTINTER %v", Oconv(i.Op, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
f := i.Right // field
|
|
||||||
if f.Op != ONAME {
|
|
||||||
Fatalf("cgen_callinter: not ONAME %v", Oconv(f.Op, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
i = i.Left // interface
|
i = i.Left // interface
|
||||||
|
|
||||||
if !i.Addable {
|
if !i.Addable {
|
||||||
|
|
|
||||||
|
|
@ -462,7 +462,7 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
|
||||||
return clos
|
return clos
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckpartialcall(fn *Node, sym *Node) {
|
func typecheckpartialcall(fn *Node, sym *Sym) {
|
||||||
switch fn.Op {
|
switch fn.Op {
|
||||||
case ODOTINTER, ODOTMETH:
|
case ODOTINTER, ODOTMETH:
|
||||||
break
|
break
|
||||||
|
|
@ -474,21 +474,21 @@ func typecheckpartialcall(fn *Node, sym *Node) {
|
||||||
// Create top-level function.
|
// Create top-level function.
|
||||||
xfunc := makepartialcall(fn, fn.Type, sym)
|
xfunc := makepartialcall(fn, fn.Type, sym)
|
||||||
fn.Func = xfunc.Func
|
fn.Func = xfunc.Func
|
||||||
fn.Right = sym
|
fn.Right = newname(sym)
|
||||||
fn.Op = OCALLPART
|
fn.Op = OCALLPART
|
||||||
fn.Type = xfunc.Type
|
fn.Type = xfunc.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
var makepartialcall_gopkg *Pkg
|
var makepartialcall_gopkg *Pkg
|
||||||
|
|
||||||
func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
|
func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
|
||||||
var p string
|
var p string
|
||||||
|
|
||||||
rcvrtype := fn.Left.Type
|
rcvrtype := fn.Left.Type
|
||||||
if exportname(meth.Sym.Name) {
|
if exportname(meth.Name) {
|
||||||
p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Sym.Name)
|
p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Name)
|
||||||
} else {
|
} else {
|
||||||
p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), Sconv(meth.Sym, FmtLeft))
|
p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), Sconv(meth, FmtLeft))
|
||||||
}
|
}
|
||||||
basetype := rcvrtype
|
basetype := rcvrtype
|
||||||
if Isptr[rcvrtype.Etype] {
|
if Isptr[rcvrtype.Etype] {
|
||||||
|
|
@ -592,7 +592,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
|
||||||
body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
|
body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
|
||||||
}
|
}
|
||||||
|
|
||||||
call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
|
call := Nod(OCALL, NodSym(OXDOT, ptr, meth), nil)
|
||||||
call.List.Set(callargs)
|
call.List.Set(callargs)
|
||||||
call.Isddd = ddd
|
call.Isddd = ddd
|
||||||
if t0.Results().NumFields() == 0 {
|
if t0.Results().NumFields() == 0 {
|
||||||
|
|
|
||||||
|
|
@ -1432,7 +1432,7 @@ func (c *nowritebarrierrecChecker) visitcode(n *Node) {
|
||||||
func (c *nowritebarrierrecChecker) visitcall(n *Node) {
|
func (c *nowritebarrierrecChecker) visitcall(n *Node) {
|
||||||
fn := n.Left
|
fn := n.Left
|
||||||
if n.Op == OCALLMETH {
|
if n.Op == OCALLMETH {
|
||||||
fn = n.Left.Right.Sym.Def
|
fn = n.Left.Sym.Def
|
||||||
}
|
}
|
||||||
if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
|
if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
|
||||||
if n.Op == OCALLFUNC || n.Op == OCALLMETH {
|
if n.Op == OCALLFUNC || n.Op == OCALLMETH {
|
||||||
fn := n.Left
|
fn := n.Left
|
||||||
if n.Op == OCALLMETH {
|
if n.Op == OCALLMETH {
|
||||||
fn = n.Left.Right.Sym.Def
|
fn = n.Left.Sym.Def
|
||||||
}
|
}
|
||||||
if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil {
|
if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil {
|
||||||
m := v.visit(fn.Name.Defn)
|
m := v.visit(fn.Name.Defn)
|
||||||
|
|
@ -1421,7 +1421,7 @@ func esccall(e *EscState, n *Node, up *Node) {
|
||||||
indirect = fn.Op != ONAME || fn.Class != PFUNC
|
indirect = fn.Op != ONAME || fn.Class != PFUNC
|
||||||
|
|
||||||
case OCALLMETH:
|
case OCALLMETH:
|
||||||
fn = n.Left.Right.Sym.Def
|
fn = n.Left.Sym.Def
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
fntype = fn.Type
|
fntype = fn.Type
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1249,12 +1249,7 @@ func exprfmt(n *Node, prec int) string {
|
||||||
}
|
}
|
||||||
return ":"
|
return ":"
|
||||||
|
|
||||||
case OXDOT,
|
case OCALLPART:
|
||||||
ODOT,
|
|
||||||
ODOTPTR,
|
|
||||||
ODOTINTER,
|
|
||||||
ODOTMETH,
|
|
||||||
OCALLPART:
|
|
||||||
var f string
|
var f string
|
||||||
f += exprfmt(n.Left, nprec)
|
f += exprfmt(n.Left, nprec)
|
||||||
if n.Right == nil || n.Right.Sym == nil {
|
if n.Right == nil || n.Right.Sym == nil {
|
||||||
|
|
@ -1264,6 +1259,16 @@ func exprfmt(n *Node, prec int) string {
|
||||||
f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, FmtShort|FmtByte))
|
f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, FmtShort|FmtByte))
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
||||||
|
var f string
|
||||||
|
f += exprfmt(n.Left, nprec)
|
||||||
|
if n.Sym == nil {
|
||||||
|
f += ".<nil>"
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
f += fmt.Sprintf(".%v", Sconv(n.Sym, FmtShort|FmtByte))
|
||||||
|
return f
|
||||||
|
|
||||||
case ODOTTYPE, ODOTTYPE2:
|
case ODOTTYPE, ODOTTYPE2:
|
||||||
var f string
|
var f string
|
||||||
f += exprfmt(n.Left, nprec)
|
f += exprfmt(n.Left, nprec)
|
||||||
|
|
|
||||||
|
|
@ -948,7 +948,7 @@ func cgen_callmeth(n *Node, proc int) {
|
||||||
|
|
||||||
n2 := *n
|
n2 := *n
|
||||||
n2.Op = OCALLFUNC
|
n2.Op = OCALLFUNC
|
||||||
n2.Left = l.Right
|
n2.Left = newname(l.Sym)
|
||||||
n2.Left.Type = l.Type
|
n2.Left.Type = l.Type
|
||||||
|
|
||||||
if n2.Left.Op == ONAME {
|
if n2.Left.Op == ONAME {
|
||||||
|
|
|
||||||
|
|
@ -416,7 +416,7 @@ func Naddr(a *obj.Addr, n *Node) {
|
||||||
// A special case to make write barriers more efficient.
|
// A special case to make write barriers more efficient.
|
||||||
// Taking the address of the first field of a named struct
|
// Taking the address of the first field of a named struct
|
||||||
// is the same as taking the address of the struct.
|
// is the same as taking the address of the struct.
|
||||||
if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Field(0).Sym != n.Right.Sym {
|
if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Field(0).Sym != n.Sym {
|
||||||
Debug['h'] = 1
|
Debug['h'] = 1
|
||||||
Dump("naddr", n)
|
Dump("naddr", n)
|
||||||
Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a))
|
Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a))
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,13 @@ func ishairy(n *Node, budget *int) bool {
|
||||||
ODCLTYPE, // can't print yet
|
ODCLTYPE, // can't print yet
|
||||||
ORETJMP:
|
ORETJMP:
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER:
|
||||||
|
// These used to store the symbol name as an ONAME in
|
||||||
|
// the Right field, meaning that it cost one budget
|
||||||
|
// unit. Stay compatible for now.
|
||||||
|
// TODO(iant): Remove this.
|
||||||
|
(*budget)--
|
||||||
}
|
}
|
||||||
|
|
||||||
(*budget)--
|
(*budget)--
|
||||||
|
|
|
||||||
|
|
@ -1793,7 +1793,7 @@ func (p *parser) new_dotname(obj *Node) *Node {
|
||||||
obj.Used = true
|
obj.Used = true
|
||||||
return oldname(s)
|
return oldname(s)
|
||||||
}
|
}
|
||||||
return Nod(OXDOT, obj, newname(sel))
|
return NodSym(OXDOT, obj, sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) dotname() *Node {
|
func (p *parser) dotname() *Node {
|
||||||
|
|
|
||||||
|
|
@ -226,27 +226,27 @@ func walkrange(n *Node) {
|
||||||
hit := prealloc[n]
|
hit := prealloc[n]
|
||||||
hit.Type = th
|
hit.Type = th
|
||||||
n.Left = nil
|
n.Left = nil
|
||||||
keyname := newname(th.Field(0).Sym) // depends on layout of iterator struct. See reflect.go:hiter
|
keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter
|
||||||
valname := newname(th.Field(1).Sym) // ditto
|
valsym := th.Field(1).Sym // ditto
|
||||||
|
|
||||||
fn := syslook("mapiterinit")
|
fn := syslook("mapiterinit")
|
||||||
|
|
||||||
substArgTypes(&fn, t.Key(), t.Type, th)
|
substArgTypes(&fn, t.Key(), t.Type, th)
|
||||||
init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
|
init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
|
||||||
n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil())
|
n.Left = Nod(ONE, NodSym(ODOT, hit, keysym), nodnil())
|
||||||
|
|
||||||
fn = syslook("mapiternext")
|
fn = syslook("mapiternext")
|
||||||
substArgTypes(&fn, th)
|
substArgTypes(&fn, th)
|
||||||
n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
|
n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
|
||||||
|
|
||||||
key := Nod(ODOT, hit, keyname)
|
key := NodSym(ODOT, hit, keysym)
|
||||||
key = Nod(OIND, key, nil)
|
key = Nod(OIND, key, nil)
|
||||||
if v1 == nil {
|
if v1 == nil {
|
||||||
body = nil
|
body = nil
|
||||||
} else if v2 == nil {
|
} else if v2 == nil {
|
||||||
body = []*Node{Nod(OAS, v1, key)}
|
body = []*Node{Nod(OAS, v1, key)}
|
||||||
} else {
|
} else {
|
||||||
val := Nod(ODOT, hit, valname)
|
val := NodSym(ODOT, hit, valsym)
|
||||||
val = Nod(OIND, val, nil)
|
val = Nod(OIND, val, nil)
|
||||||
a := Nod(OAS2, nil, nil)
|
a := Nod(OAS2, nil, nil)
|
||||||
a.List.Set([]*Node{v1, v2})
|
a.List.Set([]*Node{v1, v2})
|
||||||
|
|
|
||||||
|
|
@ -574,10 +574,10 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
|
||||||
case OARRAYLIT:
|
case OARRAYLIT:
|
||||||
if value.Type.Bound < 0 {
|
if value.Type.Bound < 0 {
|
||||||
if pass == 1 && ctxt != 0 {
|
if pass == 1 && ctxt != 0 {
|
||||||
a = Nod(ODOT, var_, newname(index.Sym))
|
a = NodSym(ODOT, var_, index.Sym)
|
||||||
slicelit(ctxt, value, a, init)
|
slicelit(ctxt, value, a, init)
|
||||||
} else if pass == 2 && ctxt == 0 {
|
} else if pass == 2 && ctxt == 0 {
|
||||||
a = Nod(ODOT, var_, newname(index.Sym))
|
a = NodSym(ODOT, var_, index.Sym)
|
||||||
slicelit(ctxt, value, a, init)
|
slicelit(ctxt, value, a, init)
|
||||||
} else if pass == 3 {
|
} else if pass == 3 {
|
||||||
break
|
break
|
||||||
|
|
@ -585,12 +585,12 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
a = Nod(ODOT, var_, newname(index.Sym))
|
a = NodSym(ODOT, var_, index.Sym)
|
||||||
arraylit(ctxt, pass, value, a, init)
|
arraylit(ctxt, pass, value, a, init)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
case OSTRUCTLIT:
|
case OSTRUCTLIT:
|
||||||
a = Nod(ODOT, var_, newname(index.Sym))
|
a = NodSym(ODOT, var_, index.Sym)
|
||||||
structlit(ctxt, pass, value, a, init)
|
structlit(ctxt, pass, value, a, init)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -605,7 +605,7 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
|
||||||
|
|
||||||
// build list of var.field = expr
|
// build list of var.field = expr
|
||||||
setlineno(value)
|
setlineno(value)
|
||||||
a = Nod(ODOT, var_, newname(index.Sym))
|
a = NodSym(ODOT, var_, index.Sym)
|
||||||
|
|
||||||
a = Nod(OAS, a, value)
|
a = Nod(OAS, a, value)
|
||||||
typecheck(&a, Etop)
|
typecheck(&a, Etop)
|
||||||
|
|
@ -904,7 +904,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
|
||||||
a = Nodintconst(b)
|
a = Nodintconst(b)
|
||||||
|
|
||||||
a = Nod(OINDEX, vstat, a)
|
a = Nod(OINDEX, vstat, a)
|
||||||
a = Nod(ODOT, a, newname(syma))
|
a = NodSym(ODOT, a, syma)
|
||||||
a = Nod(OAS, a, index)
|
a = Nod(OAS, a, index)
|
||||||
typecheck(&a, Etop)
|
typecheck(&a, Etop)
|
||||||
walkexpr(&a, init)
|
walkexpr(&a, init)
|
||||||
|
|
@ -916,7 +916,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
|
||||||
a = Nodintconst(b)
|
a = Nodintconst(b)
|
||||||
|
|
||||||
a = Nod(OINDEX, vstat, a)
|
a = Nod(OINDEX, vstat, a)
|
||||||
a = Nod(ODOT, a, newname(symb))
|
a = NodSym(ODOT, a, symb)
|
||||||
a = Nod(OAS, a, value)
|
a = Nod(OAS, a, value)
|
||||||
typecheck(&a, Etop)
|
typecheck(&a, Etop)
|
||||||
walkexpr(&a, init)
|
walkexpr(&a, init)
|
||||||
|
|
@ -935,11 +935,11 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
|
||||||
|
|
||||||
a = Nod(OINDEX, vstat, index)
|
a = Nod(OINDEX, vstat, index)
|
||||||
a.Bounded = true
|
a.Bounded = true
|
||||||
a = Nod(ODOT, a, newname(symb))
|
a = NodSym(ODOT, a, symb)
|
||||||
|
|
||||||
r := Nod(OINDEX, vstat, index)
|
r := Nod(OINDEX, vstat, index)
|
||||||
r.Bounded = true
|
r.Bounded = true
|
||||||
r = Nod(ODOT, r, newname(syma))
|
r = NodSym(ODOT, r, syma)
|
||||||
r = Nod(OINDEX, var_, r)
|
r = Nod(OINDEX, var_, r)
|
||||||
|
|
||||||
r = Nod(OAS, r, a)
|
r = Nod(OAS, r, a)
|
||||||
|
|
|
||||||
|
|
@ -2326,16 +2326,14 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
|
||||||
if fn.Op != ODOTMETH {
|
if fn.Op != ODOTMETH {
|
||||||
Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
|
Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
|
||||||
}
|
}
|
||||||
if fn.Right.Op != ONAME {
|
|
||||||
Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
|
|
||||||
}
|
|
||||||
if k == callNormal {
|
if k == callNormal {
|
||||||
sym = fn.Right.Sym
|
sym = fn.Sym
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
n2 := *fn.Right
|
n2 := newname(fn.Sym)
|
||||||
n2.Class = PFUNC
|
n2.Class = PFUNC
|
||||||
closure = s.expr(&n2)
|
n2.Lineno = fn.Lineno
|
||||||
|
closure = s.expr(n2)
|
||||||
// Note: receiver is already assigned in n.List, so we don't
|
// Note: receiver is already assigned in n.List, so we don't
|
||||||
// want to set it here.
|
// want to set it here.
|
||||||
case OCALLINTER:
|
case OCALLINTER:
|
||||||
|
|
@ -3967,14 +3965,14 @@ func AutoVar(v *ssa.Value) (*Node, int64) {
|
||||||
// fieldIdx finds the index of the field referred to by the ODOT node n.
|
// fieldIdx finds the index of the field referred to by the ODOT node n.
|
||||||
func fieldIdx(n *Node) int {
|
func fieldIdx(n *Node) int {
|
||||||
t := n.Left.Type
|
t := n.Left.Type
|
||||||
f := n.Right
|
f := n.Sym
|
||||||
if t.Etype != TSTRUCT {
|
if t.Etype != TSTRUCT {
|
||||||
panic("ODOT's LHS is not a struct")
|
panic("ODOT's LHS is not a struct")
|
||||||
}
|
}
|
||||||
|
|
||||||
var i int
|
var i int
|
||||||
for _, t1 := range t.Fields().Slice() {
|
for _, t1 := range t.Fields().Slice() {
|
||||||
if t1.Sym != f.Sym {
|
if t1.Sym != f {
|
||||||
i++
|
i++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,14 @@ func Nod(op Op, nleft *Node, nright *Node) *Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodSym makes a Node with Op op and with the Left field set to left
|
||||||
|
// and the Sym field set to sym. This is for ODOT and friends.
|
||||||
|
func NodSym(op Op, left *Node, sym *Sym) *Node {
|
||||||
|
n := Nod(op, left, nil)
|
||||||
|
n.Sym = sym
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
func saveorignode(n *Node) {
|
func saveorignode(n *Node) {
|
||||||
if n.Orig != nil {
|
if n.Orig != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -1677,10 +1685,7 @@ func adddot(n *Node) *Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Right.Op != ONAME {
|
s := n.Sym
|
||||||
return n
|
|
||||||
}
|
|
||||||
s := n.Right.Sym
|
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
@ -1689,7 +1694,7 @@ func adddot(n *Node) *Node {
|
||||||
case path != nil:
|
case path != nil:
|
||||||
// rebuild elided dots
|
// rebuild elided dots
|
||||||
for c := len(path) - 1; c >= 0; c-- {
|
for c := len(path) - 1; c >= 0; c-- {
|
||||||
n.Left = Nod(ODOT, n.Left, newname(path[c].field.Sym))
|
n.Left = NodSym(ODOT, n.Left, path[c].field.Sym)
|
||||||
n.Left.Implicit = true
|
n.Left.Implicit = true
|
||||||
}
|
}
|
||||||
case ambig:
|
case ambig:
|
||||||
|
|
@ -1960,7 +1965,7 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
|
||||||
fn.Nbody.Append(n)
|
fn.Nbody.Append(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
dot := adddot(Nod(OXDOT, this.Left, newname(method.Sym)))
|
dot := adddot(NodSym(OXDOT, this.Left, method.Sym))
|
||||||
|
|
||||||
// generate call
|
// generate call
|
||||||
if !instrumenting && Isptr[rcvr.Etype] && Isptr[methodrcvr.Etype] && method.Embedded != 0 && !isifacemethod(method.Type) {
|
if !instrumenting && Isptr[rcvr.Etype] && Isptr[methodrcvr.Etype] && method.Embedded != 0 && !isifacemethod(method.Type) {
|
||||||
|
|
|
||||||
|
|
@ -595,14 +595,14 @@ func (s *typeSwitch) walk(sw *Node) {
|
||||||
|
|
||||||
if !isnilinter(cond.Right.Type) {
|
if !isnilinter(cond.Right.Type) {
|
||||||
// Load type from itab.
|
// Load type from itab.
|
||||||
typ = Nod(ODOTPTR, typ, nil)
|
typ = NodSym(ODOTPTR, typ, nil)
|
||||||
typ.Type = Ptrto(Types[TUINT8])
|
typ.Type = Ptrto(Types[TUINT8])
|
||||||
typ.Typecheck = 1
|
typ.Typecheck = 1
|
||||||
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
|
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
|
||||||
typ.Bounded = true // guaranteed not to fault
|
typ.Bounded = true // guaranteed not to fault
|
||||||
}
|
}
|
||||||
// Load hash from type.
|
// Load hash from type.
|
||||||
h := Nod(ODOTPTR, typ, nil)
|
h := NodSym(ODOTPTR, typ, nil)
|
||||||
h.Type = Types[TUINT32]
|
h.Type = Types[TUINT32]
|
||||||
h.Typecheck = 1
|
h.Typecheck = 1
|
||||||
h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
|
h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
|
||||||
|
|
|
||||||
|
|
@ -249,11 +249,11 @@ const (
|
||||||
ODCLTYPE // type Int int
|
ODCLTYPE // type Int int
|
||||||
|
|
||||||
ODELETE // delete(Left, Right)
|
ODELETE // delete(Left, Right)
|
||||||
ODOT // Left.Right (Left is of struct type)
|
ODOT // Left.Sym (Left is of struct type)
|
||||||
ODOTPTR // Left.Right (Left is of pointer to struct type)
|
ODOTPTR // Left.Sym (Left is of pointer to struct type)
|
||||||
ODOTMETH // Left.Right (Left is non-interface, Right is method name)
|
ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
|
||||||
ODOTINTER // Left.Right (Left is interface, Right is method name)
|
ODOTINTER // Left.Sym (Left is interface, Right is method name)
|
||||||
OXDOT // Left.Right (before rewrite to one of the preceding)
|
OXDOT // Left.Sym (before rewrite to one of the preceding)
|
||||||
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved)
|
ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved)
|
||||||
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE)
|
ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE)
|
||||||
OEQ // Left == Right
|
OEQ // Left == Right
|
||||||
|
|
|
||||||
|
|
@ -252,17 +252,22 @@ func typecheck1(np **Node, top int) {
|
||||||
*np = n
|
*np = n
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if n.Sym != nil {
|
switch n.Op {
|
||||||
if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
|
case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER:
|
||||||
Yyerror("use of builtin %v not in function call", n.Sym)
|
// n.Sym is a field/method name, not a variable.
|
||||||
n.Type = nil
|
default:
|
||||||
return
|
if n.Sym != nil {
|
||||||
}
|
if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
|
||||||
|
Yyerror("use of builtin %v not in function call", n.Sym)
|
||||||
|
n.Type = nil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
typecheckdef(n)
|
typecheckdef(n)
|
||||||
if n.Op == ONONAME {
|
if n.Op == ONONAME {
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -819,11 +824,6 @@ OpSwitch:
|
||||||
typecheck(&n.Left, Erv|Etype)
|
typecheck(&n.Left, Erv|Etype)
|
||||||
|
|
||||||
defaultlit(&n.Left, nil)
|
defaultlit(&n.Left, nil)
|
||||||
if n.Right.Op != ONAME {
|
|
||||||
Yyerror("rhs of . must be a name") // impossible
|
|
||||||
n.Type = nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t := n.Left.Type
|
t := n.Left.Type
|
||||||
if t == nil {
|
if t == nil {
|
||||||
|
|
@ -832,14 +832,14 @@ OpSwitch:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r := n.Right
|
s := n.Sym
|
||||||
|
|
||||||
if n.Left.Op == OTYPE {
|
if n.Left.Op == OTYPE {
|
||||||
if !looktypedot(n, t, 0) {
|
if !looktypedot(n, t, 0) {
|
||||||
if looktypedot(n, t, 1) {
|
if looktypedot(n, t, 1) {
|
||||||
Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Right.Sym)
|
Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Sym)
|
||||||
} else {
|
} else {
|
||||||
Yyerror("%v undefined (type %v has no method %v)", n, t, n.Right.Sym)
|
Yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
|
||||||
}
|
}
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return
|
return
|
||||||
|
|
@ -856,7 +856,7 @@ OpSwitch:
|
||||||
if n.Name == nil {
|
if n.Name == nil {
|
||||||
n.Name = new(Name)
|
n.Name = new(Name)
|
||||||
}
|
}
|
||||||
n.Sym = n.Right.Sym
|
n.Right = newname(n.Sym)
|
||||||
n.Type = methodfunc(n.Type, n.Left.Type)
|
n.Type = methodfunc(n.Type, n.Left.Type)
|
||||||
n.Xoffset = 0
|
n.Xoffset = 0
|
||||||
n.Class = PFUNC
|
n.Class = PFUNC
|
||||||
|
|
@ -874,7 +874,7 @@ OpSwitch:
|
||||||
checkwidth(t)
|
checkwidth(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isblank(n.Right) {
|
if isblanksym(n.Sym) {
|
||||||
Yyerror("cannot refer to blank field or method")
|
Yyerror("cannot refer to blank field or method")
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
return
|
return
|
||||||
|
|
@ -892,13 +892,13 @@ OpSwitch:
|
||||||
|
|
||||||
case lookdot(n, t, 1) != nil:
|
case lookdot(n, t, 1) != nil:
|
||||||
// Field or method matches by name, but it is not exported.
|
// Field or method matches by name, but it is not exported.
|
||||||
Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Right.Sym)
|
Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
|
if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
|
||||||
Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Right.Sym, mt.Sym)
|
Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Sym, mt.Sym)
|
||||||
} else {
|
} else {
|
||||||
Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Right.Sym)
|
Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n.Type = nil
|
n.Type = nil
|
||||||
|
|
@ -910,7 +910,7 @@ OpSwitch:
|
||||||
if top&Ecall != 0 {
|
if top&Ecall != 0 {
|
||||||
ok |= Ecall
|
ok |= Ecall
|
||||||
} else {
|
} else {
|
||||||
typecheckpartialcall(n, r)
|
typecheckpartialcall(n, s)
|
||||||
ok |= Erv
|
ok |= Erv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2392,7 +2392,7 @@ func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
|
||||||
}
|
}
|
||||||
|
|
||||||
func looktypedot(n *Node, t *Type, dostrcmp int) bool {
|
func looktypedot(n *Node, t *Type, dostrcmp int) bool {
|
||||||
s := n.Right.Sym
|
s := n.Sym
|
||||||
|
|
||||||
if t.Etype == TINTER {
|
if t.Etype == TINTER {
|
||||||
f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
|
f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
|
||||||
|
|
@ -2400,7 +2400,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Right = methodname(n.Right, t)
|
n.Sym = methodsym(n.Sym, t, 0)
|
||||||
n.Xoffset = f1.Width
|
n.Xoffset = f1.Width
|
||||||
n.Type = f1.Type
|
n.Type = f1.Type
|
||||||
n.Op = ODOTINTER
|
n.Op = ODOTINTER
|
||||||
|
|
@ -2426,7 +2426,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Right = methodname(n.Right, t)
|
n.Sym = methodsym(n.Sym, t, 0)
|
||||||
n.Xoffset = f2.Width
|
n.Xoffset = f2.Width
|
||||||
n.Type = f2.Type
|
n.Type = f2.Type
|
||||||
n.Op = ODOTMETH
|
n.Op = ODOTMETH
|
||||||
|
|
@ -2450,7 +2450,7 @@ type typeSym struct {
|
||||||
var dotField = map[typeSym]*Field{}
|
var dotField = map[typeSym]*Field{}
|
||||||
|
|
||||||
func lookdot(n *Node, t *Type, dostrcmp int) *Field {
|
func lookdot(n *Node, t *Type, dostrcmp int) *Field {
|
||||||
s := n.Right.Sym
|
s := n.Sym
|
||||||
|
|
||||||
dowidth(t)
|
dowidth(t)
|
||||||
var f1 *Field
|
var f1 *Field
|
||||||
|
|
@ -2474,7 +2474,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
|
||||||
return f1
|
return f1
|
||||||
}
|
}
|
||||||
if f2 != nil {
|
if f2 != nil {
|
||||||
Yyerror("%v is both field and method", n.Right.Sym)
|
Yyerror("%v is both field and method", n.Sym)
|
||||||
}
|
}
|
||||||
if f1.Width == BADWIDTH {
|
if f1.Width == BADWIDTH {
|
||||||
Fatalf("lookdot badwidth %v %p", f1, f1)
|
Fatalf("lookdot badwidth %v %p", f1, f1)
|
||||||
|
|
@ -2516,7 +2516,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
|
||||||
n.Left.Implicit = true
|
n.Left.Implicit = true
|
||||||
typecheck(&n.Left, Etype|Erv)
|
typecheck(&n.Left, Etype|Erv)
|
||||||
} else if tt.Etype == Tptr && tt.Type.Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
|
} else if tt.Etype == Tptr && tt.Type.Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
|
||||||
Yyerror("calling method %v with receiver %v requires explicit dereference", n.Right, Nconv(n.Left, FmtLong))
|
Yyerror("calling method %v with receiver %v requires explicit dereference", n.Sym, Nconv(n.Left, FmtLong))
|
||||||
for tt.Etype == Tptr {
|
for tt.Etype == Tptr {
|
||||||
// Stop one level early for method with pointer receiver.
|
// Stop one level early for method with pointer receiver.
|
||||||
if rcvr.Etype == Tptr && tt.Type.Etype != Tptr {
|
if rcvr.Etype == Tptr && tt.Type.Etype != Tptr {
|
||||||
|
|
@ -2545,7 +2545,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Right = methodname(n.Right, n.Left.Type)
|
n.Sym = methodsym(n.Sym, n.Left.Type, 0)
|
||||||
n.Xoffset = f2.Width
|
n.Xoffset = f2.Width
|
||||||
n.Type = f2.Type
|
n.Type = f2.Type
|
||||||
|
|
||||||
|
|
@ -3232,7 +3232,7 @@ func samesafeexpr(l *Node, r *Node) bool {
|
||||||
return l == r
|
return l == r
|
||||||
|
|
||||||
case ODOT, ODOTPTR:
|
case ODOT, ODOTPTR:
|
||||||
return l.Right != nil && r.Right != nil && l.Right.Sym == r.Right.Sym && samesafeexpr(l.Left, r.Left)
|
return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left)
|
||||||
|
|
||||||
case OIND:
|
case OIND:
|
||||||
return samesafeexpr(l.Left, r.Left)
|
return samesafeexpr(l.Left, r.Left)
|
||||||
|
|
|
||||||
|
|
@ -2480,12 +2480,17 @@ func varexpr(n *Node) bool {
|
||||||
OPAREN,
|
OPAREN,
|
||||||
OANDAND,
|
OANDAND,
|
||||||
OOROR,
|
OOROR,
|
||||||
ODOT, // but not ODOTPTR
|
|
||||||
OCONV,
|
OCONV,
|
||||||
OCONVNOP,
|
OCONVNOP,
|
||||||
OCONVIFACE,
|
OCONVIFACE,
|
||||||
ODOTTYPE:
|
ODOTTYPE:
|
||||||
return varexpr(n.Left) && varexpr(n.Right)
|
return varexpr(n.Left) && varexpr(n.Right)
|
||||||
|
|
||||||
|
case ODOT: // but not ODOTPTR
|
||||||
|
// The original code always returned false for ODOT,
|
||||||
|
// because n.Right would be an ONAME with n.Class not set.
|
||||||
|
// TODO(iant): Fix this to remove "&& false".
|
||||||
|
return varexpr(n.Left) && false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Be conservative.
|
// Be conservative.
|
||||||
|
|
@ -3234,8 +3239,8 @@ func walkcompare(np **Node, init *Nodes) {
|
||||||
if isblanksym(t1.Sym) {
|
if isblanksym(t1.Sym) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
li = Nod(OXDOT, l, newname(t1.Sym))
|
li = NodSym(OXDOT, l, t1.Sym)
|
||||||
ri = Nod(OXDOT, r, newname(t1.Sym))
|
ri = NodSym(OXDOT, r, t1.Sym)
|
||||||
a = Nod(n.Op, li, ri)
|
a = Nod(n.Op, li, ri)
|
||||||
if expr == nil {
|
if expr == nil {
|
||||||
expr = a
|
expr = a
|
||||||
|
|
@ -3295,9 +3300,7 @@ func samecheap(a *Node, b *Node) bool {
|
||||||
return a == b
|
return a == b
|
||||||
|
|
||||||
case ODOT, ODOTPTR:
|
case ODOT, ODOTPTR:
|
||||||
ar = a.Right
|
if a.Sym != b.Sym {
|
||||||
br = b.Right
|
|
||||||
if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3815,7 +3818,7 @@ func usefield(n *Node) {
|
||||||
case ODOT, ODOTPTR:
|
case ODOT, ODOTPTR:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if n.Right == nil {
|
if n.Sym == nil {
|
||||||
// No field name. This DOTPTR was built by the compiler for access
|
// No field name. This DOTPTR was built by the compiler for access
|
||||||
// to runtime data structures. Ignore.
|
// to runtime data structures. Ignore.
|
||||||
return
|
return
|
||||||
|
|
@ -3825,9 +3828,9 @@ func usefield(n *Node) {
|
||||||
if Isptr[t.Etype] {
|
if Isptr[t.Etype] {
|
||||||
t = t.Type
|
t = t.Type
|
||||||
}
|
}
|
||||||
field := dotField[typeSym{t.Orig, n.Right.Sym}]
|
field := dotField[typeSym{t.Orig, n.Sym}]
|
||||||
if field == nil {
|
if field == nil {
|
||||||
Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
|
Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
|
||||||
}
|
}
|
||||||
if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
|
if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -639,7 +639,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
||||||
// A special case to make write barriers more efficient.
|
// A special case to make write barriers more efficient.
|
||||||
// Comparing the first field of a named struct can be done directly.
|
// Comparing the first field of a named struct can be done directly.
|
||||||
base := n1
|
base := n1
|
||||||
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Right.Sym {
|
if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Field(0).Sym == n1.Sym {
|
||||||
base = n1.Left
|
base = n1.Left
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue