Commit 4492811c authored by Russ Cox's avatar Russ Cox

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