cmd/compile: use inline tree index to identify call stack

When building the name for closures, in order to make sure each
closure has a unique name, we attach a hash of the inline call
stack. We currently use a combination of function name, line
number, and column number at each level to construct the hash. In
some situations, this may not be able to uniquely identify the
call stack: there could be multiple inline call sites at the same
line of different files (we currently don't include the file name),
and XPos.ColumnNumber can saturate. This could lead to duplicate
symbol definitions. Instead of using name + line number + column
number, switch to use the global inline tree index, which should
uniquely identify the call site at each level.

Fixes #79274.

Change-Id: I69110a212d6b856283aae4c999258ae585be5977
Reviewed-on: https://go-review.googlesource.com/c/go/+/775624
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Cherry Mui 2026-05-08 16:44:45 -04:00
parent 55ff407d4f
commit ce4fc9417c
5 changed files with 48 additions and 3 deletions

View file

@ -13,7 +13,6 @@ import (
"cmd/internal/src"
"encoding/base64"
"fmt"
"io"
"unicode/utf8"
)
@ -472,9 +471,11 @@ func closureName(outerfn *Func, pos src.XPos, why Op, gen int) *types.Sym {
// we use a content hash to disambiguate instead.
// We choose the suffix as a hash of the inline call stack.
h := hash.New32()
io.WriteString(h, outer)
fmt.Fprint(h, inlIndex)
base.Ctxt.InlTree.AllParents(inlIndex, func(call obj.InlinedCall) {
io.WriteString(h, call.Name+":"+call.Pos.LineNumber()+":"+call.Pos.ColumnNumber())
if call.Parent >= 0 {
fmt.Fprint(h, " ", call.Parent)
}
})
inlHash = base64.StdEncoding.EncodeToString(h.Sum(nil)[:8])

View file

@ -0,0 +1,25 @@
// compile
// Copyright 2026 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 main
import "math/big"
func F() {
var pg0_0 *int
_ = pg0_0
var u16_0 uint16
fnc := func(a [0][][3]int, b [14][9]uint16, c []big.Int) uint16 {
pg0_0 = func() *int { return nil }()
return 0
}
fnc([0][][3]int{}, [14][9]uint16{[9]uint16{fnc([0][][3]int{}, [14][9]uint16{[9]uint16{min(fnc([0][][3]int{}, [14][9]uint16{[9]uint16{(uint16)(16), (uint16)(93), (uint16)(31)}, [9]uint16{(uint16)(5), (uint16)(69)}, [9]uint16{}}, []big.Int{}), u16_0), fnc([0][][3]int{}, [14][9]uint16{}, nil)}, [9]uint16{fnc([0][][3]int{}, [14][9]uint16{}, nil)}, [9]uint16{}}, nil), 0}}, nil)
}
func main() {
F()
}

View file

@ -0,0 +1,6 @@
// Copyright 2026 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
var _ = F(); func F() func() { return func() {} }

View file

@ -0,0 +1,6 @@
// Copyright 2026 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
var _ = F()

View file

@ -0,0 +1,7 @@
// compiledir
// Copyright 2026 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