}
}
+// VisitFuncAndClosures calls visit on each non-nil node in fn.Body,
+// including any nested closure bodies.
+func VisitFuncAndClosures(fn *Func, visit func(n Node)) {
+ VisitList(fn.Body, func(n Node) {
+ visit(n)
+ if n, ok := n.(*ClosureExpr); ok && n.Op() == OCLOSURE {
+ VisitFuncAndClosures(n.Func, visit)
+ }
+ })
+}
+
// Any looks for a non-nil node x in the IR tree rooted at n
// for which cond(x) returns true.
// Any considers nodes in a depth-first, preorder traversal.
// The body of wrapper function after inlining may reveal new ir.OMETHVALUE node,
// we don't know whether wrapper function has been generated for it or not, so
// generate one immediately here.
- ir.VisitList(fn.Body, func(n ir.Node) {
+ //
+ // Further, after CL 492017, function that construct closures is allowed to be inlined,
+ // even though the closure itself can't be inline. So we also need to visit body of any
+ // closure that we see when visiting body of the wrapper function.
+ ir.VisitFuncAndClosures(fn, func(n ir.Node) {
if n, ok := n.(*ir.SelectorExpr); ok && n.Op() == ir.OMETHVALUE {
wrapMethodValue(n.X.Type(), n.Selection, target, true)
}
--- /dev/null
+// Copyright 2023 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
+
+type S struct{}
+
+func callClosure(closure func()) {
+ closure()
+}
+
+func (s *S) M() {
+ callClosure(func() {
+ defer f(s.m) // prevent closures to be inlined.
+ })
+}
+
+func (s *S) m() {}
+
+//go:noinline
+func f(a ...any) {}
--- /dev/null
+// Copyright 2023 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 b
+
+import "./a"
+
+var _ = (&a.S{}).M
--- /dev/null
+// compiledir
+
+// Copyright 2023 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