mirror of https://github.com/golang/go.git
go/ssa/ssautil: initialize info when there is syntax
Only initialize *types.Info when there are []*ast.Files available. Previously, when packages x and z, where x imports y and y imports z, are loaded with packages.LoadSyntax and built with ssautil.Packages, then package y will have *types.Info but no files. If y has any globals initialized from a func variable, the bodies of the function literals did not have type information and failed to build. Fixes golang/go#53604 Change-Id: I3cce608d6a127ac44b65947b68cf0d748fc2dfc6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/422639 Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com> Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
0eebaabce7
commit
e71c338beb
|
|
@ -2461,6 +2461,9 @@ func (p *Package) build() {
|
|||
}
|
||||
|
||||
// Initialize package-level vars in correct order.
|
||||
if len(p.info.InitOrder) > 0 && len(p.files) == 0 {
|
||||
panic("no source files provided for package. cannot initialize globals")
|
||||
}
|
||||
for _, varinit := range p.info.InitOrder {
|
||||
if init.Prog.mode&LogSource != 0 {
|
||||
fmt.Fprintf(os.Stderr, "build global initializer %v @ %s\n",
|
||||
|
|
|
|||
|
|
@ -77,10 +77,12 @@ func doPackages(initial []*packages.Package, mode ssa.BuilderMode, deps bool) (*
|
|||
packages.Visit(initial, nil, func(p *packages.Package) {
|
||||
if p.Types != nil && !p.IllTyped {
|
||||
var files []*ast.File
|
||||
var info *types.Info
|
||||
if deps || isInitial[p] {
|
||||
files = p.Syntax
|
||||
info = p.TypesInfo
|
||||
}
|
||||
ssamap[p] = prog.CreatePackage(p.Types, files, p.TypesInfo, true)
|
||||
ssamap[p] = prog.CreatePackage(p.Types, files, info, true)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@ import (
|
|||
"go/token"
|
||||
"go/types"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
"golang.org/x/tools/go/packages/packagestest"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/ssa/ssautil"
|
||||
"golang.org/x/tools/internal/testenv"
|
||||
|
|
@ -135,3 +137,57 @@ func TestIssue28106(t *testing.T) {
|
|||
prog, _ := ssautil.Packages(pkgs, ssa.BuilderMode(0))
|
||||
prog.Build() // no crash
|
||||
}
|
||||
|
||||
func TestIssue53604(t *testing.T) {
|
||||
// Tests that variable initializers are not added to init() when syntax
|
||||
// is not present but types.Info is available.
|
||||
//
|
||||
// Packages x, y, z are loaded with mode `packages.LoadSyntax`.
|
||||
// Package x imports y, and y imports z.
|
||||
// Packages are built using ssautil.Packages() with x and z as roots.
|
||||
// This setup creates y using CreatePackage(pkg, files, info, ...)
|
||||
// where len(files) == 0 but info != nil.
|
||||
//
|
||||
// Tests that globals from y are not initialized.
|
||||
e := packagestest.Export(t, packagestest.Modules, []packagestest.Module{
|
||||
{
|
||||
Name: "golang.org/fake",
|
||||
Files: map[string]interface{}{
|
||||
"x/x.go": `package x; import "golang.org/fake/y"; var V = y.F()`,
|
||||
"y/y.go": `package y; import "golang.org/fake/z"; var F = func () *int { return &z.Z } `,
|
||||
"z/z.go": `package z; var Z int`,
|
||||
},
|
||||
},
|
||||
})
|
||||
defer e.Cleanup()
|
||||
|
||||
// Load x and z as entry packages using packages.LoadSyntax
|
||||
e.Config.Mode = packages.LoadSyntax
|
||||
pkgs, err := packages.Load(e.Config, path.Join(e.Temp(), "fake/x"), path.Join(e.Temp(), "fake/z"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, p := range pkgs {
|
||||
if len(p.Errors) > 0 {
|
||||
t.Fatalf("%v", p.Errors)
|
||||
}
|
||||
}
|
||||
|
||||
prog, _ := ssautil.Packages(pkgs, ssa.BuilderMode(0))
|
||||
prog.Build()
|
||||
|
||||
// y does not initialize F.
|
||||
y := prog.ImportedPackage("golang.org/fake/y")
|
||||
if y == nil {
|
||||
t.Fatal("Failed to load intermediate package y")
|
||||
}
|
||||
yinit := y.Members["init"].(*ssa.Function)
|
||||
for _, bb := range yinit.Blocks {
|
||||
for _, i := range bb.Instrs {
|
||||
if store, ok := i.(*ssa.Store); ok && store.Addr == y.Var("F") {
|
||||
t.Errorf("y.init() stores to F %v", store)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue