From: Russ Cox Date: Tue, 3 Mar 2015 01:34:22 +0000 (-0500) Subject: cmd/internal/gc: manual goto removal + grind to move var decls X-Git-Tag: go1.5beta1~1741 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=4492811c05f0f57d0bf9e11b9ef4ee7d71d126fd;p=gostls13.git cmd/internal/gc: manual goto removal + grind to move var decls Also change gc.Naddr to return the Addr instead of filling it in. Change-Id: I98a86705d23bee49626a12a042a4d51cabe290ea Reviewed-on: https://go-review.googlesource.com/6601 Reviewed-by: Rob Pike --- diff --git a/src/cmd/5g/ggen.go b/src/cmd/5g/ggen.go index 374d5e32ee..58b0c36b28 100644 --- a/src/cmd/5g/ggen.go +++ b/src/cmd/5g/ggen.go @@ -78,7 +78,7 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Pr p.Reg = arm.REGSP p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0) f := gc.Sysfunc("duffzero") - gc.Naddr(f, &p.To, 1) + p.To = gc.Naddr(f, 1) gc.Afunclit(&p.To, f) p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr)) } else { diff --git a/src/cmd/5g/gsubr.go b/src/cmd/5g/gsubr.go index b8547dd4f1..f2ba6e2bff 100644 --- a/src/cmd/5g/gsubr.go +++ b/src/cmd/5g/gsubr.go @@ -766,12 +766,14 @@ func gmove(f *gc.Node, t *gc.Node) { // removed. // requires register destination rdst: - regalloc(&r1, t.Type, t) + { + regalloc(&r1, t.Type, t) - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return + } // requires register intermediate hard: @@ -844,10 +846,10 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { var at obj.Addr if f != nil { - gc.Naddr(f, &af, 1) + af = gc.Naddr(f, 1) } if t != nil { - gc.Naddr(t, &at, 1) + at = gc.Naddr(t, 1) } p := gc.Prog(as) if f != nil { @@ -868,7 +870,7 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { func raddr(n *gc.Node, p *obj.Prog) { var a obj.Addr - gc.Naddr(n, &a, 1) + a = gc.Naddr(n, 1) if a.Type != obj.TYPE_REG { if n != nil { gc.Fatal("bad in raddr: %v", gc.Oconv(int(n.Op), 0)) @@ -1304,7 +1306,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool { reg1 := &clean[cleani-2] reg.Op = gc.OEMPTY reg1.Op = gc.OEMPTY - gc.Naddr(n, a, 1) + *a = gc.Naddr(n, 1) return true case gc.ODOT, @@ -1328,7 +1330,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool { n1.Type = n.Type n1.Xoffset += oary[0] - gc.Naddr(&n1, a, 1) + *a = gc.Naddr(&n1, 1) return true } @@ -1356,7 +1358,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool { a.Type = obj.TYPE_NONE a.Name = obj.NAME_NONE n1.Type = n.Type - gc.Naddr(&n1, a, 1) + *a = gc.Naddr(&n1, 1) return true case gc.OINDEX: diff --git a/src/cmd/6g/cgen.go b/src/cmd/6g/cgen.go index 8e282155f6..0b0d6b3249 100644 --- a/src/cmd/6g/cgen.go +++ b/src/cmd/6g/cgen.go @@ -1115,8 +1115,6 @@ func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { return } - var nr *gc.Node - for n.Op == gc.OCONVNOP { n = n.Left if n.Ninit != nil { @@ -1125,6 +1123,7 @@ func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { } var nl *gc.Node + var nr *gc.Node switch n.Op { default: goto def diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go index 2934f1e249..45242b34a0 100644 --- a/src/cmd/6g/ggen.go +++ b/src/cmd/6g/ggen.go @@ -503,7 +503,6 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { gmove(&n31, &n3) } - var p2 *obj.Prog var n4 gc.Node if gc.Nacl { // Native Client does not relay the divide-by-zero trap @@ -520,6 +519,7 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { gc.Patch(p1, gc.Pc) } + var p2 *obj.Prog if check != 0 { gc.Nodconst(&n4, t, -1) gins(optoas(gc.OCMP, t), &n3, &n4) diff --git a/src/cmd/6g/gsubr.go b/src/cmd/6g/gsubr.go index 73afb93501..719a1fee92 100644 --- a/src/cmd/6g/gsubr.go +++ b/src/cmd/6g/gsubr.go @@ -314,7 +314,6 @@ func gmove(f *gc.Node, t *gc.Node) { } // cannot have two memory operands - var r1 gc.Node var a int if gc.Ismem(f) && gc.Ismem(t) { goto hard @@ -669,15 +668,19 @@ func gmove(f *gc.Node, t *gc.Node) { // requires register destination rdst: - regalloc(&r1, t.Type, t) + { + var r1 gc.Node + regalloc(&r1, t.Type, t) - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return + } // requires register intermediate hard: + var r1 gc.Node regalloc(&r1, cvt, t) gmove(f, &r1) @@ -744,12 +747,12 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { } var af obj.Addr - var at obj.Addr if f != nil { - gc.Naddr(f, &af, 1) + af = gc.Naddr(f, 1) } + var at obj.Addr if t != nil { - gc.Naddr(t, &at, 1) + at = gc.Naddr(t, 1) } p := gc.Prog(as) if f != nil { @@ -1402,7 +1405,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { reg1 := &clean[cleani-2] reg.Op = gc.OEMPTY reg1.Op = gc.OEMPTY - gc.Naddr(n, a, 1) + *a = gc.Naddr(n, 1) return true case gc.ODOT, @@ -1426,7 +1429,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { n1.Type = n.Type n1.Xoffset += oary[0] - gc.Naddr(&n1, a, 1) + *a = gc.Naddr(&n1, 1) return true } @@ -1454,7 +1457,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { a.Type = obj.TYPE_NONE a.Index = obj.TYPE_NONE fixlargeoffset(&n1) - gc.Naddr(&n1, a, 1) + *a = gc.Naddr(&n1, 1) return true case gc.OINDEX: diff --git a/src/cmd/6g/peep.go b/src/cmd/6g/peep.go index 7eff574556..a967bba223 100644 --- a/src/cmd/6g/peep.go +++ b/src/cmd/6g/peep.go @@ -825,8 +825,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { if p.As == obj.AVARDEF || p.As == obj.AVARKILL { return 0 } - var info gc.ProgInfo - info = proginfo(p) + info := proginfo(p) if (info.Reguse|info.Regset)&RtoB(int(v.Reg)) != 0 { return 2 diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go index 6931ea8732..95ec01aaf6 100644 --- a/src/cmd/8g/gsubr.go +++ b/src/cmd/8g/gsubr.go @@ -1148,12 +1148,14 @@ rsrc: // requires register destination rdst: - regalloc(&r1, t.Type, t) + { + regalloc(&r1, t.Type, t) - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return + } // requires register intermediate hard: @@ -1845,10 +1847,10 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { var af obj.Addr var at obj.Addr if f != nil { - gc.Naddr(f, &af, 1) + af = gc.Naddr(f, 1) } if t != nil { - gc.Naddr(t, &at, 1) + at = gc.Naddr(t, 1) } p := gc.Prog(as) if f != nil { diff --git a/src/cmd/9g/ggen.go b/src/cmd/9g/ggen.go index 98357eb525..d9bcfb7028 100644 --- a/src/cmd/9g/ggen.go +++ b/src/cmd/9g/ggen.go @@ -76,7 +76,7 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog { p.Reg = ppc64.REGSP p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0) f := gc.Sysfunc("duffzero") - gc.Naddr(f, &p.To, 1) + p.To = gc.Naddr(f, 1) gc.Afunclit(&p.To, f) p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr)) } else { diff --git a/src/cmd/9g/gsubr.go b/src/cmd/9g/gsubr.go index 2c51d06ded..1f1a43edb3 100644 --- a/src/cmd/9g/gsubr.go +++ b/src/cmd/9g/gsubr.go @@ -669,12 +669,14 @@ func gmove(f *gc.Node, t *gc.Node) { // requires register destination rdst: - regalloc(&r1, t.Type, t) + { + regalloc(&r1, t.Type, t) - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return + } // requires register intermediate hard: @@ -698,10 +700,10 @@ func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { at := obj.Addr(obj.Addr{}) if f != nil { - gc.Naddr(f, &af, 1) + af = gc.Naddr(f, 1) } if t != nil { - gc.Naddr(t, &at, 1) + at = gc.Naddr(t, 1) } p := (*obj.Prog)(gc.Prog(as)) if f != nil { diff --git a/src/cmd/internal/gc/closure.go b/src/cmd/internal/gc/closure.go index c9b6981aec..d6f657f125 100644 --- a/src/cmd/internal/gc/closure.go +++ b/src/cmd/internal/gc/closure.go @@ -596,7 +596,6 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node { declare(xfunc.Nname, PFUNC) // Declare and initialize variable holding receiver. - var body *NodeList xfunc.Needctxt = true cv := Nod(OCLOSUREVAR, nil, nil) @@ -613,6 +612,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node { ptr.Used = 1 ptr.Curfn = xfunc xfunc.Dcl = list(xfunc.Dcl, ptr) + var body *NodeList if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) { ptr.Ntype = typenod(rcvrtype) body = list(body, Nod(OAS, ptr, cv)) diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go index 8ea5d8dd76..a9454e6457 100644 --- a/src/cmd/internal/gc/dcl.go +++ b/src/cmd/internal/gc/dcl.go @@ -313,7 +313,6 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList { * new_name_list [[type] = expr_list] */ func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList { - var vv *NodeList if cl == nil { if t != nil { Yyerror("const declaration cannot have type without expression") @@ -329,6 +328,7 @@ func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList { var v *Node var c *Node + var vv *NodeList for ; vl != nil; vl = vl.Next { if cl == nil { Yyerror("missing value in const declaration") diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/internal/gc/gsubr.go index ad5e494f4f..48a24a6b56 100644 --- a/src/cmd/internal/gc/gsubr.go +++ b/src/cmd/internal/gc/gsubr.go @@ -274,8 +274,7 @@ func markautoused(p *obj.Prog) { } } -func Naddr(n *Node, a *obj.Addr, canemitcode int) { - *a = obj.Addr{} +func Naddr(n *Node, canemitcode int) (a obj.Addr) { if n == nil { return } @@ -294,7 +293,8 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) { switch n.Op { default: - Fatal("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a)) + a := a // copy to let escape into Ctxt.Dconv + Fatal("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(&a)) case OREGISTER: a.Type = obj.TYPE_REG @@ -338,7 +338,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) { a.Offset = n.Xoffset case OCFUNC: - Naddr(n.Left, a, canemitcode) + a = Naddr(n.Left, canemitcode) a.Sym = Linksym(n.Left.Sym) case ONAME: @@ -408,7 +408,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) { a.Offset = Mpgetfix(n.Val.U.Xval) case CTSTR: - datagostring(n.Val.U.Sval, a) + datagostring(n.Val.U.Sval, &a) case CTBOOL: a.Sym = nil @@ -422,19 +422,20 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) { } case OADDR: - Naddr(n.Left, a, canemitcode) + a = Naddr(n.Left, canemitcode) a.Etype = uint8(Tptr) if Thearch.Thechar != '5' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64. a.Width = int64(Widthptr) } if a.Type != obj.TYPE_MEM { - Fatal("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(int(n.Left.Op), 0)) + a := a // copy to let escape into Ctxt.Dconv + Fatal("naddr: OADDR %v (from %v)", Ctxt.Dconv(&a), Oconv(int(n.Left.Op), 0)) } a.Type = obj.TYPE_ADDR // itable of interface value case OITAB: - Naddr(n.Left, a, canemitcode) + a = Naddr(n.Left, canemitcode) if a.Type == obj.TYPE_CONST && a.Offset == 0 { break // itab(nil) @@ -444,7 +445,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) { // pointer in a string or slice case OSPTR: - Naddr(n.Left, a, canemitcode) + a = Naddr(n.Left, canemitcode) if a.Type == obj.TYPE_CONST && a.Offset == 0 { break // ptr(nil) @@ -455,7 +456,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) { // len of string or slice case OLEN: - Naddr(n.Left, a, canemitcode) + a = Naddr(n.Left, canemitcode) if a.Type == obj.TYPE_CONST && a.Offset == 0 { break // len(nil) @@ -471,7 +472,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) { // cap of string or slice case OCAP: - Naddr(n.Left, a, canemitcode) + a = Naddr(n.Left, canemitcode) if a.Type == obj.TYPE_CONST && a.Offset == 0 { break // cap(nil) @@ -485,6 +486,7 @@ func Naddr(n *Node, a *obj.Addr, canemitcode int) { a.Width = int64(Widthint) } } + return } func newplist() *obj.Plist { diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/internal/gc/plive.go index 5456435509..ba13cdb1c3 100644 --- a/src/cmd/internal/gc/plive.go +++ b/src/cmd/internal/gc/plive.go @@ -556,13 +556,11 @@ func isfunny(n *Node) bool { // initialized, because any use of a variable must come after its // initialization. func progeffects(prog *obj.Prog, vars []*Node, uevar *Bvec, varkill *Bvec, avarinit *Bvec) { - var info ProgInfo - bvresetall(uevar) bvresetall(varkill) bvresetall(avarinit) - info = Thearch.Proginfo(prog) + info := Thearch.Proginfo(prog) if prog.As == obj.ARET { // Return instructions implicitly read all the arguments. For // the sake of correctness, out arguments must be read. For the @@ -1087,8 +1085,8 @@ func newpcdataprog(prog *obj.Prog, index int32) *obj.Prog { Nodconst(&to, Types[TINT32], int64(index)) pcdata := unlinkedprog(obj.APCDATA) pcdata.Lineno = prog.Lineno - Naddr(&from, &pcdata.From, 0) - Naddr(&to, &pcdata.To, 0) + pcdata.From = Naddr(&from, 0) + pcdata.To = Naddr(&to, 0) return pcdata } @@ -1296,7 +1294,6 @@ func livenessepilogue(lv *Liveness) { any := bvalloc(nvars) all := bvalloc(nvars) ambig := bvalloc(localswords() * obj.BitsPerPointer) - var msg []string nmsg := int32(0) startmsg := int32(0) @@ -1392,6 +1389,7 @@ func livenessepilogue(lv *Liveness) { var fmt_ string var next *obj.Prog var numlive int32 + var msg []string for i := int32(0); i < int32(len(lv.cfg)); i++ { bb = lv.cfg[i] diff --git a/src/cmd/internal/gc/range.go b/src/cmd/internal/gc/range.go index ed50bdf67e..3de70ba71c 100644 --- a/src/cmd/internal/gc/range.go +++ b/src/cmd/internal/gc/range.go @@ -136,7 +136,6 @@ out: func walkrange(n *Node) { t := n.Type - var init *NodeList a := n.Right lno := int(setlineno(a)) @@ -154,9 +153,8 @@ func walkrange(n *Node) { // to avoid erroneous processing by racewalk. n.List = nil - var hv2 *Node - var body *NodeList + var init *NodeList switch t.Etype { default: Fatal("walkrange") @@ -366,6 +364,7 @@ func walkrange(n *Node) { init = list(init, Nod(OAS, hv1, nil)) var a *Node + var hv2 *Node if v2 == nil { a = Nod(OAS, hv1, mkcall("stringiter", Types[TINT], nil, ha, hv1)) } else { diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go index 0ff8224e62..845aac6965 100644 --- a/src/cmd/internal/gc/typecheck.go +++ b/src/cmd/internal/gc/typecheck.go @@ -276,44 +276,27 @@ func indexlit(np **Node) { } func typecheck1(np **Node, top int) { - var et int - var aop int - var op int - var ptr int - var l *Node - var r *Node - var lo *Node - var mid *Node - var hi *Node - var ok int - var ntop int - var t *Type - var tp *Type - var missing *Type - var have *Type - var badtype *Type - var v Val - var why string - var x int64 - n := *np + defer func() { + *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", Sconv(n.Sym, 0)) - goto error + n.Type = nil + return } typecheckdef(n) if n.Op == ONONAME { - goto error + n.Type = nil + return } } - *np = n - -reswitch: - ok = 0 + ok := 0 +OpSwitch: switch n.Op { // until typecheck is complete, do nothing. default: @@ -330,11 +313,11 @@ reswitch: if n.Type == nil && n.Val.Ctype == CTSTR { n.Type = idealstring } - goto ret + break OpSwitch case ONONAME: ok |= Erv - goto ret + break OpSwitch case ONAME: if n.Decldepth == 0 { @@ -342,14 +325,15 @@ reswitch: } if n.Etype != 0 { ok |= Ecall - goto ret + break OpSwitch } if top&Easgn == 0 { // not a write to the variable if isblank(n) { Yyerror("cannot use _ as value") - goto error + n.Type = nil + return } n.Used = 1 @@ -357,15 +341,17 @@ reswitch: if top&Ecall == 0 && isunsafebuiltin(n) { Yyerror("%v is not an expression, must be called", Nconv(n, 0)) - goto error + n.Type = nil + return } ok |= Erv - goto ret + break OpSwitch case OPACK: Yyerror("use of package %v without selector", Sconv(n.Sym, 0)) - goto error + n.Type = nil + return case ODDD: break @@ -377,14 +363,15 @@ reswitch: ok |= Etype if n.Type == nil { - goto error + n.Type = nil + return } case OTARRAY: ok |= Etype - t = typ(TARRAY) - l = n.Left - r = n.Right + t := typ(TARRAY) + l := n.Left + r := n.Right if l == nil { t.Bound = -1 // slice } else if l.Op == ODDD { @@ -395,7 +382,8 @@ reswitch: Yyerror("use of [...] array outside of array literal") } } else { - l = typecheck(&n.Left, Erv) + l := typecheck(&n.Left, Erv) + var v Val switch consttype(l) { case CTINT, CTRUNE: @@ -410,22 +398,26 @@ reswitch: } else { Yyerror("invalid array bound %v", Nconv(l, 0)) } - goto error + n.Type = nil + return } t.Bound = Mpgetfix(v.U.Xval) if doesoverflow(v, Types[TINT]) { Yyerror("array bound is too large") - goto error + n.Type = nil + return } else if t.Bound < 0 { Yyerror("array bound must be non-negative") - goto error + n.Type = nil + return } } typecheck(&r, Etype) if r.Type == nil { - goto error + n.Type = nil + return } t.Type = r.Type n.Op = OTYPE @@ -438,10 +430,11 @@ reswitch: case OTMAP: ok |= Etype - l = typecheck(&n.Left, Etype) - r = typecheck(&n.Right, Etype) + l := typecheck(&n.Left, Etype) + r := typecheck(&n.Right, Etype) if l.Type == nil || r.Type == nil { - goto error + n.Type = nil + return } n.Op = OTYPE n.Type = maptype(l.Type, r.Type) @@ -450,11 +443,12 @@ reswitch: case OTCHAN: ok |= Etype - l = typecheck(&n.Left, Etype) + l := typecheck(&n.Left, Etype) if l.Type == nil { - goto error + n.Type = nil + return } - t = typ(TCHAN) + t := typ(TCHAN) t.Type = l.Type t.Chan = n.Etype n.Op = OTYPE @@ -467,7 +461,8 @@ reswitch: n.Op = OTYPE n.Type = tostruct(n.List) if n.Type == nil || n.Type.Broke != 0 { - goto error + n.Type = nil + return } n.List = nil @@ -476,7 +471,8 @@ reswitch: n.Op = OTYPE n.Type = tointerface(n.List) if n.Type == nil { - goto error + n.Type = nil + return } case OTFUNC: @@ -484,61 +480,53 @@ reswitch: n.Op = OTYPE n.Type = functype(n.Left, n.List, n.Rlist) if n.Type == nil { - goto error + n.Type = nil + return } /* * type or expr */ case OIND: - ntop = Erv | Etype + ntop := Erv | Etype if top&Eaddr == 0 { ntop |= Eindir } ntop |= top & Ecomplit - l = typecheck(&n.Left, ntop) - t = l.Type + l := typecheck(&n.Left, ntop) + t := l.Type if t == nil { - goto error + n.Type = nil + return } if l.Op == OTYPE { ok |= Etype n.Op = OTYPE n.Type = Ptrto(l.Type) n.Left = nil - goto ret + break OpSwitch } if !Isptr[t.Etype] { if top&(Erv|Etop) != 0 { Yyerror("invalid indirect of %v", Nconv(n.Left, obj.FmtLong)) - goto error + n.Type = nil + return } - goto ret + break OpSwitch } ok |= Erv n.Type = t.Type - goto ret + break OpSwitch /* * arithmetic exprs */ - case OASOP: - ok |= Etop - - l = typecheck(&n.Left, Erv) - r = typecheck(&n.Right, Erv) - checkassign(n, n.Left) - if l.Type == nil || r.Type == nil { - goto error - } - op = int(n.Etype) - goto arith - - case OADD, + case OASOP, + OADD, OAND, OANDAND, OANDNOT, @@ -557,32 +545,270 @@ reswitch: OOROR, OSUB, OXOR: - ok |= Erv - l = typecheck(&n.Left, Erv|top&Eiota) - r = typecheck(&n.Right, Erv|top&Eiota) + var l *Node + var op int + var r *Node + if n.Op == OASOP { + ok |= Etop + l = typecheck(&n.Left, Erv) + r = typecheck(&n.Right, Erv) + checkassign(n, n.Left) + if l.Type == nil || r.Type == nil { + n.Type = nil + return + } + op = int(n.Etype) + } else { + ok |= Erv + l = typecheck(&n.Left, Erv|top&Eiota) + r = typecheck(&n.Right, Erv|top&Eiota) + if l.Type == nil || r.Type == nil { + n.Type = nil + return + } + op = int(n.Op) + } + if op == OLSH || op == ORSH { + defaultlit(&r, Types[TUINT]) + n.Right = r + t := r.Type + if !Isint[t.Etype] || Issigned[t.Etype] { + Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", Nconv(n, 0), Tconv(r.Type, 0)) + n.Type = nil + return + } + + t = l.Type + if t != nil && t.Etype != TIDEAL && !Isint[t.Etype] { + Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0)) + n.Type = nil + return + } + + // no defaultlit for left + // the outer context gives the type + n.Type = l.Type + + break OpSwitch + } + + // ideal mixed with non-ideal + defaultlit2(&l, &r, 0) + + n.Left = l + n.Right = r if l.Type == nil || r.Type == nil { - goto error + n.Type = nil + return + } + t := l.Type + if t.Etype == TIDEAL { + t = r.Type + } + et := int(t.Etype) + if et == TIDEAL { + et = TINT + } + aop := 0 + if iscmp[n.Op] && t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) { + // comparison is okay as long as one side is + // assignable to the other. convert so they have + // the same type. + // + // the only conversion that isn't a no-op is concrete == interface. + // in that case, check comparability of the concrete type. + // The conversion allocates, so only do it if the concrete type is huge. + if r.Type.Etype != TBLANK { + aop = assignop(l.Type, r.Type, nil) + if aop != 0 { + if Isinter(r.Type) && !Isinter(l.Type) && algtype1(l.Type, nil) == ANOEQ { + Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(l.Type)) + n.Type = nil + return + } + + dowidth(l.Type) + if Isinter(r.Type) == Isinter(l.Type) || l.Type.Width >= 1<<16 { + l = Nod(aop, l, nil) + l.Type = r.Type + l.Typecheck = 1 + n.Left = l + } + + t = r.Type + goto converted + } + } + + if l.Type.Etype != TBLANK { + aop = assignop(r.Type, l.Type, nil) + if aop != 0 { + if Isinter(l.Type) && !Isinter(r.Type) && algtype1(r.Type, nil) == ANOEQ { + Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(r.Type)) + n.Type = nil + return + } + + dowidth(r.Type) + if Isinter(r.Type) == Isinter(l.Type) || r.Type.Width >= 1<<16 { + r = Nod(aop, r, nil) + r.Type = l.Type + r.Typecheck = 1 + n.Right = r + } + + t = l.Type + } + } + + converted: + et = int(t.Etype) + } + + if t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) { + defaultlit2(&l, &r, 1) + if n.Op == OASOP && n.Implicit != 0 { + Yyerror("invalid operation: %v (non-numeric type %v)", Nconv(n, 0), Tconv(l.Type, 0)) + n.Type = nil + return + } + + if Isinter(r.Type) == Isinter(l.Type) || aop == 0 { + Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0)) + n.Type = nil + return + } + } + + if !okfor[op][et] { + Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(t)) + n.Type = nil + return + } + + // okfor allows any array == array, map == map, func == func. + // restrict to slice/map/func == nil and nil == slice/map/func. + if Isfixedarray(l.Type) && algtype1(l.Type, nil) == ANOEQ { + Yyerror("invalid operation: %v (%v cannot be compared)", Nconv(n, 0), Tconv(l.Type, 0)) + n.Type = nil + return + } + + if Isslice(l.Type) && !isnil(l) && !isnil(r) { + Yyerror("invalid operation: %v (slice can only be compared to nil)", Nconv(n, 0)) + n.Type = nil + return + } + + if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) { + Yyerror("invalid operation: %v (map can only be compared to nil)", Nconv(n, 0)) + n.Type = nil + return + } + + if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) { + Yyerror("invalid operation: %v (func can only be compared to nil)", Nconv(n, 0)) + n.Type = nil + return + } + + var badtype *Type + if l.Type.Etype == TSTRUCT && algtype1(l.Type, &badtype) == ANOEQ { + Yyerror("invalid operation: %v (struct containing %v cannot be compared)", Nconv(n, 0), Tconv(badtype, 0)) + n.Type = nil + return + } + + t = l.Type + if iscmp[n.Op] { + evconst(n) + t = idealbool + if n.Op != OLITERAL { + defaultlit2(&l, &r, 1) + n.Left = l + n.Right = r + } + } else if n.Op == OANDAND || n.Op == OOROR { + if l.Type == r.Type { + t = l.Type + } else if l.Type == idealbool { + t = r.Type + } else if r.Type == idealbool { + t = l.Type + } + } else + // non-comparison operators on ideal bools should make them lose their ideal-ness + if t == idealbool { + t = Types[TBOOL] + } + + if et == TSTRING { + if iscmp[n.Op] { + n.Etype = n.Op + n.Op = OCMPSTR + } else if n.Op == OADD { + // create OADDSTR node with list of strings in x + y + z + (w + v) + ... + n.Op = OADDSTR + + if l.Op == OADDSTR { + n.List = l.List + } else { + n.List = list1(l) + } + if r.Op == OADDSTR { + n.List = concat(n.List, r.List) + } else { + n.List = list(n.List, r) + } + n.Left = nil + n.Right = nil + } + } + + if et == TINTER { + if l.Op == OLITERAL && l.Val.Ctype == CTNIL { + // swap for back end + n.Left = r + + n.Right = l + } else if r.Op == OLITERAL && r.Val.Ctype == CTNIL { + } else // leave alone for back end + if Isinter(r.Type) == Isinter(l.Type) { + n.Etype = n.Op + n.Op = OCMPIFACE + } } - op = int(n.Op) - goto arith + + if (op == ODIV || op == OMOD) && Isconst(r, CTINT) { + if mpcmpfixc(r.Val.U.Xval, 0) == 0 { + Yyerror("division by zero") + n.Type = nil + return + } + } + + n.Type = t + break OpSwitch case OCOM, OMINUS, ONOT, OPLUS: ok |= Erv - l = typecheck(&n.Left, Erv|top&Eiota) - t = l.Type + l := typecheck(&n.Left, Erv|top&Eiota) + t := l.Type if t == nil { - goto error + n.Type = nil + return } if !okfor[n.Op][t.Etype] { Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), Tconv(t, 0)) - goto error + n.Type = nil + return } n.Type = t - goto ret + break OpSwitch /* * exprs @@ -592,10 +818,12 @@ reswitch: typecheck(&n.Left, Erv|Eaddr) if n.Left.Type == nil { - goto error + n.Type = nil + return } checklvalue(n.Left, "take the address of") - r = outervalue(n.Left) + r := outervalue(n.Left) + var l *Node for l = n.Left; l != r; l = l.Left { l.Addrtaken = 1 if l.Closure != nil { @@ -612,46 +840,50 @@ reswitch: } defaultlit(&n.Left, nil) l = n.Left - t = l.Type + t := l.Type if t == nil { - goto error + n.Type = nil + return } n.Type = Ptrto(t) - goto ret + break OpSwitch case OCOMPLIT: ok |= Erv typecheckcomplit(&n) if n.Type == nil { - goto error + n.Type = nil + return } - goto ret + break OpSwitch - case OXDOT: - n = adddot(n) - n.Op = ODOT - if n.Left == nil { - goto error + case OXDOT, ODOT: + if n.Op == OXDOT { + n = adddot(n) + n.Op = ODOT + if n.Left == nil { + n.Type = nil + return + } } - fallthrough - // fall through - case ODOT: typecheck(&n.Left, Erv|Etype) defaultlit(&n.Left, nil) if n.Right.Op != ONAME { Yyerror("rhs of . must be a name") // impossible - goto error + n.Type = nil + return } - t = n.Left.Type + t := n.Left.Type if t == nil { adderrorname(n) - goto error + n.Type = nil + return } - r = n.Right + r := n.Right if n.Left.Op == OTYPE { if !looktypedot(n, t, 0) { @@ -660,13 +892,15 @@ reswitch: } else { Yyerror("%v undefined (type %v has no method %v)", Nconv(n, 0), Tconv(t, 0), Sconv(n.Right.Sym, 0)) } - goto error + n.Type = nil + return } if n.Type.Etype != TFUNC || n.Type.Thistuple != 1 { Yyerror("type %v has no method %v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort)) n.Type = nil - goto error + n.Type = nil + return } n.Op = ONAME @@ -675,13 +909,14 @@ reswitch: n.Xoffset = 0 n.Class = PFUNC ok = Erv - goto ret + break OpSwitch } if Isptr[t.Etype] && t.Type.Etype != TINTER { t = t.Type if t == nil { - goto error + n.Type = nil + return } n.Op = ODOTPTR checkwidth(t) @@ -689,7 +924,8 @@ reswitch: if isblank(n.Right) { Yyerror("cannot refer to blank field or method") - goto error + n.Type = nil + return } if !lookdot(n, t, 0) { @@ -698,7 +934,8 @@ reswitch: } else { Yyerror("%v undefined (type %v has no field or method %v)", Nconv(n, 0), Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, 0)) } - goto error + n.Type = nil + return } switch n.Op { @@ -715,20 +952,22 @@ reswitch: ok |= Erv } - goto ret + break OpSwitch case ODOTTYPE: ok |= Erv typecheck(&n.Left, Erv) defaultlit(&n.Left, nil) - l = n.Left - t = l.Type + l := n.Left + t := l.Type if t == nil { - goto error + n.Type = nil + return } if !Isinter(t) { Yyerror("invalid type assertion: %v (non-interface type %v on left)", Nconv(n, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } if n.Right != nil { @@ -736,11 +975,15 @@ reswitch: n.Type = n.Right.Type n.Right = nil if n.Type == nil { - goto error + n.Type = nil + return } } if n.Type != nil && n.Type.Etype != TINTER { + var have *Type + var missing *Type + var ptr int if !implements(n.Type, t, &missing, &have, &ptr) { if have != nil && have.Sym == missing.Sym { Yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort|obj.FmtByte), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort|obj.FmtByte)) @@ -751,28 +994,31 @@ reswitch: } else { Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0)) } - goto error + n.Type = nil + return } } - goto ret + break OpSwitch case OINDEX: ok |= Erv typecheck(&n.Left, Erv) defaultlit(&n.Left, nil) implicitstar(&n.Left) - l = n.Left + l := n.Left typecheck(&n.Right, Erv) - r = n.Right - t = l.Type + r := n.Right + t := l.Type if t == nil || r.Type == nil { - goto error + n.Type = nil + return } switch t.Etype { default: Yyerror("invalid operation: %v (type %v does not support indexing)", Nconv(n, 0), Tconv(t, 0)) - goto error + n.Type = nil + return case TSTRING, TARRAY: @@ -782,7 +1028,7 @@ reswitch: } else { n.Type = t.Type } - why = "string" + why := "string" if t.Etype == TARRAY { if Isfixedarray(t) { why = "array" @@ -797,7 +1043,7 @@ reswitch: } if Isconst(n.Right, CTINT) { - x = Mpgetfix(n.Right.Val.U.Xval) + x := Mpgetfix(n.Right.Val.U.Xval) if x < 0 { Yyerror("invalid %s index %v (index must be non-negative)", why, Nconv(n.Right, 0)) } else if Isfixedarray(t) && t.Bound > 0 && x >= t.Bound { @@ -819,54 +1065,61 @@ reswitch: n.Op = OINDEXMAP } - goto ret + break OpSwitch case ORECV: ok |= Etop | Erv typecheck(&n.Left, Erv) defaultlit(&n.Left, nil) - l = n.Left - t = l.Type + l := n.Left + t := l.Type if t == nil { - goto error + n.Type = nil + return } if t.Etype != TCHAN { Yyerror("invalid operation: %v (receive from non-chan type %v)", Nconv(n, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } if t.Chan&Crecv == 0 { Yyerror("invalid operation: %v (receive from send-only type %v)", Nconv(n, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } n.Type = t.Type - goto ret + break OpSwitch case OSEND: ok |= Etop - l = typecheck(&n.Left, Erv) + l := typecheck(&n.Left, Erv) typecheck(&n.Right, Erv) defaultlit(&n.Left, nil) l = n.Left - t = l.Type + t := l.Type if t == nil { - goto error + n.Type = nil + return } if t.Etype != TCHAN { Yyerror("invalid operation: %v (send to non-chan type %v)", Nconv(n, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } if t.Chan&Csend == 0 { Yyerror("invalid operation: %v (send to receive-only type %v)", Nconv(n, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } defaultlit(&n.Right, t.Type) - r = n.Right + r := n.Right if r.Type == nil { - goto error + n.Type = nil + return } n.Right = assignconv(r, l.Type.Type, "send") @@ -874,7 +1127,7 @@ reswitch: n.Etype = 0 n.Type = nil - goto ret + break OpSwitch case OSLICE: ok |= Erv @@ -884,11 +1137,12 @@ reswitch: defaultlit(&n.Left, nil) indexlit(&n.Right.Left) indexlit(&n.Right.Right) - l = n.Left + l := n.Left if Isfixedarray(l.Type) { if !islvalue(n.Left) { Yyerror("invalid operation %v (slice of unaddressable value)", Nconv(n, 0)) - goto error + n.Type = nil + return } n.Left = Nod(OADDR, n.Left, nil) @@ -897,11 +1151,12 @@ reswitch: l = n.Left } - t = l.Type + t := l.Type if t == nil { - goto error + n.Type = nil + return } - tp = nil + var tp *Type if Istype(t, TSTRING) { n.Type = t n.Op = OSLICESTR @@ -916,21 +1171,25 @@ reswitch: n.Type = t } else { Yyerror("cannot slice %v (type %v)", Nconv(l, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } - lo = n.Right.Left + lo := n.Right.Left if lo != nil && checksliceindex(l, lo, tp) < 0 { - goto error + n.Type = nil + return } - hi = n.Right.Right + hi := n.Right.Right if hi != nil && checksliceindex(l, hi, tp) < 0 { - goto error + n.Type = nil + return } if checksliceconst(lo, hi) < 0 { - goto error + n.Type = nil + return } - goto ret + break OpSwitch case OSLICE3: ok |= Erv @@ -942,11 +1201,12 @@ reswitch: indexlit(&n.Right.Left) indexlit(&n.Right.Right.Left) indexlit(&n.Right.Right.Right) - l = n.Left + l := n.Left if Isfixedarray(l.Type) { if !islvalue(n.Left) { Yyerror("invalid operation %v (slice of unaddressable value)", Nconv(n, 0)) - goto error + n.Type = nil + return } n.Left = Nod(OADDR, n.Left, nil) @@ -955,16 +1215,18 @@ reswitch: l = n.Left } - t = l.Type + t := l.Type if t == nil { - goto error + n.Type = nil + return } - tp = nil if Istype(t, TSTRING) { Yyerror("invalid operation %v (3-index slice of string)", Nconv(n, 0)) - goto error + n.Type = nil + return } + var tp *Type if Isptr[t.Etype] && Isfixedarray(t.Type) { tp = t.Type n.Type = typ(TARRAY) @@ -976,40 +1238,46 @@ reswitch: n.Type = t } else { Yyerror("cannot slice %v (type %v)", Nconv(l, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } - lo = n.Right.Left + lo := n.Right.Left if lo != nil && checksliceindex(l, lo, tp) < 0 { - goto error + n.Type = nil + return } - mid = n.Right.Right.Left + mid := n.Right.Right.Left if mid != nil && checksliceindex(l, mid, tp) < 0 { - goto error + n.Type = nil + return } - hi = n.Right.Right.Right + hi := n.Right.Right.Right if hi != nil && checksliceindex(l, hi, tp) < 0 { - goto error + n.Type = nil + return } if checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0 { - goto error + n.Type = nil + return } - goto ret + break OpSwitch /* * call and call like */ case OCALL: - l = n.Left + l := n.Left if l.Op == ONAME { - r = unsafenmagic(n) + r := unsafenmagic(n) if r != nil { if n.Isddd != 0 { Yyerror("invalid use of ... with builtin %v", Nconv(l, 0)) } n = r - goto reswitch + typecheck1(&n, top) + return } } @@ -1026,11 +1294,12 @@ reswitch: n.Left = n.Right n.Right = nil - goto reswitch + typecheck1(&n, top) + return } defaultlit(&n.Left, nil) - l := n.Left + l = n.Left if l.Op == OTYPE { if n.Isddd != 0 || l.Type.Bound == -100 { if l.Type.Broke == 0 { @@ -1048,9 +1317,11 @@ reswitch: n.Op = OCONV n.Type = l.Type if onearg(n, "conversion to %v", Tconv(l.Type, 0)) < 0 { - goto error + n.Type = nil + return } - goto doconv + typecheck1(&n, top) + return } if count(n.List) == 1 && n.Isddd == 0 { @@ -1060,7 +1331,8 @@ reswitch: } t := l.Type if t == nil { - goto error + n.Type = nil + return } checkwidth(t) @@ -1085,7 +1357,8 @@ reswitch: n.Op = OCALLFUNC if t.Etype != TFUNC { Yyerror("cannot call non-function %v (type %v)", Nconv(l, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } } @@ -1094,29 +1367,30 @@ reswitch: typecheckaste(OCALL, n.Left, int(n.Isddd), getinargx(t), n.List, desc) ok |= Etop if t.Outtuple == 0 { - goto ret + break OpSwitch } ok |= Erv if t.Outtuple == 1 { t := getoutargx(l.Type).Type if t == nil { - goto error + n.Type = nil + return } if t.Etype == TFIELD { t = t.Type } n.Type = t - goto ret + break OpSwitch } // multiple return if top&(Efnstruct|Etop) == 0 { Yyerror("multiple-value %v() in single-value context", Nconv(l, 0)) - goto ret + break OpSwitch } n.Type = getoutargx(l.Type) - goto ret + break OpSwitch case OCAP, OLEN, @@ -1124,7 +1398,8 @@ reswitch: OIMAG: ok |= Erv if onearg(n, "%v", Oconv(int(n.Op), 0)) < 0 { - goto error + n.Type = nil + return } typecheck(&n.Left, Erv) defaultlit(&n.Left, nil) @@ -1132,7 +1407,8 @@ reswitch: l := n.Left t := l.Type if t == nil { - goto error + n.Type = nil + return } switch n.Op { case OCAP: @@ -1161,7 +1437,7 @@ reswitch: } n.Type = Types[cplxsubtype(int(t.Etype))] - goto ret + break OpSwitch } // might be constant @@ -1188,7 +1464,12 @@ reswitch: } n.Type = Types[TINT] - goto ret + break OpSwitch + + badcall1: + Yyerror("invalid argument %v for %v", Nconv(n.Left, obj.FmtLong), Oconv(int(n.Op), 0)) + n.Type = nil + return case OCOMPLEX: ok |= Erv @@ -1198,13 +1479,15 @@ reswitch: typechecklist(n.List, Efnstruct) if n.List.N.Op != OCALLFUNC && n.List.N.Op != OCALLMETH { Yyerror("invalid operation: complex expects two arguments") - goto error + n.Type = nil + return } t := n.List.N.Left.Type if t.Outtuple != 2 { Yyerror("invalid operation: complex expects two arguments, %v returns %d results", Nconv(n.List.N, 0), t.Outtuple) - goto error + n.Type = nil + return } t = n.List.N.Type.Type @@ -1212,16 +1495,19 @@ reswitch: r = t.Down.Nname } else { if twoarg(n) < 0 { - goto error + n.Type = nil + return } l = typecheck(&n.Left, Erv|top&Eiota) r = typecheck(&n.Right, Erv|top&Eiota) if l.Type == nil || r.Type == nil { - goto error + n.Type = nil + return } defaultlit2(&l, &r, 0) if l.Type == nil || r.Type == nil { - goto error + n.Type = nil + return } n.Left = l n.Right = r @@ -1229,14 +1515,16 @@ reswitch: if !Eqtype(l.Type, r.Type) { Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0)) - goto error + n.Type = nil + return } var t *Type switch l.Type.Etype { default: Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", Nconv(n, 0), Tconv(l.Type, 0), r.Type) - goto error + n.Type = nil + return case TIDEAL: t = Types[TIDEAL] @@ -1257,47 +1545,54 @@ reswitch: } n.Type = t - goto ret + break OpSwitch case OCLOSE: if onearg(n, "%v", Oconv(int(n.Op), 0)) < 0 { - goto error + n.Type = nil + return } typecheck(&n.Left, Erv) defaultlit(&n.Left, nil) l := n.Left t := l.Type if t == nil { - goto error + n.Type = nil + return } if t.Etype != TCHAN { Yyerror("invalid operation: %v (non-chan type %v)", Nconv(n, 0), Tconv(t, 0)) - goto error + n.Type = nil + return } if t.Chan&Csend == 0 { Yyerror("invalid operation: %v (cannot close receive-only channel)", Nconv(n, 0)) - goto error + n.Type = nil + return } ok |= Etop - goto ret + break OpSwitch case ODELETE: args := n.List if args == nil { Yyerror("missing arguments to delete") - goto error + n.Type = nil + return } if args.Next == nil { Yyerror("missing second (key) argument to delete") - goto error + n.Type = nil + return } if args.Next.Next != nil { Yyerror("too many arguments to delete") - goto error + n.Type = nil + return } ok |= Etop @@ -1306,18 +1601,20 @@ reswitch: r := args.Next.N if l.Type != nil && l.Type.Etype != TMAP { Yyerror("first argument to delete must be map; have %v", Tconv(l.Type, obj.FmtLong)) - goto error + n.Type = nil + return } args.Next.N = assignconv(r, l.Type.Down, "delete") - goto ret + break OpSwitch case OAPPEND: ok |= Erv args := n.List if args == nil { Yyerror("missing arguments to append") - goto error + n.Type = nil + return } if count(args) == 1 && n.Isddd == 0 { @@ -1328,7 +1625,8 @@ reswitch: t := args.N.Type if t == nil { - goto error + n.Type = nil + return } // Unpack multiple-return result before type-checking. @@ -1343,31 +1641,35 @@ reswitch: if !Isslice(t) { if Isconst(args.N, CTNIL) { Yyerror("first argument to append must be typed slice; have untyped nil", t) - goto error + n.Type = nil + return } Yyerror("first argument to append must be slice; have %v", Tconv(t, obj.FmtLong)) - goto error + n.Type = nil + return } if n.Isddd != 0 { if args.Next == nil { Yyerror("cannot use ... on first argument to append") - goto error + n.Type = nil + return } if args.Next.Next != nil { Yyerror("too many arguments to append") - goto error + n.Type = nil + return } if Istype(t.Type, TUINT8) && Istype(args.Next.N.Type, TSTRING) { defaultlit(&args.Next.N, Types[TSTRING]) - goto ret + break OpSwitch } args.Next.N = assignconv(args.Next.N, t.Orig, "append") - goto ret + break OpSwitch } for args = args.Next; args != nil; args = args.Next { @@ -1377,19 +1679,21 @@ reswitch: args.N = assignconv(args.N, t.Type, "append") } - goto ret + break OpSwitch case OCOPY: ok |= Etop | Erv args := n.List if args == nil || args.Next == nil { Yyerror("missing arguments to copy") - goto error + n.Type = nil + return } if args.Next.Next != nil { Yyerror("too many arguments to copy") - goto error + n.Type = nil + return } n.Left = args.N @@ -1399,21 +1703,24 @@ reswitch: typecheck(&n.Left, Erv) typecheck(&n.Right, Erv) if n.Left.Type == nil || n.Right.Type == nil { - goto error + n.Type = nil + return } defaultlit(&n.Left, nil) defaultlit(&n.Right, nil) if n.Left.Type == nil || n.Right.Type == nil { - goto error + n.Type = nil + return } // copy([]byte, string) if Isslice(n.Left.Type) && n.Right.Type.Etype == TSTRING { if Eqtype(n.Left.Type.Type, bytetype) { - goto ret + break OpSwitch } Yyerror("arguments to copy have different element types: %v and string", Tconv(n.Left.Type, obj.FmtLong)) - goto error + n.Type = nil + return } if !Isslice(n.Left.Type) || !Isslice(n.Right.Type) { @@ -1424,25 +1731,73 @@ reswitch: } else { Yyerror("second argument to copy should be slice or string; have %v", Tconv(n.Right.Type, obj.FmtLong)) } - goto error + n.Type = nil + return } if !Eqtype(n.Left.Type.Type, n.Right.Type.Type) { Yyerror("arguments to copy have different element types: %v and %v", Tconv(n.Left.Type, obj.FmtLong), Tconv(n.Right.Type, obj.FmtLong)) - goto error + n.Type = nil + return } - goto ret + break OpSwitch case OCONV: - goto doconv + { + ok |= Erv + saveorignode(n) + typecheck(&n.Left, Erv|top&(Eindir|Eiota)) + convlit1(&n.Left, n.Type, true) + t := n.Left.Type + if t == nil || n.Type == nil { + n.Type = nil + return + } + var why string + n.Op = uint8(convertop(t, n.Type, &why)) + if (n.Op) == 0 { + if n.Diag == 0 && n.Type.Broke == 0 { + Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), Tconv(n.Type, 0), why) + n.Diag = 1 + } + + n.Op = OCONV + } + + switch n.Op { + case OCONVNOP: + if n.Left.Op == OLITERAL && n.Type != Types[TBOOL] { + r := Nod(OXXX, nil, nil) + n.Op = OCONV + n.Orig = r + *r = *n + n.Op = OLITERAL + n.Val = n.Left.Val + } + + // do not use stringtoarraylit. + // generated code and compiler memory footprint is better without it. + case OSTRARRAYBYTE: + break + + case OSTRARRAYRUNE: + if n.Left.Op == OLITERAL { + stringtoarraylit(&n) + } + } + + break OpSwitch + } + break OpSwitch case OMAKE: ok |= Erv args := n.List if args == nil { Yyerror("missing argument to make") - goto error + n.Type = nil + return } n.List = nil @@ -1451,23 +1806,27 @@ reswitch: typecheck(&l, Etype) t := l.Type if t == nil { - goto error + n.Type = nil + return } switch t.Etype { default: Yyerror("cannot make type %v", Tconv(t, 0)) - goto error + n.Type = nil + return case TARRAY: if !Isslice(t) { Yyerror("cannot make type %v", Tconv(t, 0)) - goto error + n.Type = nil + return } if args == nil { Yyerror("missing len argument to make(%v)", Tconv(t, 0)) - goto error + n.Type = nil + return } l = args.N @@ -1481,16 +1840,19 @@ reswitch: } if l.Type == nil || (r != nil && r.Type == nil) { - goto error + n.Type = nil + return } et := bool2int(checkmake(t, "len", l) < 0) et |= bool2int(r != nil && checkmake(t, "cap", r) < 0) if et != 0 { - goto error + n.Type = nil + return } if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.Xval, r.Val.U.Xval) > 0 { Yyerror("len larger than cap in make(%v)", Tconv(t, 0)) - goto error + n.Type = nil + return } n.Left = l @@ -1504,10 +1866,12 @@ reswitch: typecheck(&l, Erv) defaultlit(&l, Types[TINT]) if l.Type == nil { - goto error + n.Type = nil + return } if checkmake(t, "size", l) < 0 { - goto error + n.Type = nil + return } n.Left = l } else { @@ -1523,10 +1887,12 @@ reswitch: typecheck(&l, Erv) defaultlit(&l, Types[TINT]) if l.Type == nil { - goto error + n.Type = nil + return } if checkmake(t, "buffer", l) < 0 { - goto error + n.Type = nil + return } n.Left = l } else { @@ -1538,34 +1904,38 @@ reswitch: if args != nil { Yyerror("too many arguments to make(%v)", Tconv(t, 0)) n.Op = OMAKE - goto error + n.Type = nil + return } n.Type = t - goto ret + break OpSwitch case ONEW: ok |= Erv args := n.List if args == nil { Yyerror("missing argument to new") - goto error + n.Type = nil + return } l := args.N typecheck(&l, Etype) t := l.Type if t == nil { - goto error + n.Type = nil + return } if args.Next != nil { Yyerror("too many arguments to new(%v)", Tconv(t, 0)) - goto error + n.Type = nil + return } n.Left = l n.Type = Ptrto(t) - goto ret + break OpSwitch case OPRINT, OPRINTN: @@ -1580,57 +1950,63 @@ reswitch: } } - goto ret + break OpSwitch case OPANIC: ok |= Etop if onearg(n, "panic") < 0 { - goto error + n.Type = nil + return } typecheck(&n.Left, Erv) defaultlit(&n.Left, Types[TINTER]) if n.Left.Type == nil { - goto error + n.Type = nil + return } - goto ret + break OpSwitch case ORECOVER: ok |= Erv | Etop if n.List != nil { Yyerror("too many arguments to recover") - goto error + n.Type = nil + return } n.Type = Types[TINTER] - goto ret + break OpSwitch case OCLOSURE: ok |= Erv typecheckclosure(n, top) if n.Type == nil { - goto error + n.Type = nil + return } - goto ret + break OpSwitch case OITAB: ok |= Erv typecheck(&n.Left, Erv) t := n.Left.Type if t == nil { - goto error + n.Type = nil + return } if t.Etype != TINTER { Fatal("OITAB of %v", Tconv(t, 0)) } n.Type = Ptrto(Types[TUINTPTR]) - goto ret + break OpSwitch case OSPTR: ok |= Erv typecheck(&n.Left, Erv) t := n.Left.Type if t == nil { - goto error + n.Type = nil + return } if !Isslice(t) && t.Etype != TSTRING { Fatal("OSPTR of %v", Tconv(t, 0)) @@ -1640,22 +2016,22 @@ reswitch: } else { n.Type = Ptrto(t.Type) } - goto ret + break OpSwitch case OCLOSUREVAR: ok |= Erv - goto ret + break OpSwitch case OCFUNC: ok |= Erv typecheck(&n.Left, Erv) n.Type = Types[TUINTPTR] - goto ret + break OpSwitch case OCONVNOP: ok |= Erv typecheck(&n.Left, Erv) - goto ret + break OpSwitch /* * statements @@ -1669,12 +2045,12 @@ reswitch: if n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") { n.Left.Defn = n } - goto ret + break OpSwitch case OAS2: ok |= Etop typecheckas2(n) - goto ret + break OpSwitch case OBREAK, OCONTINUE, @@ -1684,12 +2060,12 @@ reswitch: OXFALL, OVARKILL: ok |= Etop - goto ret + break OpSwitch case OLABEL: ok |= Etop decldepth++ - goto ret + break OpSwitch case ODEFER: ok |= Etop @@ -1697,13 +2073,13 @@ reswitch: if n.Left.Diag == 0 { checkdefergo(n) } - goto ret + break OpSwitch case OPROC: ok |= Etop typecheck(&n.Left, Etop|Eproc|Erv) checkdefergo(n) - goto ret + break OpSwitch case OFOR: ok |= Etop @@ -1719,7 +2095,7 @@ reswitch: typecheck(&n.Nincr, Etop) typechecklist(n.Nbody, Etop) decldepth-- - goto ret + break OpSwitch case OIF: ok |= Etop @@ -1733,7 +2109,7 @@ reswitch: } typechecklist(n.Nbody, Etop) typechecklist(n.Nelse, Etop) - goto ret + break OpSwitch case ORETURN: ok |= Etop @@ -1744,53 +2120,55 @@ reswitch: } if Curfn == nil { Yyerror("return outside function") - goto error + n.Type = nil + return } if Curfn.Type.Outnamed != 0 && n.List == nil { - goto ret + break OpSwitch } typecheckaste(ORETURN, nil, 0, getoutargx(Curfn.Type), n.List, "return argument") - goto ret + break OpSwitch case ORETJMP: ok |= Etop - goto ret + break OpSwitch case OSELECT: ok |= Etop typecheckselect(n) - goto ret + break OpSwitch case OSWITCH: ok |= Etop typecheckswitch(n) - goto ret + break OpSwitch case ORANGE: ok |= Etop typecheckrange(n) - goto ret + break OpSwitch case OTYPESW: Yyerror("use of .(type) outside type switch") - goto error + n.Type = nil + return case OXCASE: ok |= Etop typechecklist(n.List, Erv) typechecklist(n.Nbody, Etop) - goto ret + break OpSwitch case ODCLFUNC: ok |= Etop typecheckfunc(n) - goto ret + break OpSwitch case ODCLCONST: ok |= Etop typecheck(&n.Left, Erv) - goto ret + break OpSwitch case ODCLTYPE: ok |= Etop @@ -1798,264 +2176,10 @@ reswitch: if incannedimport == 0 { checkwidth(n.Left.Type) } - goto ret + break OpSwitch } - goto ret - -arith: - if op == OLSH || op == ORSH { - defaultlit(&r, Types[TUINT]) - n.Right = r - t := r.Type - if !Isint[t.Etype] || Issigned[t.Etype] { - Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", Nconv(n, 0), Tconv(r.Type, 0)) - goto error - } - - t = l.Type - if t != nil && t.Etype != TIDEAL && !Isint[t.Etype] { - Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0)) - goto error - } - - // no defaultlit for left - // the outer context gives the type - n.Type = l.Type - - goto ret - } - - // ideal mixed with non-ideal - defaultlit2(&l, &r, 0) - - n.Left = l - n.Right = r - if l.Type == nil || r.Type == nil { - goto error - } - t = l.Type - if t.Etype == TIDEAL { - t = r.Type - } - et = int(t.Etype) - if et == TIDEAL { - et = TINT - } - aop = 0 - if iscmp[n.Op] && t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) { - // comparison is okay as long as one side is - // assignable to the other. convert so they have - // the same type. - // - // the only conversion that isn't a no-op is concrete == interface. - // in that case, check comparability of the concrete type. - // The conversion allocates, so only do it if the concrete type is huge. - if r.Type.Etype != TBLANK { - aop = assignop(l.Type, r.Type, nil) - if aop != 0 { - if Isinter(r.Type) && !Isinter(l.Type) && algtype1(l.Type, nil) == ANOEQ { - Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(l.Type)) - goto error - } - - dowidth(l.Type) - if Isinter(r.Type) == Isinter(l.Type) || l.Type.Width >= 1<<16 { - l = Nod(aop, l, nil) - l.Type = r.Type - l.Typecheck = 1 - n.Left = l - } - - t = r.Type - goto converted - } - } - - if l.Type.Etype != TBLANK { - aop = assignop(r.Type, l.Type, nil) - if aop != 0 { - if Isinter(l.Type) && !Isinter(r.Type) && algtype1(r.Type, nil) == ANOEQ { - Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(r.Type)) - goto error - } - - dowidth(r.Type) - if Isinter(r.Type) == Isinter(l.Type) || r.Type.Width >= 1<<16 { - r = Nod(aop, r, nil) - r.Type = l.Type - r.Typecheck = 1 - n.Right = r - } - - t = l.Type - } - } - - converted: - et = int(t.Etype) - } - - if t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) { - defaultlit2(&l, &r, 1) - if n.Op == OASOP && n.Implicit != 0 { - Yyerror("invalid operation: %v (non-numeric type %v)", Nconv(n, 0), Tconv(l.Type, 0)) - goto error - } - - if Isinter(r.Type) == Isinter(l.Type) || aop == 0 { - Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0)) - goto error - } - } - - if !okfor[op][et] { - Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(t)) - goto error - } - - // okfor allows any array == array, map == map, func == func. - // restrict to slice/map/func == nil and nil == slice/map/func. - if Isfixedarray(l.Type) && algtype1(l.Type, nil) == ANOEQ { - Yyerror("invalid operation: %v (%v cannot be compared)", Nconv(n, 0), Tconv(l.Type, 0)) - goto error - } - - if Isslice(l.Type) && !isnil(l) && !isnil(r) { - Yyerror("invalid operation: %v (slice can only be compared to nil)", Nconv(n, 0)) - goto error - } - - if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) { - Yyerror("invalid operation: %v (map can only be compared to nil)", Nconv(n, 0)) - goto error - } - - if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) { - Yyerror("invalid operation: %v (func can only be compared to nil)", Nconv(n, 0)) - goto error - } - - if l.Type.Etype == TSTRUCT && algtype1(l.Type, &badtype) == ANOEQ { - Yyerror("invalid operation: %v (struct containing %v cannot be compared)", Nconv(n, 0), Tconv(badtype, 0)) - goto error - } - - t = l.Type - if iscmp[n.Op] { - evconst(n) - t = idealbool - if n.Op != OLITERAL { - defaultlit2(&l, &r, 1) - n.Left = l - n.Right = r - } - } else if n.Op == OANDAND || n.Op == OOROR { - if l.Type == r.Type { - t = l.Type - } else if l.Type == idealbool { - t = r.Type - } else if r.Type == idealbool { - t = l.Type - } - } else - // non-comparison operators on ideal bools should make them lose their ideal-ness - if t == idealbool { - t = Types[TBOOL] - } - - if et == TSTRING { - if iscmp[n.Op] { - n.Etype = n.Op - n.Op = OCMPSTR - } else if n.Op == OADD { - // create OADDSTR node with list of strings in x + y + z + (w + v) + ... - n.Op = OADDSTR - - if l.Op == OADDSTR { - n.List = l.List - } else { - n.List = list1(l) - } - if r.Op == OADDSTR { - n.List = concat(n.List, r.List) - } else { - n.List = list(n.List, r) - } - n.Left = nil - n.Right = nil - } - } - - if et == TINTER { - if l.Op == OLITERAL && l.Val.Ctype == CTNIL { - // swap for back end - n.Left = r - - n.Right = l - } else if r.Op == OLITERAL && r.Val.Ctype == CTNIL { - } else // leave alone for back end - if Isinter(r.Type) == Isinter(l.Type) { - n.Etype = n.Op - n.Op = OCMPIFACE - } - } - - if (op == ODIV || op == OMOD) && Isconst(r, CTINT) { - if mpcmpfixc(r.Val.U.Xval, 0) == 0 { - Yyerror("division by zero") - goto error - } - } - - n.Type = t - goto ret - -doconv: - ok |= Erv - saveorignode(n) - typecheck(&n.Left, Erv|top&(Eindir|Eiota)) - convlit1(&n.Left, n.Type, true) - t = n.Left.Type - if t == nil || n.Type == nil { - goto error - } - n.Op = uint8(convertop(t, n.Type, &why)) - if (n.Op) == 0 { - if n.Diag == 0 && n.Type.Broke == 0 { - Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), Tconv(n.Type, 0), why) - n.Diag = 1 - } - - n.Op = OCONV - } - - switch n.Op { - case OCONVNOP: - if n.Left.Op == OLITERAL && n.Type != Types[TBOOL] { - r := Nod(OXXX, nil, nil) - n.Op = OCONV - n.Orig = r - *r = *n - n.Op = OLITERAL - n.Val = n.Left.Val - } - - // do not use stringtoarraylit. - // generated code and compiler memory footprint is better without it. - case OSTRARRAYBYTE: - break - - case OSTRARRAYRUNE: - if n.Left.Op == OLITERAL { - stringtoarraylit(&n) - } - } - - goto ret - -ret: - t = n.Type + t := n.Type if t != nil && t.Funarg == 0 && n.Op != OTYPE { switch t.Etype { case TFUNC, // might have TANY; wait until its called @@ -2078,18 +2202,21 @@ ret: evconst(n) if n.Op == OTYPE && top&Etype == 0 { Yyerror("type %v is not an expression", Tconv(n.Type, 0)) - goto error + n.Type = nil + return } if top&(Erv|Etype) == Etype && n.Op != OTYPE { Yyerror("%v is not a type", Nconv(n, 0)) - goto error + n.Type = nil + return } // TODO(rsc): simplify if (top&(Ecall|Erv|Etype) != 0) && top&Etop == 0 && ok&(Erv|Etype|Ecall) == 0 { Yyerror("%v used as value", Nconv(n, 0)) - goto error + n.Type = nil + return } if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 { @@ -2098,24 +2225,14 @@ ret: n.Diag = 1 } - goto error + n.Type = nil + return } /* TODO if(n->type == T) fatal("typecheck nil type"); */ - goto out - -badcall1: - Yyerror("invalid argument %v for %v", Nconv(n.Left, obj.FmtLong), Oconv(int(n.Op), 0)) - goto error - -error: - n.Type = nil - -out: - *np = n } func checksliceindex(l *Node, r *Node, tp *Type) int { @@ -2840,35 +2957,35 @@ func pushtype(n *Node, t *Type) { } func typecheckcomplit(np **Node) { - var nerr int - var l *Node - var norig *Node - var r *Node - var t *Type - n := *np lno := lineno + defer func() { + lineno = lno + *np = n + }() if n.Right == nil { if n.List != nil { setlineno(n.List.N) } Yyerror("missing type in composite literal") - goto error + n.Type = nil + return } // Save original node (including n->right) - norig = Nod(int(n.Op), nil, nil) + norig := Nod(int(n.Op), nil, nil) *norig = *n setlineno(n.Right) - l = typecheck(&n.Right, Etype|Ecomplit) /* sic */ - t = l.Type + l := typecheck(&n.Right, Etype|Ecomplit) /* sic */ + t := l.Type if t == nil { - goto error + n.Type = nil + return } - nerr = nerrors + nerr := nerrors n.Type = t if Isptr[t.Etype] { @@ -2876,18 +2993,21 @@ func typecheckcomplit(np **Node) { // except when using the &T syntax, which sets implicit on the OIND. if n.Right.Implicit == 0 { Yyerror("invalid pointer type %v for composite literal (use &%v instead)", Tconv(t, 0), Tconv(t.Type, 0)) - goto error + n.Type = nil + return } // Also, the underlying type must be a struct, map, slice, or array. if !iscomptype(t) { Yyerror("invalid pointer type %v for composite literal", Tconv(t, 0)) - goto error + n.Type = nil + return } t = t.Type } + var r *Node switch t.Etype { default: Yyerror("invalid type for composite literal: %v", Tconv(t, 0)) @@ -3075,7 +3195,8 @@ func typecheckcomplit(np **Node) { } if nerr != nerrors { - goto error + n.Type = nil + return } n.Orig = norig @@ -3088,14 +3209,7 @@ func typecheckcomplit(np **Node) { } n.Orig = norig - *np = n - lineno = lno return - -error: - n.Type = nil - *np = n - lineno = lno } /* diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go index ed46809a37..0992c181cd 100644 --- a/src/cmd/internal/gc/walk.go +++ b/src/cmd/internal/gc/walk.go @@ -3235,9 +3235,6 @@ func sliceany(n *Node, init **NodeList) *Node { // Checking src[lb:hb:cb] or src[lb:hb]. // if chk0 || chk1 || chk2 { panicslice() } - var chk0 *Node // cap(src) < cb - var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb] - var chk2 *Node // hb < lb // All comparisons are unsigned to avoid testing < 0. bt := Types[Simtype[TUINT]] @@ -3254,6 +3251,7 @@ func sliceany(n *Node, init **NodeList) *Node { bound = cheapexpr(conv(bound, bt), init) + var chk0 *Node // cap(src) < cb if cb != nil { cb = cheapexpr(conv(cb, bt), init) if bounded == 0 { @@ -3264,6 +3262,7 @@ func sliceany(n *Node, init **NodeList) *Node { Fatal("slice3 with cb == N") // rejected by parser } + var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb] if hb != nil { hb = cheapexpr(conv(hb, bt), init) if bounded == 0 { @@ -3285,6 +3284,7 @@ func sliceany(n *Node, init **NodeList) *Node { hb = cheapexpr(conv(hb, bt), init) } + var chk2 *Node // hb < lb if lb != nil { lb = cheapexpr(conv(lb, bt), init) if bounded == 0 { @@ -3432,14 +3432,6 @@ func walkcompare(np **Node, init **NodeList) { r = n.Left } - var call *Node - var a *Node - var cmpl *Node - var cmpr *Node - var andor int - var expr *Node - var needsize int - var t *Type if l != nil { x := temp(r.Type) ok := temp(Types[TBOOL]) @@ -3464,12 +3456,13 @@ func walkcompare(np **Node, init **NodeList) { r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r)) } *init = list(*init, expr) - goto ret + finishcompare(np, n, r, init) + return } // Must be comparison of array or struct. // Otherwise back end handles it. - t = n.Left.Type + t := n.Left.Type switch t.Etype { default: @@ -3484,11 +3477,11 @@ func walkcompare(np **Node, init **NodeList) { break } - cmpl = n.Left + cmpl := n.Left for cmpl != nil && cmpl.Op == OCONVNOP { cmpl = cmpl.Left } - cmpr = n.Right + cmpr := n.Right for cmpr != nil && cmpr.Op == OCONVNOP { cmpr = cmpr.Left } @@ -3498,7 +3491,7 @@ func walkcompare(np **Node, init **NodeList) { } l = temp(Ptrto(t)) - a = Nod(OAS, l, Nod(OADDR, cmpl, nil)) + a := Nod(OAS, l, Nod(OADDR, cmpl, nil)) a.Right.Etype = 1 // addr does not escape typecheck(&a, Etop) *init = list(*init, a) @@ -3509,12 +3502,12 @@ func walkcompare(np **Node, init **NodeList) { typecheck(&a, Etop) *init = list(*init, a) - expr = nil - andor = OANDAND + andor := OANDAND if n.Op == ONE { andor = OOROR } + var expr *Node if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] { // Four or fewer elements of a basic type. // Unroll comparisons. @@ -3534,8 +3527,8 @@ func walkcompare(np **Node, init **NodeList) { if expr == nil { expr = Nodbool(n.Op == OEQ) } - r = expr - goto ret + finishcompare(np, n, expr, init) + return } if t.Etype == TSTRUCT && countfield(t) <= 4 { @@ -3560,12 +3553,13 @@ func walkcompare(np **Node, init **NodeList) { if expr == nil { expr = Nodbool(n.Op == OEQ) } - r = expr - goto ret + finishcompare(np, n, expr, init) + return } // Chose not to inline. Call equality function directly. - call = Nod(OCALL, eqfor(t, &needsize), nil) + var needsize int + call := Nod(OCALL, eqfor(t, &needsize), nil) call.List = list(call.List, l) call.List = list(call.List, r) @@ -3576,19 +3570,23 @@ func walkcompare(np **Node, init **NodeList) { if n.Op != OEQ { r = Nod(ONOT, r, nil) } - goto ret -ret: - typecheck(&r, Erv) - walkexpr(&r, init) + finishcompare(np, n, r, init) + return +} + +func finishcompare(np **Node, n, r *Node, init **NodeList) { + // Using np here to avoid passing &r to typecheck. + *np = r + typecheck(np, Erv) + walkexpr(np, init) + r = *np if r.Type != n.Type { r = Nod(OCONVNOP, r, nil) r.Type = n.Type r.Typecheck = 1 + *np = r } - - *np = r - return } func samecheap(a *Node, b *Node) bool {