}
func deadcodeslice(nn Nodes) {
- for _, n := range nn.Slice() {
+ for i, n := range nn.Slice() {
+ // Cut is set to true when all nodes after i'th position
+ // should be removed.
+ // In other words, it marks whole slice "tail" as dead.
+ cut := false
if n == nil {
continue
}
if n.Op == OIF {
n.Left = deadcodeexpr(n.Left)
if Isconst(n.Left, CTBOOL) {
+ var body Nodes
if n.Left.Bool() {
n.Rlist = Nodes{}
+ body = n.Nbody
} else {
n.Nbody = Nodes{}
+ body = n.Rlist
+ }
+ // If "then" or "else" branch ends with panic or return statement,
+ // it is safe to remove all statements after this node.
+ // isterminating is not used to avoid goto-related complications.
+ if body := body.Slice(); len(body) != 0 {
+ switch body[(len(body) - 1)].Op {
+ case ORETURN, ORETJMP, OPANIC:
+ cut = true
+ }
}
}
}
+
deadcodeslice(n.Ninit)
deadcodeslice(n.Nbody)
deadcodeslice(n.List)
deadcodeslice(n.Rlist)
+ if cut {
+ *nn.slice = nn.Slice()[:i+1]
+ break
+ }
}
}
--- /dev/null
+// errorcheck -0 -m
+
+// Copyright 2018 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.
+
+// Issue 23521: improve early DCE for if without explicit else.
+
+package p
+
+//go:noinline
+func nonleaf() {}
+
+const truth = true
+
+func f() int { // ERROR "can inline f"
+ if truth {
+ return 0
+ }
+ // If everything below is removed, as it should,
+ // function f should be inlineable.
+ nonleaf()
+ for {
+ panic("")
+ }
+}
+
+func g() int { // ERROR "can inline g"
+ return f() // ERROR "inlining call to f"
+}
+
+func f2() int { // ERROR "can inline f2"
+ if !truth {
+ nonleaf()
+ } else {
+ return 0
+ }
+ panic("")
+}
+
+func g2() int { // ERROR "can inline g2"
+ return f2() // ERROR "inlining call to f2"
+}