typecheck.AssertFixedCall(n)
- inlIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
+ inlIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym, ir.FuncName(fn))
closureInitLSym := func(n *ir.CallExpr, fn *ir.Func) {
// The linker needs FuncInfo metadata for all inlined
"cmd/internal/objabi"
"cmd/internal/src"
"fmt"
+ "strings"
)
// A Func corresponds to a single function in a Go program
// globClosgen is like Func.Closgen, but for the global scope.
var globClosgen int32
-// closureName generates a new unique name for a closure within outerfn.
-func closureName(outerfn *Func) *types.Sym {
+// closureName generates a new unique name for a closure within outerfn at pos.
+func closureName(outerfn *Func, pos src.XPos) *types.Sym {
pkg := types.LocalPkg
outer := "glob."
prefix := "func"
}
}
+ // If this closure was created due to inlining, then incorporate any
+ // inlined functions' names into the closure's linker symbol name
+ // too (#60324).
+ if inlIndex := base.Ctxt.InnermostPos(pos).Base().InliningIndex(); inlIndex >= 0 {
+ names := []string{outer}
+ base.Ctxt.InlTree.AllParents(inlIndex, func(call obj.InlinedCall) {
+ names = append(names, call.Name)
+ })
+ outer = strings.Join(names, ".")
+ }
+
*gen++
return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
}
base.FatalfAt(clo.Pos(), "closure already named: %v", name)
}
- name.SetSym(closureName(outerfn))
+ name.SetSym(closureName(outerfn, clo.Pos()))
MarkFunc(name)
}
Parent int // index of the parent in the InlTree or < 0 if outermost call
Pos src.XPos // position of the inlined call
Func *LSym // function that was inlined
+ Name string // bare name of the function (w/o package prefix)
ParentPC int32 // PC of instruction just before inlined body. Only valid in local trees.
}
// Add adds a new call to the tree, returning its index.
-func (tree *InlTree) Add(parent int, pos src.XPos, func_ *LSym) int {
+func (tree *InlTree) Add(parent int, pos src.XPos, func_ *LSym, name string) int {
r := len(tree.nodes)
call := InlinedCall{
Parent: parent,
Pos: pos,
Func: func_,
+ Name: name,
}
tree.nodes = append(tree.nodes, call)
return r
}
+// AllParents invokes do on each InlinedCall in the inlining call
+// stack, from outermost to innermost.
+//
+// That is, if inlIndex corresponds to f inlining g inlining h,
+// AllParents invokes do with the call for inlining g into f, and then
+// inlining h into g.
+func (tree *InlTree) AllParents(inlIndex int, do func(InlinedCall)) {
+ if inlIndex >= 0 {
+ call := tree.nodes[inlIndex]
+ tree.AllParents(call.Parent, do)
+ do(call)
+ }
+}
+
func (tree *InlTree) Parent(inlIndex int) int {
return tree.nodes[inlIndex].Parent
}
// AllPos invokes do with the position in f, then the position in g, then the position in h.
func (ctxt *Link) AllPos(xpos src.XPos, do func(src.Pos)) {
pos := ctxt.InnermostPos(xpos)
- ctxt.forAllPos(pos.Base().InliningIndex(), do)
- do(ctxt.PosTable.Pos(xpos))
-}
-
-func (ctxt *Link) forAllPos(ix int, do func(src.Pos)) {
- if ix >= 0 {
- call := ctxt.InlTree.nodes[ix]
- ctxt.forAllPos(call.Parent, do)
- do(ctxt.PosTable.Pos(call.Pos))
- }
+ ctxt.InlTree.AllParents(pos.Base().InliningIndex(), func(call InlinedCall) {
+ do(ctxt.InnermostPos(call.Pos))
+ })
+ do(pos)
}
func dumpInlTree(ctxt *Link, tree InlTree) {
{
x := 42
if z := func(y int) int { // ERROR "can inline main.func22"
- return func() int { // ERROR "can inline main.func22.1" "can inline main.func30"
+ return func() int { // ERROR "can inline main.func22.1" "can inline main.main.func22.func30"
return x + y
}() // ERROR "inlining call to main.func22.1"
- }(1); z != 43 { // ERROR "inlining call to main.func22" "inlining call to main.func30"
+ }(1); z != 43 { // ERROR "inlining call to main.func22" "inlining call to main.main.func22.func30"
ppanic("z != 43")
}
if z := func(y int) int { // ERROR "func literal does not escape" "can inline main.func23"
- return func() int { // ERROR "can inline main.func23.1" "can inline main.func31"
+ return func() int { // ERROR "can inline main.func23.1" "can inline main.main.func23.func31"
return x + y
}() // ERROR "inlining call to main.func23.1"
- }; z(1) != 43 { // ERROR "inlining call to main.func23" "inlining call to main.func31"
+ }; z(1) != 43 { // ERROR "inlining call to main.func23" "inlining call to main.main.func23.func31"
ppanic("z(1) != 43")
}
}
{
a := 1
func() { // ERROR "can inline main.func24"
- func() { // ERROR "can inline main.func24" "can inline main.func32"
+ func() { // ERROR "can inline main.func24" "can inline main.main.func24.func32"
a = 2
}() // ERROR "inlining call to main.func24"
- }() // ERROR "inlining call to main.func24" "inlining call to main.func32"
+ }() // ERROR "inlining call to main.func24" "inlining call to main.main.func24.func32"
if a != 2 {
ppanic("a != 2")
}
// revisit those. E.g., func34 and func36 are constructed by the inliner.
if r := func(x int) int { // ERROR "can inline main.func27"
b := 3
- return func(y int) int { // ERROR "can inline main.func27.1" "can inline main.func34"
+ return func(y int) int { // ERROR "can inline main.func27.1" "can inline main.main.func27.func34"
c := 5
- return func(z int) int { // ERROR "can inline main.func27.1.1" "can inline main.func27.(func)?2" "can inline main.func34.1" "can inline main.func36"
+ return func(z int) int { // ERROR "can inline main.func27.1.1" "can inline main.main.func27.func34.1" "can inline main.func27.main.func27.1.func2" "can inline main.main.func27.main.main.func27.func34.func36"
return a*x + b*y + c*z
}(10) // ERROR "inlining call to main.func27.1.1"
- }(100) // ERROR "inlining call to main.func27.1" "inlining call to main.func27.(func)?2"
- }(1000); r != 2350 { // ERROR "inlining call to main.func27" "inlining call to main.func34" "inlining call to main.func36"
+ }(100) // ERROR "inlining call to main.func27.1" "inlining call to main.func27.main.func27.1.func2"
+ }(1000); r != 2350 { // ERROR "inlining call to main.func27" "inlining call to main.main.func27.func34" "inlining call to main.main.func27.main.main.func27.func34.func36"
ppanic("r != 2350")
}
}
a := 2
if r := func(x int) int { // ERROR "can inline main.func28"
b := 3
- return func(y int) int { // ERROR "can inline main.func28.1" "can inline main.func35"
+ return func(y int) int { // ERROR "can inline main.func28.1" "can inline main.main.func28.func35"
c := 5
- func(z int) { // ERROR "can inline main.func28.1.1" "can inline main.func28.(func)?2" "can inline main.func35.1" "can inline main.func37"
+ func(z int) { // ERROR "can inline main.func28.1.1" "can inline main.func28.main.func28.1.func2" "can inline main.main.func28.func35.1" "can inline main.main.func28.main.main.func28.func35.func37"
a = a * x
b = b * y
c = c * z
}(10) // ERROR "inlining call to main.func28.1.1"
return a + c
- }(100) + b // ERROR "inlining call to main.func28.1" "inlining call to main.func28.(func)?2"
- }(1000); r != 2350 { // ERROR "inlining call to main.func28" "inlining call to main.func35" "inlining call to main.func37"
+ }(100) + b // ERROR "inlining call to main.func28.1" "inlining call to main.func28.main.func28.1.func2"
+ }(1000); r != 2350 { // ERROR "inlining call to main.func28" "inlining call to main.main.func28.func35" "inlining call to main.main.func28.main.main.func28.func35.func37"
ppanic("r != 2350")
}
if a != 2000 {
--- /dev/null
+// asmcheck
+
+// 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 codegen
+
+func main() {
+ // amd64:"LEAQ\tcommand-line-arguments\\.main\\.f\\.g\\.h\\.func3"
+ f(1)()
+
+ // amd64:"LEAQ\tcommand-line-arguments\\.main\\.g\\.h\\.func2"
+ g(2)()
+
+ // amd64:"LEAQ\tcommand-line-arguments\\.main\\.h\\.func1"
+ h(3)()
+
+ // amd64:"LEAQ\tcommand-line-arguments\\.main\\.f\\.g\\.h\\.func4"
+ f(4)()
+}
+
+func f(x int) func() {
+ // amd64:"LEAQ\tcommand-line-arguments\\.f\\.g\\.h\\.func1"
+ return g(x)
+}
+
+func g(x int) func() {
+ // amd64:"LEAQ\tcommand-line-arguments\\.g\\.h\\.func1"
+ return h(x)
+}
+
+func h(x int) func() {
+ // amd64:"LEAQ\tcommand-line-arguments\\.h\\.func1"
+ return func() { recover() }
+}
return x + z
}
bar := func(x int) int { // ERROR "func literal does not escape" "can inline r.func2"
- return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.func3"
+ return x + func(y int) int { // ERROR "can inline r.func2.1" "can inline r.r.func2.func3"
return 2*y + x*z
}(x) // ERROR "inlining call to r.func2.1"
}
- return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.func3"
+ return foo(42) + bar(42) // ERROR "inlining call to r.func1" "inlining call to r.func2" "inlining call to r.r.func2.func3"
}