p.pos(n)
p.stmtList(n.Ninit)
p.expr(n.Left)
- nbody := n.Nbody
- rlist := n.Rlist
- if Isconst(n.Left, CTBOOL) {
- // if false { ... } or if true { ... }
- // Only export the taken branch.
- // This is more efficient,
- // and avoids trying to export
- // un-exportable nodes.
- if n.Left.Bool() {
- rlist = Nodes{}
- } else {
- nbody = Nodes{}
- }
- }
- p.stmtList(nbody)
- p.stmtList(rlist)
+ p.stmtList(n.Nbody)
+ p.stmtList(n.Rlist)
case OFOR:
p.op(OFOR)
e.escassignSinkWhy(n, n, "too large for stack") // TODO category: tooLarge
}
- if n.Op == OIF && Isconst(n.Left, CTBOOL) {
- // Don't examine dead code.
- if n.Left.Bool() {
- e.esclist(n.Nbody, n)
- } else {
- e.esclist(n.Rlist, n)
- }
- } else {
- e.esc(n.Left, n)
- e.esc(n.Right, n)
- e.esclist(n.Nbody, n)
- e.esclist(n.List, n)
- e.esclist(n.Rlist, n)
- }
+ e.esc(n.Left, n)
+ e.esc(n.Right, n)
+ e.esclist(n.Nbody, n)
+ e.esclist(n.List, n)
+ e.esclist(n.Rlist, n)
if n.Op == OFOR || n.Op == OFORUNTIL || n.Op == ORANGE {
e.loopdepth--
return true
}
- if n.Op == OIF && Isconst(n.Left, CTBOOL) {
- var taken Nodes // statements for the branch that is always taken
- if n.Left.Bool() {
- taken = n.Nbody // then case
- } else {
- taken = n.Rlist // else case
- }
- return ishairylist(n.Ninit, budget, reason) || ishairylist(taken, budget, reason)
- }
-
return ishairy(n.Left, budget, reason) || ishairy(n.Right, budget, reason) ||
ishairylist(n.List, budget, reason) || ishairylist(n.Rlist, budget, reason) ||
ishairylist(n.Ninit, budget, reason) || ishairylist(n.Nbody, budget, reason)
if nerrors != 0 {
Curfn.Nbody.Set(nil) // type errors; do not compile
}
+ // Now that we've checked whether n terminates,
+ // we can eliminate some obviously dead code.
+ deadcode(Curfn)
fcount++
}
}
lab.SetHasBreak(true)
}
}
-
- case OFOR,
- OFORUNTIL,
- OSWITCH,
- OTYPESW,
- OSELECT,
- ORANGE:
+ case OFOR, OFORUNTIL, OSWITCH, OTYPESW, OSELECT, ORANGE:
implicit = n
fallthrough
default:
}
}
-// Isterminating whether the Nodes list ends with a terminating
-// statement.
+// isterminating reports whether the Nodes list ends with a terminating statement.
func (l Nodes) isterminating() bool {
s := l.Slice()
c := len(s)
return s[c-1].isterminating()
}
-// Isterminating returns whether the node n, the last one in a
+// Isterminating reports whether the node n, the last one in a
// statement list, is a terminating statement.
func (n *Node) isterminating() bool {
switch n.Op {
case OBLOCK:
return n.List.isterminating()
- case OGOTO,
- ORETURN,
- ORETJMP,
- OPANIC,
- OXFALL:
+ case OGOTO, ORETURN, ORETJMP, OPANIC, OXFALL:
return true
case OFOR, OFORUNTIL:
return false
}
+// checkreturn makes sure that fn terminates appropriately.
func checkreturn(fn *Node) {
if fn.Type.Results().NumFields() != 0 && fn.Nbody.Len() != 0 {
markbreaklist(fn.Nbody, nil)
}
}
}
+
+func deadcode(fn *Node) {
+ deadcodeslice(fn.Nbody)
+}
+
+func deadcodeslice(nn Nodes) {
+ for _, n := range nn.Slice() {
+ if n == nil {
+ continue
+ }
+ if n.Op == OIF && Isconst(n.Left, CTBOOL) {
+ var dead *Nodes
+ if n.Left.Bool() {
+ dead = &n.Rlist
+ } else {
+ dead = &n.Nbody
+ }
+ // TODO(mdempsky/josharian): eliminate need for haslabelgoto
+ // by checking labels and gotos earlier. See issue 19699.
+ if !(*dead).haslabelgoto() {
+ *dead = Nodes{}
+ }
+ }
+ deadcodeslice(n.Ninit)
+ deadcodeslice(n.Nbody)
+ deadcodeslice(n.List)
+ deadcodeslice(n.Rlist)
+ }
+}
+
+// haslabelgoto reports whether the Nodes list contains any label or goto statements.
+func (l Nodes) haslabelgoto() bool {
+ for _, n := range l.Slice() {
+ if n == nil {
+ continue
+ }
+ if n.Op == OLABEL || n.Op == OGOTO {
+ return true
+ }
+ if n.Ninit.haslabelgoto() || n.Nbody.haslabelgoto() || n.List.haslabelgoto() || n.Rlist.haslabelgoto() {
+ return true
+ }
+ }
+ return false
+}
--- /dev/null
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+func F() {
+l1:
+ if false {
+ goto l1
+ }
+}
--- /dev/null
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ a.F()
+}
--- /dev/null
+// compiledir
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ignored
--- /dev/null
+// errorcheck
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f() bool {
+ if false {
+ } else {
+ return true
+ }
+} // ERROR "missing return at end of function"
--- /dev/null
+// compile
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f1() {
+ f2()
+}
+
+func f2() {
+ if false {
+ _ = func() {}
+ }
+}