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
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 {
......
......@@ -766,12 +766,14 @@ func gmove(f *gc.Node, t *gc.Node) {
// removed.
// requires register destination
rdst:
{
regalloc(&r1, t.Type, t)
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:
......
......@@ -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
......
......@@ -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)
......
......@@ -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:
{
var r1 gc.Node
regalloc(&r1, t.Type, t)
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:
......
......@@ -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
......
......@@ -1148,12 +1148,14 @@ rsrc:
// requires register destination
rdst:
{
regalloc(&r1, t.Type, t)
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 {
......
......@@ -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 {
......
......@@ -669,12 +669,14 @@ func gmove(f *gc.Node, t *gc.Node) {
// requires register destination
rdst:
{
regalloc(&r1, t.Type, t)
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 {
......
......@@ -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))
......
......@@ -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")
......
......@@ -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 {
......
......@@ -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]
......
......@@ -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 {
......
......@@ -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,139 +545,387 @@ reswitch:
OOROR,
OSUB,
OXOR:
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 {
goto error
n.Type = nil
return
}
op = int(n.Op)
goto 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))
n.Type = nil
return
}
case OCOM,
OMINUS,
ONOT,
OPLUS:
ok |= Erv
l = typecheck(&n.Left, Erv|top&Eiota)
t = l.Type
if t == nil {
goto error
}
if !okfor[n.Op][t.Etype] {
Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), Tconv(t, 0))
goto error
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
}
n.Type = t
goto ret
// no defaultlit for left
// the outer context gives the type
n.Type = l.Type
/*
* exprs
*/
case OADDR:
ok |= Erv
break OpSwitch
}
typecheck(&n.Left, Erv|Eaddr)
if n.Left.Type == nil {
goto error
// ideal mixed with non-ideal
defaultlit2(&l, &r, 0)
n.Left = l
n.Right = r
if l.Type == nil || r.Type == nil {
n.Type = nil
return
}
checklvalue(n.Left, "take the address of")
r = outervalue(n.Left)
for l = n.Left; l != r; l = l.Left {
l.Addrtaken = 1
if l.Closure != nil {
l.Closure.Addrtaken = 1
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
}
if l.Orig != l && l.Op == ONAME {
Fatal("found non-orig name node %v", Nconv(l, 0))
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
}
l.Addrtaken = 1
if l.Closure != nil {
l.Closure.Addrtaken = 1
t = r.Type
goto converted
}
defaultlit(&n.Left, nil)
l = n.Left
t = l.Type
if t == nil {
goto error
}
n.Type = Ptrto(t)
goto ret
case OCOMPLIT:
ok |= Erv
typecheckcomplit(&n)
if n.Type == nil {
goto error
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
}
goto ret
case OXDOT:
n = adddot(n)
n.Op = ODOT
if n.Left == nil {
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
}
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
t = l.Type
}
}
t = n.Left.Type
if t == nil {
adderrorname(n)
goto error
converted:
et = int(t.Etype)
}
r = n.Right
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 n.Left.Op == OTYPE {
if !looktypedot(n, t, 0) {
if looktypedot(n, t, 1) {
Yyerror("%v undefined (cannot refer to unexported method %v)", Nconv(n, 0), Sconv(n.Right.Sym, 0))
} else {
Yyerror("%v undefined (type %v has no method %v)", Nconv(n, 0), Tconv(t, 0), Sconv(n.Right.Sym, 0))
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
}
goto error
}
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))
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
goto error
return
}
n.Op = ONAME
n.Sym = n.Right.Sym
n.Type = methodfunc(n.Type, n.Left.Type)
n.Xoffset = 0
n.Class = PFUNC
ok = Erv
goto ret
// 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 Isptr[t.Etype] && t.Type.Etype != TINTER {
t = t.Type
if t == nil {
goto error
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
}
n.Op = ODOTPTR
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
}
}
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
if t == nil {
n.Type = nil
return
}
if !okfor[n.Op][t.Etype] {
Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), Tconv(t, 0))
n.Type = nil
return
}
n.Type = t
break OpSwitch
/*
* exprs
*/
case OADDR:
ok |= Erv
typecheck(&n.Left, Erv|Eaddr)
if n.Left.Type == nil {
n.Type = nil
return
}
checklvalue(n.Left, "take the address of")
r := outervalue(n.Left)
var l *Node
for l = n.Left; l != r; l = l.Left {
l.Addrtaken = 1
if l.Closure != nil {
l.Closure.Addrtaken = 1
}
}
if l.Orig != l && l.Op == ONAME {
Fatal("found non-orig name node %v", Nconv(l, 0))
}
l.Addrtaken = 1
if l.Closure != nil {
l.Closure.Addrtaken = 1
}
defaultlit(&n.Left, nil)
l = n.Left
t := l.Type
if t == nil {
n.Type = nil
return
}
n.Type = Ptrto(t)
break OpSwitch
case OCOMPLIT:
ok |= Erv
typecheckcomplit(&n)
if n.Type == nil {
n.Type = nil
return
}
break OpSwitch
case OXDOT, ODOT:
if n.Op == OXDOT {
n = adddot(n)
n.Op = ODOT
if n.Left == nil {
n.Type = nil
return
}
}
typecheck(&n.Left, Erv|Etype)
defaultlit(&n.Left, nil)
if n.Right.Op != ONAME {
Yyerror("rhs of . must be a name") // impossible
n.Type = nil
return
}
t := n.Left.Type
if t == nil {
adderrorname(n)
n.Type = nil
return
}
r := n.Right
if n.Left.Op == OTYPE {
if !looktypedot(n, t, 0) {
if looktypedot(n, t, 1) {
Yyerror("%v undefined (cannot refer to unexported method %v)", Nconv(n, 0), Sconv(n.Right.Sym, 0))
} else {
Yyerror("%v undefined (type %v has no method %v)", Nconv(n, 0), Tconv(t, 0), Sconv(n.Right.Sym, 0))
}
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
n.Type = nil
return
}
n.Op = ONAME
n.Sym = n.Right.Sym
n.Type = methodfunc(n.Type, n.Left.Type)
n.Xoffset = 0
n.Class = PFUNC
ok = Erv
break OpSwitch
}
if Isptr[t.Etype] && t.Type.Etype != TINTER {
t = t.Type
if t == nil {
n.Type = nil
return
}
n.Op = ODOTPTR
checkwidth(t)
}
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,422 +2016,170 @@ 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
*/
case OAS:
ok |= Etop
typecheckas(n)
// Code that creates temps does not bother to set defn, so do it here.
if n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
n.Left.Defn = n
}
goto ret
case OAS2:
ok |= Etop
typecheckas2(n)
goto ret
case OBREAK,
OCONTINUE,
ODCL,
OEMPTY,
OGOTO,
OXFALL,
OVARKILL:
ok |= Etop
goto ret
case OLABEL:
ok |= Etop
decldepth++
goto ret
case ODEFER:
ok |= Etop
typecheck(&n.Left, Etop|Erv)
if n.Left.Diag == 0 {
checkdefergo(n)
}
goto ret
case OPROC:
ok |= Etop
typecheck(&n.Left, Etop|Eproc|Erv)
checkdefergo(n)
goto ret
case OFOR:
ok |= Etop
typechecklist(n.Ninit, Etop)
decldepth++
typecheck(&n.Ntest, Erv)
if n.Ntest != nil {
t := n.Ntest.Type
if t != nil && t.Etype != TBOOL {
Yyerror("non-bool %v used as for condition", Nconv(n.Ntest, obj.FmtLong))
}
}
typecheck(&n.Nincr, Etop)
typechecklist(n.Nbody, Etop)
decldepth--
goto ret
case OIF:
ok |= Etop
typechecklist(n.Ninit, Etop)
typecheck(&n.Ntest, Erv)
if n.Ntest != nil {
t := n.Ntest.Type
if t != nil && t.Etype != TBOOL {
Yyerror("non-bool %v used as if condition", Nconv(n.Ntest, obj.FmtLong))
}
}
typechecklist(n.Nbody, Etop)
typechecklist(n.Nelse, Etop)
goto ret
case ORETURN:
ok |= Etop
if count(n.List) == 1 {
typechecklist(n.List, Erv|Efnstruct)
} else {
typechecklist(n.List, Erv)
}
if Curfn == nil {
Yyerror("return outside function")
goto error
}
if Curfn.Type.Outnamed != 0 && n.List == nil {
goto ret
}
typecheckaste(ORETURN, nil, 0, getoutargx(Curfn.Type), n.List, "return argument")
goto ret
case ORETJMP:
ok |= Etop
goto ret
case OSELECT:
ok |= Etop
typecheckselect(n)
goto ret
case OSWITCH:
ok |= Etop
typecheckswitch(n)
goto ret
case ORANGE:
ok |= Etop
typecheckrange(n)
goto ret
case OTYPESW:
Yyerror("use of .(type) outside type switch")
goto error
case OXCASE:
ok |= Etop
typechecklist(n.List, Erv)
typechecklist(n.Nbody, Etop)
goto ret
case ODCLFUNC:
ok |= Etop
typecheckfunc(n)
goto ret
case ODCLCONST:
ok |= Etop
typecheck(&n.Left, Erv)
goto ret
case ODCLTYPE:
ok |= Etop
typecheck(&n.Left, Etype)
if incannedimport == 0 {
checkwidth(n.Left.Type)
}
goto ret
}
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
}
}
case OAS:
ok |= Etop
converted:
et = int(t.Etype)
}
typecheckas(n)
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
// Code that creates temps does not bother to set defn, so do it here.
if n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
n.Left.Defn = n
}
break OpSwitch
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
}
}
case OAS2:
ok |= Etop
typecheckas2(n)
break OpSwitch
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
}
case OBREAK,
OCONTINUE,
ODCL,
OEMPTY,
OGOTO,
OXFALL,
OVARKILL:
ok |= Etop
break OpSwitch
// 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
}
case OLABEL:
ok |= Etop
decldepth++
break OpSwitch
if Isslice(l.Type) && !isnil(l) && !isnil(r) {
Yyerror("invalid operation: %v (slice can only be compared to nil)", Nconv(n, 0))
goto error
case ODEFER:
ok |= Etop
typecheck(&n.Left, Etop|Erv)
if n.Left.Diag == 0 {
checkdefergo(n)
}
break OpSwitch
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
}
case OPROC:
ok |= Etop
typecheck(&n.Left, Etop|Eproc|Erv)
checkdefergo(n)
break OpSwitch
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
case OFOR:
ok |= Etop
typechecklist(n.Ninit, Etop)
decldepth++
typecheck(&n.Ntest, Erv)
if n.Ntest != nil {
t := n.Ntest.Type
if t != nil && t.Etype != TBOOL {
Yyerror("non-bool %v used as for condition", Nconv(n.Ntest, obj.FmtLong))
}
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
}
typecheck(&n.Nincr, Etop)
typechecklist(n.Nbody, Etop)
decldepth--
break OpSwitch
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
case OIF:
ok |= Etop
typechecklist(n.Ninit, Etop)
typecheck(&n.Ntest, Erv)
if n.Ntest != nil {
t := n.Ntest.Type
if t != nil && t.Etype != TBOOL {
Yyerror("non-bool %v used as if condition", Nconv(n.Ntest, obj.FmtLong))
}
} else
// non-comparison operators on ideal bools should make them lose their ideal-ness
if t == idealbool {
t = Types[TBOOL]
}
typechecklist(n.Nbody, Etop)
typechecklist(n.Nelse, Etop)
break OpSwitch
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)
case ORETURN:
ok |= Etop
if count(n.List) == 1 {
typechecklist(n.List, Erv|Efnstruct)
} else {
n.List = list(n.List, r)
typechecklist(n.List, Erv)
}
n.Left = nil
n.Right = nil
if Curfn == nil {
Yyerror("return outside function")
n.Type = nil
return
}
if Curfn.Type.Outnamed != 0 && n.List == nil {
break OpSwitch
}
typecheckaste(ORETURN, nil, 0, getoutargx(Curfn.Type), n.List, "return argument")
break OpSwitch
if et == TINTER {
if l.Op == OLITERAL && l.Val.Ctype == CTNIL {
// swap for back end
n.Left = r
case ORETJMP:
ok |= Etop
break OpSwitch
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
}
}
case OSELECT:
ok |= Etop
typecheckselect(n)
break OpSwitch
if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
if mpcmpfixc(r.Val.U.Xval, 0) == 0 {
Yyerror("division by zero")
goto error
}
}
case OSWITCH:
ok |= Etop
typecheckswitch(n)
break OpSwitch
n.Type = t
goto ret
case ORANGE:
ok |= Etop
typecheckrange(n)
break OpSwitch
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
}
case OTYPESW:
Yyerror("use of .(type) outside type switch")
n.Type = nil
return
n.Op = OCONV
}
case OXCASE:
ok |= Etop
typechecklist(n.List, Erv)
typechecklist(n.Nbody, Etop)
break OpSwitch
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
}
case ODCLFUNC:
ok |= Etop
typecheckfunc(n)
break OpSwitch
// do not use stringtoarraylit.
// generated code and compiler memory footprint is better without it.
case OSTRARRAYBYTE:
break
case ODCLCONST:
ok |= Etop
typecheck(&n.Left, Erv)
break OpSwitch
case OSTRARRAYRUNE:
if n.Left.Op == OLITERAL {
stringtoarraylit(&n)
case ODCLTYPE:
ok |= Etop
typecheck(&n.Left, Etype)
if incannedimport == 0 {
checkwidth(n.Left.Type)
}
break OpSwitch
}
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
}
/*
......
......@@ -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
return
}
}
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