// A special case to make write barriers more efficient.
// Comparing the first field of a named struct can be done directly.
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
}
if algtype1(f.Type, nil) != AMEM {
hashel := hashfor(f.Type)
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.Etype = 1 // no escape to heap
call.List.Append(na)
// h = hashel(&p.first, size, h)
hashel := hashmem(f.Type)
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.Etype = 1 // no escape to heap
call.List.Append(na)
// Compare non-memory fields with field equality.
if algtype1(f.Type, nil) != AMEM {
- and(eqfield(np, nq, newname(f.Sym)))
+ and(eqfield(np, nq, f.Sym))
i++
continue
}
if s := fields[i:next]; len(s) <= 2 {
// Two or fewer fields: use plain field equality.
for _, f := range s {
- and(eqfield(np, nq, newname(f.Sym)))
+ and(eqfield(np, nq, f.Sym))
}
} else {
// More than two fields: use memequal.
- and(eqmem(np, nq, newname(f.Sym), size))
+ and(eqmem(np, nq, f.Sym, size))
}
i = next
}
// eqfield returns the node
// p.field == q.field
-func eqfield(p *Node, q *Node, field *Node) *Node {
- nx := Nod(OXDOT, p, field)
- ny := Nod(OXDOT, q, field)
+func eqfield(p *Node, q *Node, field *Sym) *Node {
+ nx := NodSym(OXDOT, p, field)
+ ny := NodSym(OXDOT, q, field)
ne := Nod(OEQ, nx, ny)
return ne
}
// eqmem returns the node
// memequal(&p.field, &q.field [, size])
-func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
- nx := Nod(OADDR, Nod(OXDOT, p, field), nil)
+func eqmem(p *Node, q *Node, field *Sym, size int64) *Node {
+ nx := Nod(OADDR, NodSym(OXDOT, p, field), nil)
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
typecheck(&nx, Erv)
typecheck(&ny, Erv)
case ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT:
p.node(n.Left)
- p.sym(n.Right.Sym)
+ p.sym(n.Sym)
case ODOTTYPE, ODOTTYPE2:
p.node(n.Left)
obj.Used = true
return oldname(s)
}
- return Nod(OXDOT, obj, newname(sel))
+ return NodSym(OXDOT, obj, sel)
case ODOTTYPE, ODOTTYPE2:
n.Left = p.node()
}
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)
pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
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
if !i.Addable {
return clos
}
-func typecheckpartialcall(fn *Node, sym *Node) {
+func typecheckpartialcall(fn *Node, sym *Sym) {
switch fn.Op {
case ODOTINTER, ODOTMETH:
break
// Create top-level function.
xfunc := makepartialcall(fn, fn.Type, sym)
fn.Func = xfunc.Func
- fn.Right = sym
+ fn.Right = newname(sym)
fn.Op = OCALLPART
fn.Type = xfunc.Type
}
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
rcvrtype := fn.Left.Type
- if exportname(meth.Sym.Name) {
- p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Sym.Name)
+ if exportname(meth.Name) {
+ p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Name)
} 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
if Isptr[rcvrtype.Etype] {
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.Isddd = ddd
if t0.Results().NumFields() == 0 {
func (c *nowritebarrierrecChecker) visitcall(n *Node) {
fn := n.Left
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 {
return
if n.Op == OCALLFUNC || n.Op == OCALLMETH {
fn := n.Left
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 {
m := v.visit(fn.Name.Defn)
indirect = fn.Op != ONAME || fn.Class != PFUNC
case OCALLMETH:
- fn = n.Left.Right.Sym.Def
+ fn = n.Left.Sym.Def
if fn != nil {
fntype = fn.Type
} else {
}
return ":"
- case OXDOT,
- ODOT,
- ODOTPTR,
- ODOTINTER,
- ODOTMETH,
- OCALLPART:
+ case OCALLPART:
var f string
f += exprfmt(n.Left, nprec)
if n.Right == nil || n.Right.Sym == nil {
f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, FmtShort|FmtByte))
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:
var f string
f += exprfmt(n.Left, nprec)
n2 := *n
n2.Op = OCALLFUNC
- n2.Left = l.Right
+ n2.Left = newname(l.Sym)
n2.Left.Type = l.Type
if n2.Left.Op == ONAME {
// A special case to make write barriers more efficient.
// Taking the address of the first field of a named 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
Dump("naddr", n)
Fatalf("naddr: bad %v %v", Oconv(n.Op, 0), Ctxt.Dconv(a))
ODCLTYPE, // can't print yet
ORETJMP:
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)--
obj.Used = true
return oldname(s)
}
- return Nod(OXDOT, obj, newname(sel))
+ return NodSym(OXDOT, obj, sel)
}
func (p *parser) dotname() *Node {
hit := prealloc[n]
hit.Type = th
n.Left = nil
- keyname := newname(th.Field(0).Sym) // depends on layout of iterator struct. See reflect.go:hiter
- valname := newname(th.Field(1).Sym) // ditto
+ keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter
+ valsym := th.Field(1).Sym // ditto
fn := syslook("mapiterinit")
substArgTypes(&fn, t.Key(), t.Type, th)
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")
substArgTypes(&fn, th)
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)
if v1 == nil {
body = nil
} else if v2 == nil {
body = []*Node{Nod(OAS, v1, key)}
} else {
- val := Nod(ODOT, hit, valname)
+ val := NodSym(ODOT, hit, valsym)
val = Nod(OIND, val, nil)
a := Nod(OAS2, nil, nil)
a.List.Set([]*Node{v1, v2})
case OARRAYLIT:
if value.Type.Bound < 0 {
if pass == 1 && ctxt != 0 {
- a = Nod(ODOT, var_, newname(index.Sym))
+ a = NodSym(ODOT, var_, index.Sym)
slicelit(ctxt, value, a, init)
} else if pass == 2 && ctxt == 0 {
- a = Nod(ODOT, var_, newname(index.Sym))
+ a = NodSym(ODOT, var_, index.Sym)
slicelit(ctxt, value, a, init)
} else if pass == 3 {
break
continue
}
- a = Nod(ODOT, var_, newname(index.Sym))
+ a = NodSym(ODOT, var_, index.Sym)
arraylit(ctxt, pass, value, a, init)
continue
case OSTRUCTLIT:
- a = Nod(ODOT, var_, newname(index.Sym))
+ a = NodSym(ODOT, var_, index.Sym)
structlit(ctxt, pass, value, a, init)
continue
}
// build list of var.field = expr
setlineno(value)
- a = Nod(ODOT, var_, newname(index.Sym))
+ a = NodSym(ODOT, var_, index.Sym)
a = Nod(OAS, a, value)
typecheck(&a, Etop)
a = Nodintconst(b)
a = Nod(OINDEX, vstat, a)
- a = Nod(ODOT, a, newname(syma))
+ a = NodSym(ODOT, a, syma)
a = Nod(OAS, a, index)
typecheck(&a, Etop)
walkexpr(&a, init)
a = Nodintconst(b)
a = Nod(OINDEX, vstat, a)
- a = Nod(ODOT, a, newname(symb))
+ a = NodSym(ODOT, a, symb)
a = Nod(OAS, a, value)
typecheck(&a, Etop)
walkexpr(&a, init)
a = Nod(OINDEX, vstat, index)
a.Bounded = true
- a = Nod(ODOT, a, newname(symb))
+ a = NodSym(ODOT, a, symb)
r := Nod(OINDEX, vstat, index)
r.Bounded = true
- r = Nod(ODOT, r, newname(syma))
+ r = NodSym(ODOT, r, syma)
r = Nod(OINDEX, var_, r)
r = Nod(OAS, r, a)
if fn.Op != ODOTMETH {
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 {
- sym = fn.Right.Sym
+ sym = fn.Sym
break
}
- n2 := *fn.Right
+ n2 := newname(fn.Sym)
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
// want to set it here.
case OCALLINTER:
// fieldIdx finds the index of the field referred to by the ODOT node n.
func fieldIdx(n *Node) int {
t := n.Left.Type
- f := n.Right
+ f := n.Sym
if t.Etype != TSTRUCT {
panic("ODOT's LHS is not a struct")
}
var i int
for _, t1 := range t.Fields().Slice() {
- if t1.Sym != f.Sym {
+ if t1.Sym != f {
i++
continue
}
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) {
if n.Orig != nil {
return
return n
}
- if n.Right.Op != ONAME {
- return n
- }
- s := n.Right.Sym
+ s := n.Sym
if s == nil {
return n
}
case path != nil:
// rebuild elided dots
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
}
case ambig:
fn.Nbody.Append(n)
}
- dot := adddot(Nod(OXDOT, this.Left, newname(method.Sym)))
+ dot := adddot(NodSym(OXDOT, this.Left, method.Sym))
// generate call
if !instrumenting && Isptr[rcvr.Etype] && Isptr[methodrcvr.Etype] && method.Embedded != 0 && !isifacemethod(method.Type) {
if !isnilinter(cond.Right.Type) {
// Load type from itab.
- typ = Nod(ODOTPTR, typ, nil)
+ typ = NodSym(ODOTPTR, typ, nil)
typ.Type = Ptrto(Types[TUINT8])
typ.Typecheck = 1
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
typ.Bounded = true // guaranteed not to fault
}
// Load hash from type.
- h := Nod(ODOTPTR, typ, nil)
+ h := NodSym(ODOTPTR, typ, nil)
h.Type = Types[TUINT32]
h.Typecheck = 1
h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
ODCLTYPE // type Int int
ODELETE // delete(Left, Right)
- ODOT // Left.Right (Left is of struct type)
- ODOTPTR // Left.Right (Left is of pointer to struct type)
- ODOTMETH // Left.Right (Left is non-interface, Right is method name)
- ODOTINTER // Left.Right (Left is interface, Right is method name)
- OXDOT // Left.Right (before rewrite to one of the preceding)
+ ODOT // Left.Sym (Left is of struct type)
+ ODOTPTR // Left.Sym (Left is of pointer to struct type)
+ ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
+ ODOTINTER // Left.Sym (Left is interface, Right is method name)
+ OXDOT // Left.Sym (before rewrite to one of the preceding)
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)
OEQ // Left == Right
*np = n
}()
- 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
- }
+ switch n.Op {
+ case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER:
+ // n.Sym is a field/method name, not a variable.
+ default:
+ 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)
- if n.Op == ONONAME {
- n.Type = nil
- return
+ typecheckdef(n)
+ if n.Op == ONONAME {
+ n.Type = nil
+ return
+ }
}
}
typecheck(&n.Left, Erv|Etype)
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
if t == nil {
return
}
- r := n.Right
+ s := n.Sym
if n.Left.Op == OTYPE {
if !looktypedot(n, t, 0) {
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 {
- 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
return
if n.Name == nil {
n.Name = new(Name)
}
- n.Sym = n.Right.Sym
+ n.Right = newname(n.Sym)
n.Type = methodfunc(n.Type, n.Left.Type)
n.Xoffset = 0
n.Class = PFUNC
checkwidth(t)
}
- if isblank(n.Right) {
+ if isblanksym(n.Sym) {
Yyerror("cannot refer to blank field or method")
n.Type = nil
return
case lookdot(n, t, 1) != nil:
// 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:
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 {
- 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
if top&Ecall != 0 {
ok |= Ecall
} else {
- typecheckpartialcall(n, r)
+ typecheckpartialcall(n, s)
ok |= Erv
}
}
func looktypedot(n *Node, t *Type, dostrcmp int) bool {
- s := n.Right.Sym
+ s := n.Sym
if t.Etype == TINTER {
f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
return false
}
- n.Right = methodname(n.Right, t)
+ n.Sym = methodsym(n.Sym, t, 0)
n.Xoffset = f1.Width
n.Type = f1.Type
n.Op = ODOTINTER
return false
}
- n.Right = methodname(n.Right, t)
+ n.Sym = methodsym(n.Sym, t, 0)
n.Xoffset = f2.Width
n.Type = f2.Type
n.Op = ODOTMETH
var dotField = map[typeSym]*Field{}
func lookdot(n *Node, t *Type, dostrcmp int) *Field {
- s := n.Right.Sym
+ s := n.Sym
dowidth(t)
var f1 *Field
return f1
}
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 {
Fatalf("lookdot badwidth %v %p", f1, f1)
n.Left.Implicit = true
typecheck(&n.Left, Etype|Erv)
} 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 {
// Stop one level early for method with pointer receiver.
if rcvr.Etype == Tptr && tt.Type.Etype != Tptr {
return nil
}
- n.Right = methodname(n.Right, n.Left.Type)
+ n.Sym = methodsym(n.Sym, n.Left.Type, 0)
n.Xoffset = f2.Width
n.Type = f2.Type
return l == r
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:
return samesafeexpr(l.Left, r.Left)
OPAREN,
OANDAND,
OOROR,
- ODOT, // but not ODOTPTR
OCONV,
OCONVNOP,
OCONVIFACE,
ODOTTYPE:
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.
if isblanksym(t1.Sym) {
continue
}
- li = Nod(OXDOT, l, newname(t1.Sym))
- ri = Nod(OXDOT, r, newname(t1.Sym))
+ li = NodSym(OXDOT, l, t1.Sym)
+ ri = NodSym(OXDOT, r, t1.Sym)
a = Nod(n.Op, li, ri)
if expr == nil {
expr = a
return a == b
case ODOT, ODOTPTR:
- ar = a.Right
- br = b.Right
- if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
+ if a.Sym != b.Sym {
return false
}
case ODOT, ODOTPTR:
break
}
- if n.Right == nil {
+ if n.Sym == nil {
// No field name. This DOTPTR was built by the compiler for access
// to runtime data structures. Ignore.
return
if Isptr[t.Etype] {
t = t.Type
}
- field := dotField[typeSym{t.Orig, n.Right.Sym}]
+ field := dotField[typeSym{t.Orig, n.Sym}]
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\"") {
return
// A special case to make write barriers more efficient.
// Comparing the first field of a named struct can be done directly.
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
}