Update to go1.24.2
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user