mirror of
https://github.com/golang/go
synced 2024-11-22 14:24:45 -07: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
@ -208,6 +208,11 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||
dwarfgen.RecordPackageName()
|
||||
ssagen.CgoSymABIs()
|
||||
|
||||
// Build init task.
|
||||
if initTask := pkginit.Task(); initTask != nil {
|
||||
typecheck.Export(initTask)
|
||||
}
|
||||
|
||||
// Compute Addrtaken for names.
|
||||
// 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.
|
||||
@ -249,11 +254,6 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||
typecheck.AllImportedBodies()
|
||||
}
|
||||
|
||||
// Build init task.
|
||||
if initTask := pkginit.Task(); initTask != nil {
|
||||
typecheck.Export(initTask)
|
||||
}
|
||||
|
||||
// Inlining
|
||||
base.Timer.Start("fe", "inlining")
|
||||
if base.Flag.LowerL != 0 {
|
||||
|
@ -474,24 +474,15 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node {
|
||||
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
|
||||
doexpr := len(el) > 0
|
||||
p.setlineno(decl)
|
||||
|
||||
if len(el) == 1 && len(vl) > 1 {
|
||||
e := el[0]
|
||||
as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
|
||||
as2.Rhs = []ir.Node{e}
|
||||
for _, v := range vl {
|
||||
if len(names) > 1 && len(exprs) == 1 {
|
||||
as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, exprs)
|
||||
for _, v := range names {
|
||||
as2.Lhs.Append(v)
|
||||
typecheck.Declare(v, typecheck.DeclContext)
|
||||
v.Ntype = t
|
||||
v.Ntype = typ
|
||||
v.Defn = as2
|
||||
if ir.CurFunc != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
for i, v := range vl {
|
||||
for i, v := range names {
|
||||
var e ir.Node
|
||||
if doexpr {
|
||||
if i >= len(el) {
|
||||
base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
|
||||
break
|
||||
}
|
||||
e = el[i]
|
||||
if i < len(exprs) {
|
||||
e = exprs[i]
|
||||
}
|
||||
|
||||
typecheck.Declare(v, typecheck.DeclContext)
|
||||
v.Ntype = t
|
||||
v.Ntype = typ
|
||||
|
||||
if e != nil || ir.CurFunc != nil || ir.IsBlank(v) {
|
||||
if ir.CurFunc != nil {
|
||||
init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
|
||||
}
|
||||
as := ir.NewAssignStmt(base.Pos, v, e)
|
||||
init = append(init, as)
|
||||
if e != nil {
|
||||
v.Defn = as
|
||||
}
|
||||
if ir.CurFunc != nil {
|
||||
init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
|
||||
}
|
||||
as := ir.NewAssignStmt(base.Pos, v, e)
|
||||
init = append(init, as)
|
||||
if e != nil || ir.CurFunc == nil {
|
||||
v.Defn = as
|
||||
}
|
||||
}
|
||||
|
||||
if len(el) > len(vl) {
|
||||
base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
|
||||
if len(exprs) != 0 && len(names) != len(exprs) {
|
||||
base.Errorf("assignment mismatch: %d variables but %d values", len(names), len(exprs))
|
||||
}
|
||||
|
||||
return init
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ package pkginit
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/deadcode"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/objw"
|
||||
"cmd/compile/internal/typecheck"
|
||||
@ -68,6 +69,9 @@ func Task() *ir.Name {
|
||||
|
||||
// Record user init functions.
|
||||
for _, fn := range typecheck.Target.Inits {
|
||||
// Must happen after initOrder; see #43444.
|
||||
deadcode.Func(fn)
|
||||
|
||||
// Skip init functions with empty bodies.
|
||||
if len(fn.Body) == 1 {
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
if rn.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
|
||||
return false
|
||||
}
|
||||
if rn.Defn.Op() != ir.OAS {
|
||||
return false
|
||||
}
|
||||
if rn.Type().IsString() { // perhaps overwritten by cmd/link -X (#34675)
|
||||
return false
|
||||
}
|
||||
if rn.Embed != nil {
|
||||
return false
|
||||
}
|
||||
orig := rn
|
||||
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) {
|
||||
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 {
|
||||
if r == nil {
|
||||
// No explicit initialization value. Either zero or supplied
|
||||
// externally.
|
||||
return true
|
||||
}
|
||||
for r.Op() == ir.OCONVNOP {
|
||||
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…
Reference in New Issue
Block a user