Update to go1.24.2

This commit is contained in:
Vorapol Rinsatitnon
2025-04-02 07:37:39 +07:00
parent 33f3fba1e8
commit f665e748c7
40 changed files with 795 additions and 119 deletions

View File

@@ -42,6 +42,7 @@ import (
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/pgo"
"cmd/internal/src"
)
// Inlining budget parameters, gathered in one place
@@ -974,6 +975,16 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller, closureCal
return true, 0, metric, hot
}
// parsePos returns all the inlining positions and the innermost position.
func parsePos(pos src.XPos, posTmp []src.Pos) ([]src.Pos, src.Pos) {
ctxt := base.Ctxt
ctxt.AllPos(pos, func(p src.Pos) {
posTmp = append(posTmp, p)
})
l := len(posTmp) - 1
return posTmp[:l], posTmp[l]
}
// canInlineCallExpr returns true if the call n from caller to callee
// can be inlined, plus the score computed for the call expr in question,
// and whether the callee is hot according to PGO.
@@ -1001,6 +1012,17 @@ func canInlineCallExpr(callerfn *ir.Func, n *ir.CallExpr, callee *ir.Func, bigCa
return false, 0, false
}
callees, calleeInner := parsePos(n.Pos(), make([]src.Pos, 0, 10))
for _, p := range callees {
if p.Line() == calleeInner.Line() && p.Col() == calleeInner.Col() && p.AbsFilename() == calleeInner.AbsFilename() {
if log && logopt.Enabled() {
logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(callerfn)))
}
return false, 0, false
}
}
if callee == callerfn {
// Can't recursively inline a function into itself.
if log && logopt.Enabled() {

View File

@@ -253,7 +253,7 @@ func (s *inlClosureState) mark(n ir.Node) ir.Node {
if isTestingBLoop(n) {
// No inlining nor devirtualization performed on b.Loop body
if base.Flag.LowerM > 1 {
if base.Flag.LowerM > 0 {
fmt.Printf("%v: skip inlining within testing.B.loop for %v\n", ir.Line(n), n)
}
// We still want to explore inlining opportunities in other parts of ForStmt.

View File

@@ -230,6 +230,9 @@ func TestIntendedInlining(t *testing.T) {
"(*Pointer[go.shape.int]).Store",
"(*Pointer[go.shape.int]).Swap",
},
"testing": {
"(*B).Loop",
},
}
if !goexperiment.SwissMap {

View File

@@ -204,7 +204,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type {
// dot-imported variables.
if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
v = w
v_used = v.used
v_used = check.usedVars[v]
}
}
}
@@ -213,7 +213,7 @@ func (check *Checker) lhsVar(lhs syntax.Expr) Type {
check.expr(nil, &x, lhs)
if v != nil {
v.used = v_used // restore v.used
check.usedVars[v] = v_used // restore v.used
}
if x.mode == invalid || !isValid(x.typ) {

View File

@@ -687,7 +687,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
if pname, _ := obj.(*PkgName); pname != nil {
assert(pname.pkg == check.pkg)
check.recordUse(ident, pname)
pname.used = true
check.usedPkgNames[pname] = true
pkg := pname.imported
var exp Object
@@ -972,13 +972,13 @@ func (check *Checker) use1(e syntax.Expr, lhs bool) bool {
// dot-imported variables.
if w, _ := obj.(*Var); w != nil && w.pkg == check.pkg {
v = w
v_used = v.used
v_used = check.usedVars[v]
}
}
}
check.exprOrType(&x, n, true)
if v != nil {
v.used = v_used // restore v.used
check.usedVars[v] = v_used // restore v.used
}
case *syntax.ListExpr:
return check.useN(n.ElemList, lhs)

View File

@@ -162,6 +162,8 @@ type Checker struct {
dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through
brokenAliases map[*TypeName]bool // set of aliases with broken (not yet determined) types
unionTypeSets map[*Union]*_TypeSet // computed type sets for union types
usedVars map[*Var]bool // set of used variables
usedPkgNames map[*PkgName]bool // set of used package names
mono monoGraph // graph for detecting non-monomorphizable instantiation loops
firstErr error // first error encountered
@@ -285,12 +287,14 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
// (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
return &Checker{
conf: conf,
ctxt: conf.Context,
pkg: pkg,
Info: info,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
conf: conf,
ctxt: conf.Context,
pkg: pkg,
Info: info,
objMap: make(map[Object]*declInfo),
impMap: make(map[importKey]*Package),
usedVars: make(map[*Var]bool),
usedPkgNames: make(map[*PkgName]bool),
}
}
@@ -298,6 +302,8 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
// The provided files must all belong to the same package.
func (check *Checker) initFiles(files []*syntax.File) {
// start with a clean slate (check.Files may be called multiple times)
// TODO(gri): what determines which fields are zeroed out here, vs at the end
// of checkFiles?
check.files = nil
check.imports = nil
check.dotImportMap = nil
@@ -309,6 +315,13 @@ func (check *Checker) initFiles(files []*syntax.File) {
check.objPath = nil
check.cleaners = nil
// We must initialize usedVars and usedPkgNames both here and in NewChecker,
// because initFiles is not called in the CheckExpr or Eval codepaths, yet we
// want to free this memory at the end of Files ('used' predicates are
// only needed in the context of a given file).
check.usedVars = make(map[*Var]bool)
check.usedPkgNames = make(map[*PkgName]bool)
// determine package name and collect valid files
pkg := check.pkg
for _, file := range files {
@@ -482,8 +495,11 @@ func (check *Checker) checkFiles(files []*syntax.File) {
check.seenPkgMap = nil
check.brokenAliases = nil
check.unionTypeSets = nil
check.usedVars = nil
check.usedPkgNames = nil
check.ctxt = nil
// TODO(gri): shouldn't the cleanup above occur after the bailout?
// TODO(gri) There's more memory we should release at this point.
}

View File

@@ -242,13 +242,12 @@ func (a *object) cmp(b *object) int {
type PkgName struct {
object
imported *Package
used bool // set if the package was used
}
// NewPkgName returns a new PkgName object representing an imported package.
// The remaining arguments set the attributes found with all Objects.
func NewPkgName(pos syntax.Pos, pkg *Package, name string, imported *Package) *PkgName {
return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, nopos}, imported, false}
return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, black, nopos}, imported}
}
// Imported returns the package that was imported.
@@ -331,10 +330,10 @@ func (obj *TypeName) IsAlias() bool {
// A Variable represents a declared variable (including function parameters and results, and struct fields).
type Var struct {
object
origin *Var // if non-nil, the Var from which this one was instantiated
embedded bool // if set, the variable is an embedded struct field, and name is the type name
isField bool // var is struct field
used bool // set if the variable was used
origin *Var // if non-nil, the Var from which this one was instantiated
isParam bool // var is a param, for backport of 'used' check to go1.24 (go.dev/issue/72826)
}
// NewVar returns a new variable.
@@ -345,7 +344,7 @@ func NewVar(pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
// NewParam returns a new variable representing a function parameter.
func NewParam(pos syntax.Pos, pkg *Package, name string, typ Type) *Var {
return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, used: true} // parameters are always 'used'
return &Var{object: object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, isParam: true}
}
// NewField returns a new variable representing a struct field.

View File

@@ -295,7 +295,7 @@ func (check *Checker) collectObjects() {
if imp.fake {
// match 1.17 cmd/compile (not prescribed by spec)
pkgName.used = true
check.usedPkgNames[pkgName] = true
}
// add import to file scope
@@ -715,7 +715,7 @@ func (check *Checker) unusedImports() {
// (initialization), use the blank identifier as explicit package name."
for _, obj := range check.imports {
if !obj.used && obj.name != "_" {
if obj.name != "_" && !check.usedPkgNames[obj] {
check.errorUnusedPkg(obj)
}
}

View File

@@ -36,7 +36,7 @@ func TestSizeof(t *testing.T) {
{term{}, 12, 24},
// Objects
{PkgName{}, 64, 104},
{PkgName{}, 60, 96},
{Const{}, 64, 104},
{TypeName{}, 56, 88},
{Var{}, 64, 104},

View File

@@ -58,7 +58,7 @@ func (check *Checker) usage(scope *Scope) {
var unused []*Var
for name, elem := range scope.elems {
elem = resolve(name, elem)
if v, _ := elem.(*Var); v != nil && !v.used {
if v, _ := elem.(*Var); v != nil && !v.isParam && !check.usedVars[v] {
unused = append(unused, v)
}
}
@@ -824,10 +824,10 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
if lhs != nil {
var used bool
for _, v := range lhsVars {
if v.used {
if check.usedVars[v] {
used = true
}
v.used = true // avoid usage error when checking entire function
check.usedVars[v] = true // avoid usage error when checking entire function
}
if !used {
check.softErrorf(lhs, UnusedVar, "%s declared and not used", lhs.Value)
@@ -934,7 +934,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
if typ == nil || typ == Typ[Invalid] {
// typ == Typ[Invalid] can happen if allowVersion fails.
obj.typ = Typ[Invalid]
obj.used = true // don't complain about unused variable
check.usedVars[obj] = true // don't complain about unused variable
continue
}

View File

@@ -55,7 +55,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
// avoid "declared but not used" errors
// (don't use Checker.use - we don't want to evaluate too much)
if v, _ := obj.(*Var); v != nil && v.pkg == check.pkg /* see Checker.use1 */ {
v.used = true
check.usedVars[v] = true
}
return
}
@@ -83,7 +83,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
// (This code is only needed for dot-imports. Without them,
// we only have to mark variables, see *Var case below).
if pkgName := check.dotImportMap[dotImportKey{scope, obj.Name()}]; pkgName != nil {
pkgName.used = true
check.usedPkgNames[pkgName] = true
}
switch obj := obj.(type) {
@@ -120,7 +120,7 @@ func (check *Checker) ident(x *operand, e *syntax.Name, def *TypeName, wantType
// from other packages to avoid potential race conditions with
// dot-imported variables.
if obj.pkg == check.pkg {
obj.used = true
check.usedVars[obj] = true
}
check.addDeclDep(obj)
if !isValid(typ) {

View File

@@ -43,6 +43,9 @@ type PkgSpecial struct {
}
var runtimePkgs = []string{
// TODO(panjf2000): consider syncing the list inside the
// isAsyncSafePoint in preempt.go based on this list?
"runtime",
"internal/runtime/atomic",