diff --git a/src/cmd/compile/internal/ir/visit.go b/src/cmd/compile/internal/ir/visit.go index 016467081e..73ec1de544 100644 --- a/src/cmd/compile/internal/ir/visit.go +++ b/src/cmd/compile/internal/ir/visit.go @@ -115,6 +115,17 @@ func VisitList(list Nodes, visit func(Node)) { } } +// 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. diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 70f51e2253..610d02c07c 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -3919,7 +3919,11 @@ func finishWrapperFunc(fn *ir.Func, target *ir.Package) { // 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) } diff --git a/test/fixedbugs/issue60945.dir/a.go b/test/fixedbugs/issue60945.dir/a.go new file mode 100644 index 0000000000..663a0cfc69 --- /dev/null +++ b/test/fixedbugs/issue60945.dir/a.go @@ -0,0 +1,22 @@ +// 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) {} diff --git a/test/fixedbugs/issue60945.dir/b.go b/test/fixedbugs/issue60945.dir/b.go new file mode 100644 index 0000000000..e60d9dc7c1 --- /dev/null +++ b/test/fixedbugs/issue60945.dir/b.go @@ -0,0 +1,9 @@ +// 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 diff --git a/test/fixedbugs/issue60945.go b/test/fixedbugs/issue60945.go new file mode 100644 index 0000000000..5c4c5c0a8f --- /dev/null +++ b/test/fixedbugs/issue60945.go @@ -0,0 +1,7 @@ +// 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