base.Errorf("%v is not a top level statement", n.Op())
}
ir.Dump("nottop", n)
+ return n
case ir.OAS,
ir.OASOP,
n = ir.NewBlockStmt(n.Pos(), init.Slice())
}
}
+ return n
// special case for a receive where we throw away
// the value received.
n.SetLeft(walkexpr(n.Left(), &init))
n = mkcall1(chanfn("chanrecv1", 2, n.Left().Type()), nil, &init, n.Left(), nodnil())
n = walkexpr(n, &init)
-
- n = initExpr(init.Slice(), n)
+ return initExpr(init.Slice(), n)
case ir.OBREAK,
ir.OCONTINUE,
ir.OVARDEF,
ir.OVARKILL,
ir.OVARLIVE:
- break
+ return n
case ir.ODCL:
v := n.Left()
nn = typecheck(nn, ctxStmt)
return walkstmt(nn)
}
+ return n
case ir.OBLOCK:
walkstmtlist(n.List().Slice())
+ return n
case ir.OCASE:
base.Errorf("case statement out of place")
+ panic("unreachable")
case ir.ODEFER:
Curfn.SetHasDefer(true)
init.Append(n)
n = ir.NewBlockStmt(n.Pos(), init.Slice())
}
+ return n
case ir.OFOR, ir.OFORUNTIL:
if n.Left() != nil {
walkstmtlist(n.List().Slice())
}
walkstmtlist(n.Body().Slice())
+ return n
case ir.OIF:
n.SetLeft(walkexpr(n.Left(), n.PtrInit()))
walkstmtlist(n.Body().Slice())
walkstmtlist(n.Rlist().Slice())
+ return n
case ir.ORETURN:
Curfn.NumReturns++
if n.List().Len() == 0 {
- break
+ return n
}
if (hasNamedResults(Curfn) && n.List().Len() > 1) || paramoutheap(Curfn) {
// assign to the function out parameters,
ll := ascompatee(n.Op(), rl, n.List().Slice(), n.PtrInit())
n.PtrList().Set(reorder3(ll))
- break
+ return n
}
walkexprlist(n.List().Slice(), n.PtrInit())
res[i] = convas(a, n.PtrInit())
}
n.PtrList().Set(res)
+ return n
case ir.ORETJMP:
- break
+ return n
case ir.OINLMARK:
- break
+ return n
case ir.OSELECT:
walkselect(n)
+ return n
case ir.OSWITCH:
walkswitch(n)
+ return n
case ir.ORANGE:
- n = walkrange(n)
+ return walkrange(n)
}
- if n.Op() == ir.ONAME {
- base.Fatalf("walkstmt ended up with name: %+v", n)
- }
- return n
+ // No return! Each case must return (or panic),
+ // to avoid confusion about what gets returned
+ // in the presence of type assertions.
}
// walk the whole tree of the body of an
return nn
}
-opswitch:
+ n = walkexpr1(n, init)
+
+ // Expressions that are constant at run time but not
+ // considered const by the language spec are not turned into
+ // constants until walk. For example, if n is y%1 == 0, the
+ // walk of y%1 may have replaced it by 0.
+ // Check whether n with its updated args is itself now a constant.
+ t := n.Type()
+ n = evalConst(n)
+ if n.Type() != t {
+ base.Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type())
+ }
+ if n.Op() == ir.OLITERAL {
+ n = typecheck(n, ctxExpr)
+ // Emit string symbol now to avoid emitting
+ // any concurrently during the backend.
+ if v := n.Val(); v.Kind() == constant.String {
+ _ = stringsym(n.Pos(), constant.StringVal(v))
+ }
+ }
+
+ updateHasCall(n)
+
+ if base.Flag.LowerW != 0 && n != nil {
+ ir.Dump("after walk expr", n)
+ }
+
+ base.Pos = lno
+ return n
+}
+
+func walkexpr1(n ir.Node, init *ir.Nodes) ir.Node {
switch n.Op() {
default:
ir.Dump("walk", n)
base.Fatalf("walkexpr: switch 1 unknown op %+v", n.Op())
+ panic("unreachable")
case ir.ONONAME, ir.OGETG, ir.ONEWOBJ, ir.OMETHEXPR:
+ return n
case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL:
// TODO(mdempsky): Just return n; see discussion on CL 38655.
// Perhaps refactor to use Node.mayBeShared for these instead.
// If these return early, make sure to still call
// stringsym for constant strings.
+ return n
case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.ODOTMETH, ir.ODOTINTER,
ir.ODEREF, ir.OSPTR, ir.OITAB, ir.OIDATA, ir.OADDR:
n.SetLeft(walkexpr(n.Left(), init))
+ return n
case ir.OEFACE, ir.OAND, ir.OANDNOT, ir.OSUB, ir.OMUL, ir.OADD, ir.OOR, ir.OXOR, ir.OLSH, ir.ORSH:
n.SetLeft(walkexpr(n.Left(), init))
n.SetRight(walkexpr(n.Right(), init))
+ return n
case ir.ODOT, ir.ODOTPTR:
usefield(n)
n.SetLeft(walkexpr(n.Left(), init))
+ return n
case ir.ODOTTYPE, ir.ODOTTYPE2:
n.SetLeft(walkexpr(n.Left(), init))
if !n.Type().IsInterface() && !n.Left().Type().IsEmptyInterface() {
n.PtrList().Set1(itabname(n.Type(), n.Left().Type()))
}
+ return n
case ir.OLEN, ir.OCAP:
if isRuneCount(n) {
// Replace len([]rune(string)) with runtime.countrunes(string).
- n = mkcall("countrunes", n.Type(), init, conv(n.Left().Left(), types.Types[types.TSTRING]))
- break
+ return mkcall("countrunes", n.Type(), init, conv(n.Left().Left(), types.Types[types.TSTRING]))
}
n.SetLeft(walkexpr(n.Left(), init))
n = origIntConst(n, t.NumElem())
n.SetTypecheck(1)
}
+ return n
case ir.OCOMPLEX:
// Use results from call expression as arguments for complex.
}
n.SetLeft(walkexpr(n.Left(), init))
n.SetRight(walkexpr(n.Right(), init))
+ return n
case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
- n = walkcompare(n, init)
+ return walkcompare(n, init)
case ir.OANDAND, ir.OOROR:
n.SetLeft(walkexpr(n.Left(), init))
n.SetRight(walkexpr(n.Right(), &ll))
n.SetRight(initExpr(ll.Slice(), n.Right()))
+ return n
case ir.OPRINT, ir.OPRINTN:
- n = walkprint(n, init)
+ return walkprint(n, init)
case ir.OPANIC:
- n = mkcall("gopanic", nil, init, n.Left())
+ return mkcall("gopanic", nil, init, n.Left())
case ir.ORECOVER:
- n = mkcall("gorecover", n.Type(), init, ir.Nod(ir.OADDR, nodfp, nil))
+ return mkcall("gorecover", n.Type(), init, ir.Nod(ir.OADDR, nodfp, nil))
case ir.OCLOSUREREAD, ir.OCFUNC:
+ return n
case ir.OCALLINTER, ir.OCALLFUNC, ir.OCALLMETH:
if n.Op() == ir.OCALLINTER {
}
walkCall(n, init)
+ return n
case ir.OAS, ir.OASOP:
init.AppendNodes(n.PtrInit())
}
if oaslit(n, init) {
- n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
- break
+ return ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
}
if n.Right() == nil {
// TODO(austin): Check all "implicit zeroing"
- break
+ return n
}
if !instrumenting && isZero(n.Right()) {
- break
+ return n
}
switch n.Right().Op() {
n1 := ir.Nod(ir.OADDR, n.Left(), nil)
r := n.Right().Left() // the channel
- n = mkcall1(chanfn("chanrecv1", 2, r.Type()), nil, init, r, n1)
- n = walkexpr(n, init)
- break opswitch
+ return mkcall1(chanfn("chanrecv1", 2, r.Type()), nil, init, r, n1)
case ir.OAPPEND:
// x = append(...)
// Do not add a new write barrier.
// Set up address of type for back end.
r.SetLeft(typename(r.Type().Elem()))
- break opswitch
+ return n
}
// Otherwise, lowered for race detector.
// Treat as ordinary assignment.
if n.Left() != nil && n.Right() != nil {
n = convas(n, init)
}
+ return n
case ir.OAS2:
init.AppendNodes(n.PtrInit())
walkexprlistsafe(n.Rlist().Slice(), init)
ll := ascompatee(ir.OAS, n.List().Slice(), n.Rlist().Slice(), init)
ll = reorder3(ll)
- n = liststmt(ll)
+ return liststmt(ll)
// a,b,... = fn()
case ir.OAS2FUNC:
if isIntrinsicCall(r) {
n.PtrRlist().Set1(r)
- break
+ return n
}
init.Append(r)
ll := ascompatet(n.List(), r.Type())
- n = liststmt(ll)
+ return liststmt(ll)
// x, y = <-c
// order.stmt made sure x is addressable or blank.
ok := n.List().Second()
call := mkcall1(fn, types.Types[types.TBOOL], init, r.Left(), n1)
n = ir.Nod(ir.OAS, ok, call)
- n = typecheck(n, ctxStmt)
+ return typecheck(n, ctxStmt)
// a,b = m[i]
case ir.OAS2MAPR:
}
n = typecheck(n, ctxStmt)
- n = walkexpr(n, init)
+ return walkexpr(n, init)
case ir.ODELETE:
init.AppendNodes(n.PtrInit())
// order.stmt made sure key is addressable.
key = ir.Nod(ir.OADDR, key, nil)
}
- n = mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
+ return mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
case ir.OAS2DOTTYPE:
walkexprlistsafe(n.List().Slice(), init)
n.PtrRlist().SetIndex(0, walkexpr(n.Rlist().First(), init))
+ return n
case ir.OCONVIFACE:
n.SetLeft(walkexpr(n.Left(), init))
l := ir.Nod(ir.OEFACE, typeword(), n.Left())
l.SetType(toType)
l.SetTypecheck(n.Typecheck())
- n = l
- break
+ return l
}
if staticuint64s == nil {
l := ir.Nod(ir.OEFACE, typeword(), typecheck(ir.Nod(ir.OADDR, value, nil), ctxExpr))
l.SetType(toType)
l.SetTypecheck(n.Typecheck())
- n = l
- break
+ return l
}
// Implement interface to empty interface conversion.
e := ir.Nod(ir.OEFACE, tmp, ifaceData(n.Pos(), c, types.NewPtr(types.Types[types.TUINT8])))
e.SetType(toType) // assign type manually, typecheck doesn't understand OEFACE.
e.SetTypecheck(1)
- n = e
- break
+ return e
}
fnname, needsaddr := convFuncName(fromType, toType)
e := ir.Nod(ir.OEFACE, typeword(), call)
e.SetType(toType)
e.SetTypecheck(1)
- n = e
- break
+ return e
}
var tab ir.Node
n = ir.Nod(ir.OCALL, fn, nil)
n.PtrList().Set2(tab, v)
n = typecheck(n, ctxExpr)
- n = walkexpr(n, init)
+ return walkexpr(n, init)
case ir.OCONV, ir.OCONVNOP:
n.SetLeft(walkexpr(n.Left(), init))
}
if n.Op() == ir.OCONVNOP && checkPtr(Curfn, 1) {
if n.Type().IsPtr() && n.Left().Type().IsUnsafePtr() { // unsafe.Pointer to *T
- n = walkCheckPtrAlignment(n, init, nil)
- break
+ return walkCheckPtrAlignment(n, init, nil)
}
if n.Type().IsUnsafePtr() && n.Left().Type().IsUintptr() { // uintptr to unsafe.Pointer
- n = walkCheckPtrArithmetic(n, init)
- break
+ return walkCheckPtrArithmetic(n, init)
}
}
param, result := rtconvfn(n.Left().Type(), n.Type())
if param == types.Txxx {
- break
+ return n
}
fn := types.BasicTypeNames[param] + "to" + types.BasicTypeNames[result]
- n = conv(mkcall(fn, types.Types[result], init, conv(n.Left(), types.Types[param])), n.Type())
+ return conv(mkcall(fn, types.Types[result], init, conv(n.Left(), types.Types[param])), n.Type())
case ir.ODIV, ir.OMOD:
n.SetLeft(walkexpr(n.Left(), init))
if isComplex[et] && n.Op() == ir.ODIV {
t := n.Type()
n = mkcall("complex128div", types.Types[types.TCOMPLEX128], init, conv(n.Left(), types.Types[types.TCOMPLEX128]), conv(n.Right(), types.Types[types.TCOMPLEX128]))
- n = conv(n, t)
- break
+ return conv(n, t)
}
// Nothing to do for float divisions.
if isFloat[et] {
- break
+ return n
}
// rewrite 64-bit div and mod on 32-bit architectures.
c = -c
}
if c != 0 && c&(c-1) == 0 {
- break opswitch
+ return n
}
case types.TUINT64:
c := ir.Uint64Val(n.Right())
if c < 1<<16 {
- break opswitch
+ return n
}
if c != 0 && c&(c-1) == 0 {
- break opswitch
+ return n
}
}
}
} else {
fn += "mod"
}
- n = mkcall(fn, n.Type(), init, conv(n.Left(), types.Types[et]), conv(n.Right(), types.Types[et]))
+ return mkcall(fn, n.Type(), init, conv(n.Left(), types.Types[et]), conv(n.Right(), types.Types[et]))
}
+ return n
case ir.OINDEX:
n.SetLeft(walkexpr(n.Left(), init))
// if range of type cannot exceed static array bound,
// disable bounds check.
if n.Bounded() {
- break
+ return n
}
t := n.Left().Type()
if t != nil && t.IsPtr() {
base.Errorf("index out of bounds")
}
}
+ return n
case ir.OINDEXMAP:
// Replace m[k] with *map{access1,assign}(maptype, m, &k)
n = ir.Nod(ir.ODEREF, n, nil)
n.SetType(t.Elem())
n.SetTypecheck(1)
+ return n
case ir.ORECV:
base.Fatalf("walkexpr ORECV") // should see inside OAS only
+ panic("unreachable")
case ir.OSLICEHEADER:
n.SetLeft(walkexpr(n.Left(), init))
n.List().SetFirst(walkexpr(n.List().First(), init))
n.List().SetSecond(walkexpr(n.List().Second(), init))
+ return n
case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
checkSlice := checkPtr(Curfn, 1) && n.Op() == ir.OSLICE3ARR && n.Left().Op() == ir.OCONVNOP && n.Left().Left().Type().IsUnsafePtr()
} else {
n.SetOp(ir.OSLICEARR)
}
- n = reduceSlice(n)
+ return reduceSlice(n)
}
- } else {
- n = reduceSlice(n)
+ return n
}
+ return reduceSlice(n)
case ir.ONEW:
if n.Type().Elem().NotInHeap() {
r = typecheck(r, ctxStmt)
init.Append(r)
r = ir.Nod(ir.OADDR, r.Left(), nil)
- r = typecheck(r, ctxExpr)
- n = r
- } else {
- n = callnew(n.Type().Elem())
+ return typecheck(r, ctxExpr)
}
+ return callnew(n.Type().Elem())
case ir.OADDSTR:
- n = addstr(n, init)
+ return addstr(n, init)
case ir.OAPPEND:
// order should make sure we only see OAS(node, OAPPEND), which we handle above.
base.Fatalf("append outside assignment")
+ panic("unreachable")
case ir.OCOPY:
- n = copyany(n, init, instrumenting && !base.Flag.CompilingRuntime)
+ return copyany(n, init, instrumenting && !base.Flag.CompilingRuntime)
- // cannot use chanfn - closechan takes any, not chan any
case ir.OCLOSE:
+ // cannot use chanfn - closechan takes any, not chan any
fn := syslook("closechan")
-
fn = substArgTypes(fn, n.Left().Type())
- n = mkcall1(fn, nil, init, n.Left())
+ return mkcall1(fn, nil, init, n.Left())
case ir.OMAKECHAN:
// When size fits into int, use makechan instead of
argtype = types.Types[types.TINT]
}
- n = mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), conv(size, argtype))
+ return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), conv(size, argtype))
case ir.OMAKEMAP:
t := n.Type()
a = typecheck(a, ctxStmt)
a = walkexpr(a, init)
init.Append(a)
- n = convnop(h, t)
- } else {
- // Call runtime.makehmap to allocate an
- // hmap on the heap and initialize hmap's hash0 field.
- fn := syslook("makemap_small")
- fn = substArgTypes(fn, t.Key(), t.Elem())
- n = mkcall1(fn, n.Type(), init)
- }
- } else {
- if n.Esc() != EscNone {
- h = nodnil()
- }
- // Map initialization with a variable or large hint is
- // more complicated. We therefore generate a call to
- // runtime.makemap to initialize hmap and allocate the
- // map buckets.
-
- // When hint fits into int, use makemap instead of
- // makemap64, which is faster and shorter on 32 bit platforms.
- fnname := "makemap64"
- argtype := types.Types[types.TINT64]
-
- // Type checking guarantees that TIDEAL hint is positive and fits in an int.
- // See checkmake call in TMAP case of OMAKE case in OpSwitch in typecheck1 function.
- // The case of hint overflow when converting TUINT or TUINTPTR to TINT
- // will be handled by the negative range checks in makemap during runtime.
- if hint.Type().IsKind(types.TIDEAL) || hint.Type().Size() <= types.Types[types.TUINT].Size() {
- fnname = "makemap"
- argtype = types.Types[types.TINT]
+ return convnop(h, t)
}
+ // Call runtime.makehmap to allocate an
+ // hmap on the heap and initialize hmap's hash0 field.
+ fn := syslook("makemap_small")
+ fn = substArgTypes(fn, t.Key(), t.Elem())
+ return mkcall1(fn, n.Type(), init)
+ }
- fn := syslook(fnname)
- fn = substArgTypes(fn, hmapType, t.Key(), t.Elem())
- n = mkcall1(fn, n.Type(), init, typename(n.Type()), conv(hint, argtype), h)
+ if n.Esc() != EscNone {
+ h = nodnil()
+ }
+ // Map initialization with a variable or large hint is
+ // more complicated. We therefore generate a call to
+ // runtime.makemap to initialize hmap and allocate the
+ // map buckets.
+
+ // When hint fits into int, use makemap instead of
+ // makemap64, which is faster and shorter on 32 bit platforms.
+ fnname := "makemap64"
+ argtype := types.Types[types.TINT64]
+
+ // Type checking guarantees that TIDEAL hint is positive and fits in an int.
+ // See checkmake call in TMAP case of OMAKE case in OpSwitch in typecheck1 function.
+ // The case of hint overflow when converting TUINT or TUINTPTR to TINT
+ // will be handled by the negative range checks in makemap during runtime.
+ if hint.Type().IsKind(types.TIDEAL) || hint.Type().Size() <= types.Types[types.TUINT].Size() {
+ fnname = "makemap"
+ argtype = types.Types[types.TINT]
}
+ fn := syslook(fnname)
+ fn = substArgTypes(fn, hmapType, t.Key(), t.Elem())
+ return mkcall1(fn, n.Type(), init, typename(n.Type()), conv(hint, argtype), h)
+
case ir.OMAKESLICE:
l := n.Left()
r := n.Right()
r = conv(r, n.Type()) // in case n.Type is named.
r = typecheck(r, ctxExpr)
r = walkexpr(r, init)
- n = r
- } else {
- // n escapes; set up a call to makeslice.
- // When len and cap can fit into int, use makeslice instead of
- // makeslice64, which is faster and shorter on 32 bit platforms.
-
- len, cap := l, r
-
- fnname := "makeslice64"
- argtype := types.Types[types.TINT64]
-
- // Type checking guarantees that TIDEAL len/cap are positive and fit in an int.
- // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
- // will be handled by the negative range checks in makeslice during runtime.
- if (len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size()) &&
- (cap.Type().IsKind(types.TIDEAL) || cap.Type().Size() <= types.Types[types.TUINT].Size()) {
- fnname = "makeslice"
- argtype = types.Types[types.TINT]
- }
+ return r
+ }
- m := ir.Nod(ir.OSLICEHEADER, nil, nil)
- m.SetType(t)
+ // n escapes; set up a call to makeslice.
+ // When len and cap can fit into int, use makeslice instead of
+ // makeslice64, which is faster and shorter on 32 bit platforms.
- fn := syslook(fnname)
- m.SetLeft(mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype)))
- m.Left().MarkNonNil()
- m.PtrList().Set2(conv(len, types.Types[types.TINT]), conv(cap, types.Types[types.TINT]))
+ len, cap := l, r
+
+ fnname := "makeslice64"
+ argtype := types.Types[types.TINT64]
- m = typecheck(m, ctxExpr)
- m = walkexpr(m, init)
- n = m
+ // Type checking guarantees that TIDEAL len/cap are positive and fit in an int.
+ // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
+ // will be handled by the negative range checks in makeslice during runtime.
+ if (len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size()) &&
+ (cap.Type().IsKind(types.TIDEAL) || cap.Type().Size() <= types.Types[types.TUINT].Size()) {
+ fnname = "makeslice"
+ argtype = types.Types[types.TINT]
}
+ m := ir.Nod(ir.OSLICEHEADER, nil, nil)
+ m.SetType(t)
+
+ fn := syslook(fnname)
+ m.SetLeft(mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype)))
+ m.Left().MarkNonNil()
+ m.PtrList().Set2(conv(len, types.Types[types.TINT]), conv(cap, types.Types[types.TINT]))
+
+ m = typecheck(m, ctxExpr)
+ m = walkexpr(m, init)
+ return m
+
case ir.OMAKESLICECOPY:
if n.Esc() == EscNone {
base.Fatalf("OMAKESLICECOPY with EscNone: %v", n)
ncopy = walkexpr(ncopy, init)
init.Append(ncopy)
- n = s
- } else { // Replace make+copy with runtime.makeslicecopy.
- // instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
- fn := syslook("makeslicecopy")
- s := ir.Nod(ir.OSLICEHEADER, nil, nil)
- s.SetLeft(mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[types.TUNSAFEPTR])))
- s.Left().MarkNonNil()
- s.PtrList().Set2(length, length)
- s.SetType(t)
- n = typecheck(s, ctxExpr)
- n = walkexpr(n, init)
+ return s
}
+ // Replace make+copy with runtime.makeslicecopy.
+ // instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
+ fn := syslook("makeslicecopy")
+ s := ir.Nod(ir.OSLICEHEADER, nil, nil)
+ s.SetLeft(mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[types.TUNSAFEPTR])))
+ s.Left().MarkNonNil()
+ s.PtrList().Set2(length, length)
+ s.SetType(t)
+ n = typecheck(s, ctxExpr)
+ return walkexpr(n, init)
case ir.ORUNESTR:
a := nodnil()
a = ir.Nod(ir.OADDR, temp(t), nil)
}
// intstring(*[4]byte, rune)
- n = mkcall("intstring", n.Type(), init, a, conv(n.Left(), types.Types[types.TINT64]))
+ return mkcall("intstring", n.Type(), init, a, conv(n.Left(), types.Types[types.TINT64]))
case ir.OBYTES2STR, ir.ORUNES2STR:
a := nodnil()
}
if n.Op() == ir.ORUNES2STR {
// slicerunetostring(*[32]byte, []rune) string
- n = mkcall("slicerunetostring", n.Type(), init, a, n.Left())
- } else {
- // slicebytetostring(*[32]byte, ptr *byte, n int) string
- n.SetLeft(cheapexpr(n.Left(), init))
- ptr, len := backingArrayPtrLen(n.Left())
- n = mkcall("slicebytetostring", n.Type(), init, a, ptr, len)
+ return mkcall("slicerunetostring", n.Type(), init, a, n.Left())
}
+ // slicebytetostring(*[32]byte, ptr *byte, n int) string
+ n.SetLeft(cheapexpr(n.Left(), init))
+ ptr, len := backingArrayPtrLen(n.Left())
+ return mkcall("slicebytetostring", n.Type(), init, a, ptr, len)
case ir.OBYTES2STRTMP:
n.SetLeft(walkexpr(n.Left(), init))
if !instrumenting {
// Let the backend handle OBYTES2STRTMP directly
// to avoid a function call to slicebytetostringtmp.
- break
+ return n
}
// slicebytetostringtmp(ptr *byte, n int) string
n.SetLeft(cheapexpr(n.Left(), init))
ptr, len := backingArrayPtrLen(n.Left())
- n = mkcall("slicebytetostringtmp", n.Type(), init, ptr, len)
+ return mkcall("slicebytetostringtmp", n.Type(), init, ptr, len)
case ir.OSTR2BYTES:
s := n.Left()
slice := ir.NodAt(n.Pos(), ir.OSLICEARR, p, nil)
slice.SetType(n.Type())
slice.SetTypecheck(1)
- n = walkexpr(slice, init)
- break
+ return walkexpr(slice, init)
}
a := nodnil()
a = ir.Nod(ir.OADDR, temp(t), nil)
}
// stringtoslicebyte(*32[byte], string) []byte
- n = mkcall("stringtoslicebyte", n.Type(), init, a, conv(s, types.Types[types.TSTRING]))
+ return mkcall("stringtoslicebyte", n.Type(), init, a, conv(s, types.Types[types.TSTRING]))
case ir.OSTR2BYTESTMP:
// []byte(string) conversion that creates a slice
// The only such case today is:
// for i, c := range []byte(string)
n.SetLeft(walkexpr(n.Left(), init))
+ return n
case ir.OSTR2RUNES:
a := nodnil()
a = ir.Nod(ir.OADDR, temp(t), nil)
}
// stringtoslicerune(*[32]rune, string) []rune
- n = mkcall("stringtoslicerune", n.Type(), init, a, conv(n.Left(), types.Types[types.TSTRING]))
+ return mkcall("stringtoslicerune", n.Type(), init, a, conv(n.Left(), types.Types[types.TSTRING]))
case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT, ir.OPTRLIT:
if isStaticCompositeLiteral(n) && !canSSAType(n.Type()) {
// Make direct reference to the static data. See issue 12841.
vstat := readonlystaticname(n.Type())
fixedlit(inInitFunction, initKindStatic, n, vstat, init)
- n = vstat
- n = typecheck(n, ctxExpr)
- break
+ return typecheck(vstat, ctxExpr)
}
var_ := temp(n.Type())
anylit(n, var_, init)
- n = var_
+ return var_
case ir.OSEND:
n1 := n.Right()
n1 = assignconv(n1, n.Left().Type().Elem(), "chan send")
n1 = walkexpr(n1, init)
n1 = ir.Nod(ir.OADDR, n1, nil)
- n = mkcall1(chanfn("chansend1", 2, n.Left().Type()), nil, init, n.Left(), n1)
+ return mkcall1(chanfn("chansend1", 2, n.Left().Type()), nil, init, n.Left(), n1)
case ir.OCLOSURE:
- n = walkclosure(n, init)
+ return walkclosure(n, init)
case ir.OCALLPART:
- n = walkpartialcall(n.(*ir.CallPartExpr), init)
- }
-
- // Expressions that are constant at run time but not
- // considered const by the language spec are not turned into
- // constants until walk. For example, if n is y%1 == 0, the
- // walk of y%1 may have replaced it by 0.
- // Check whether n with its updated args is itself now a constant.
- t := n.Type()
- n = evalConst(n)
- if n.Type() != t {
- base.Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type())
- }
- if n.Op() == ir.OLITERAL {
- n = typecheck(n, ctxExpr)
- // Emit string symbol now to avoid emitting
- // any concurrently during the backend.
- if v := n.Val(); v.Kind() == constant.String {
- _ = stringsym(n.Pos(), constant.StringVal(v))
- }
- }
-
- updateHasCall(n)
-
- if base.Flag.LowerW != 0 && n != nil {
- ir.Dump("after walk expr", n)
+ return walkpartialcall(n.(*ir.CallPartExpr), init)
}
- base.Pos = lno
- return n
+ // No return! Each case must return (or panic),
+ // to avoid confusion about what gets returned
+ // in the presence of type assertions.
}
// markTypeUsedInInterface marks that type t is converted to an interface.