aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/deadcode/deadcode.go13
-rw-r--r--src/cmd/compile/internal/gc/main.go4
-rw-r--r--src/cmd/compile/internal/ir/func.go3
-rw-r--r--test/fixedbugs/issue47712.go23
4 files changed, 43 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/deadcode/deadcode.go b/src/cmd/compile/internal/deadcode/deadcode.go
index 520203787f..3658c89912 100644
--- a/src/cmd/compile/internal/deadcode/deadcode.go
+++ b/src/cmd/compile/internal/deadcode/deadcode.go
@@ -38,6 +38,7 @@ func Func(fn *ir.Func) {
}
}
+ ir.VisitList(fn.Body, markHiddenClosureDead)
fn.Body = []ir.Node{ir.NewBlockStmt(base.Pos, nil)}
}
@@ -62,9 +63,11 @@ func stmts(nn *ir.Nodes) {
if ir.IsConst(n.Cond, constant.Bool) {
var body ir.Nodes
if ir.BoolVal(n.Cond) {
+ ir.VisitList(n.Else, markHiddenClosureDead)
n.Else = ir.Nodes{}
body = n.Body
} else {
+ ir.VisitList(n.Body, markHiddenClosureDead)
n.Body = ir.Nodes{}
body = n.Else
}
@@ -150,3 +153,13 @@ func expr(n ir.Node) ir.Node {
}
return n
}
+
+func markHiddenClosureDead(n ir.Node) {
+ if n.Op() != ir.OCLOSURE {
+ return
+ }
+ clo := n.(*ir.ClosureExpr)
+ if clo.Func.IsHiddenClosure() {
+ clo.Func.SetIsDeadcodeClosure(true)
+ }
+}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 6a373ce33d..9660ef9dd5 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -289,6 +289,10 @@ func Main(archInit func(*ssagen.ArchInfo)) {
fcount := int64(0)
for i := 0; i < len(typecheck.Target.Decls); i++ {
if fn, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
+ // Don't try compiling dead hidden closure.
+ if fn.IsDeadcodeClosure() {
+ continue
+ }
enqueueFunc(fn)
fcount++
}
diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go
index 269b6f14ec..18d0b023ad 100644
--- a/src/cmd/compile/internal/ir/func.go
+++ b/src/cmd/compile/internal/ir/func.go
@@ -196,6 +196,7 @@ const (
// true if closure inside a function; false if a simple function or a
// closure in a global variable initialization
funcIsHiddenClosure
+ funcIsDeadcodeClosure // true if closure is deadcode
funcHasDefer // contains a defer statement
funcNilCheckDisabled // disable nil checks when compiling this function
funcInlinabilityChecked // inliner has already determined whether the function is inlinable
@@ -216,6 +217,7 @@ func (f *Func) ABIWrapper() bool { return f.flags&funcABIWrapper !
func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 }
func (f *Func) ReflectMethod() bool { return f.flags&funcReflectMethod != 0 }
func (f *Func) IsHiddenClosure() bool { return f.flags&funcIsHiddenClosure != 0 }
+func (f *Func) IsDeadcodeClosure() bool { return f.flags&funcIsDeadcodeClosure != 0 }
func (f *Func) HasDefer() bool { return f.flags&funcHasDefer != 0 }
func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 }
func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 }
@@ -230,6 +232,7 @@ func (f *Func) SetABIWrapper(b bool) { f.flags.set(funcABIWrapper,
func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) }
func (f *Func) SetReflectMethod(b bool) { f.flags.set(funcReflectMethod, b) }
func (f *Func) SetIsHiddenClosure(b bool) { f.flags.set(funcIsHiddenClosure, b) }
+func (f *Func) SetIsDeadcodeClosure(b bool) { f.flags.set(funcIsDeadcodeClosure, b) }
func (f *Func) SetHasDefer(b bool) { f.flags.set(funcHasDefer, b) }
func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) }
func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) }
diff --git a/test/fixedbugs/issue47712.go b/test/fixedbugs/issue47712.go
new file mode 100644
index 0000000000..81a2681592
--- /dev/null
+++ b/test/fixedbugs/issue47712.go
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2021 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() {
+ if false {
+ defer func() {
+ _ = recover()
+ }()
+ }
+}
+
+func g() {
+ for false {
+ defer func() {
+ _ = recover()
+ }()
+ }
+}