mirror of
https://github.com/golang/go.git
synced 2025-11-11 14:11:04 +00:00
[dev.regabi] cmd/compile: fix package-initialization order
This CL fixes package initialization order by creating the init task before the general deadcode-removal pass. It also changes noder to emit zero-initialization assignments (i.e., OAS with nil RHS) for package-block variables, so that initOrder can tell the variables still need initialization. To allow this, we need to also extend the static-init code to recognize zero-initialization assignments. This doesn't pass toolstash -cmp, because it reorders some package initialization routines. Fixes #43444. Change-Id: I0da7996a62c85e15e97ce965298127e075390a7e Reviewed-on: https://go-review.googlesource.com/c/go/+/280976 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
3a4474cdfd
commit
68e6fa4f68
6 changed files with 70 additions and 41 deletions
|
|
@ -208,6 +208,11 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||||
dwarfgen.RecordPackageName()
|
dwarfgen.RecordPackageName()
|
||||||
ssagen.CgoSymABIs()
|
ssagen.CgoSymABIs()
|
||||||
|
|
||||||
|
// Build init task.
|
||||||
|
if initTask := pkginit.Task(); initTask != nil {
|
||||||
|
typecheck.Export(initTask)
|
||||||
|
}
|
||||||
|
|
||||||
// Compute Addrtaken for names.
|
// Compute Addrtaken for names.
|
||||||
// We need to wait until typechecking is done so that when we see &x[i]
|
// We need to wait until typechecking is done so that when we see &x[i]
|
||||||
// we know that x has its address taken if x is an array, but not if x is a slice.
|
// we know that x has its address taken if x is an array, but not if x is a slice.
|
||||||
|
|
@ -249,11 +254,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||||
typecheck.AllImportedBodies()
|
typecheck.AllImportedBodies()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build init task.
|
|
||||||
if initTask := pkginit.Task(); initTask != nil {
|
|
||||||
typecheck.Export(initTask)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inlining
|
// Inlining
|
||||||
base.Timer.Start("fe", "inlining")
|
base.Timer.Start("fe", "inlining")
|
||||||
if base.Flag.LowerL != 0 {
|
if base.Flag.LowerL != 0 {
|
||||||
|
|
|
||||||
|
|
@ -474,24 +474,15 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node {
|
||||||
p.checkUnused(pragma)
|
p.checkUnused(pragma)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.setlineno(decl)
|
|
||||||
return DeclVars(names, typ, exprs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// declare variables from grammar
|
|
||||||
// new_name_list (type | [type] = expr_list)
|
|
||||||
func DeclVars(vl []*ir.Name, t ir.Ntype, el []ir.Node) []ir.Node {
|
|
||||||
var init []ir.Node
|
var init []ir.Node
|
||||||
doexpr := len(el) > 0
|
p.setlineno(decl)
|
||||||
|
|
||||||
if len(el) == 1 && len(vl) > 1 {
|
if len(names) > 1 && len(exprs) == 1 {
|
||||||
e := el[0]
|
as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, exprs)
|
||||||
as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
|
for _, v := range names {
|
||||||
as2.Rhs = []ir.Node{e}
|
|
||||||
for _, v := range vl {
|
|
||||||
as2.Lhs.Append(v)
|
as2.Lhs.Append(v)
|
||||||
typecheck.Declare(v, typecheck.DeclContext)
|
typecheck.Declare(v, typecheck.DeclContext)
|
||||||
v.Ntype = t
|
v.Ntype = typ
|
||||||
v.Defn = as2
|
v.Defn = as2
|
||||||
if ir.CurFunc != nil {
|
if ir.CurFunc != nil {
|
||||||
init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
|
init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
|
||||||
|
|
@ -501,34 +492,29 @@ func DeclVars(vl []*ir.Name, t ir.Ntype, el []ir.Node) []ir.Node {
|
||||||
return append(init, as2)
|
return append(init, as2)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, v := range vl {
|
for i, v := range names {
|
||||||
var e ir.Node
|
var e ir.Node
|
||||||
if doexpr {
|
if i < len(exprs) {
|
||||||
if i >= len(el) {
|
e = exprs[i]
|
||||||
base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
e = el[i]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typecheck.Declare(v, typecheck.DeclContext)
|
typecheck.Declare(v, typecheck.DeclContext)
|
||||||
v.Ntype = t
|
v.Ntype = typ
|
||||||
|
|
||||||
if e != nil || ir.CurFunc != nil || ir.IsBlank(v) {
|
|
||||||
if ir.CurFunc != nil {
|
if ir.CurFunc != nil {
|
||||||
init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
|
init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
|
||||||
}
|
}
|
||||||
as := ir.NewAssignStmt(base.Pos, v, e)
|
as := ir.NewAssignStmt(base.Pos, v, e)
|
||||||
init = append(init, as)
|
init = append(init, as)
|
||||||
if e != nil {
|
if e != nil || ir.CurFunc == nil {
|
||||||
v.Defn = as
|
v.Defn = as
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(exprs) != 0 && len(names) != len(exprs) {
|
||||||
|
base.Errorf("assignment mismatch: %d variables but %d values", len(names), len(exprs))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(el) > len(vl) {
|
|
||||||
base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
|
|
||||||
}
|
|
||||||
return init
|
return init
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ package pkginit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
|
"cmd/compile/internal/deadcode"
|
||||||
"cmd/compile/internal/ir"
|
"cmd/compile/internal/ir"
|
||||||
"cmd/compile/internal/objw"
|
"cmd/compile/internal/objw"
|
||||||
"cmd/compile/internal/typecheck"
|
"cmd/compile/internal/typecheck"
|
||||||
|
|
@ -68,6 +69,9 @@ func Task() *ir.Name {
|
||||||
|
|
||||||
// Record user init functions.
|
// Record user init functions.
|
||||||
for _, fn := range typecheck.Target.Inits {
|
for _, fn := range typecheck.Target.Inits {
|
||||||
|
// Must happen after initOrder; see #43444.
|
||||||
|
deadcode.Func(fn)
|
||||||
|
|
||||||
// Skip init functions with empty bodies.
|
// Skip init functions with empty bodies.
|
||||||
if len(fn.Body) == 1 {
|
if len(fn.Body) == 1 {
|
||||||
if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
|
if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
|
||||||
|
|
|
||||||
|
|
@ -86,17 +86,22 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
|
||||||
if rn.Class_ != ir.PEXTERN || rn.Sym().Pkg != types.LocalPkg {
|
if rn.Class_ != ir.PEXTERN || rn.Sym().Pkg != types.LocalPkg {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if rn.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if rn.Defn.Op() != ir.OAS {
|
if rn.Defn.Op() != ir.OAS {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if rn.Type().IsString() { // perhaps overwritten by cmd/link -X (#34675)
|
if rn.Type().IsString() { // perhaps overwritten by cmd/link -X (#34675)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if rn.Embed != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
orig := rn
|
orig := rn
|
||||||
r := rn.Defn.(*ir.AssignStmt).Y
|
r := rn.Defn.(*ir.AssignStmt).Y
|
||||||
|
if r == nil {
|
||||||
|
// No explicit initialization value. Probably zeroed but perhaps
|
||||||
|
// supplied externally and of unknown value.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for r.Op() == ir.OCONVNOP && !types.Identical(r.Type(), typ) {
|
for r.Op() == ir.OCONVNOP && !types.Identical(r.Type(), typ) {
|
||||||
r = r.(*ir.ConvExpr).X
|
r = r.(*ir.ConvExpr).X
|
||||||
|
|
@ -185,6 +190,11 @@ func (s *Schedule) staticcopy(l *ir.Name, loff int64, rn *ir.Name, typ *types.Ty
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Type) bool {
|
func (s *Schedule) StaticAssign(l *ir.Name, loff int64, r ir.Node, typ *types.Type) bool {
|
||||||
|
if r == nil {
|
||||||
|
// No explicit initialization value. Either zero or supplied
|
||||||
|
// externally.
|
||||||
|
return true
|
||||||
|
}
|
||||||
for r.Op() == ir.OCONVNOP {
|
for r.Op() == ir.OCONVNOP {
|
||||||
r = r.(*ir.ConvExpr).X
|
r = r.(*ir.ConvExpr).X
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
test/fixedbugs/issue43444.go
Normal file
28
test/fixedbugs/issue43444.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
// run
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
var sp = ""
|
||||||
|
|
||||||
|
func f(name string, _ ...interface{}) int {
|
||||||
|
print(sp, name)
|
||||||
|
sp = " "
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var a = f("a", x)
|
||||||
|
var b = f("b", y)
|
||||||
|
var c = f("c", z)
|
||||||
|
var d = func() int {
|
||||||
|
if false {
|
||||||
|
_ = z
|
||||||
|
}
|
||||||
|
return f("d")
|
||||||
|
}()
|
||||||
|
var e = f("e")
|
||||||
|
|
||||||
|
var x int
|
||||||
|
var y int = 42
|
||||||
|
var z int = func() int { return 42 }()
|
||||||
|
|
||||||
|
func main() { println() }
|
||||||
1
test/fixedbugs/issue43444.out
Normal file
1
test/fixedbugs/issue43444.out
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
e a b c d
|
||||||
Loading…
Add table
Add a link
Reference in a new issue