Commit 13aa235a authored by Than McIntosh's avatar Than McIntosh

go/internal/gccgoimporter: fix bug reading V1 export data

Fix a bug in the reading of elderly export data. In such export data
when reading type information it's possible to encounter a named type N1
defined as a typedef of some other named type N2 at a point when the
underying type of N1 has not yet been finalized. Handle this case by
generating a fixup, then process fixups at the end of parsing to
set the correct underlying type.

Fixes #29006.

Change-Id: I6a505c897bd95eb161ee04637bb6eebad9f20d52
Reviewed-on: https://go-review.googlesource.com/c/151997
Run-TryBot: Than McIntosh <thanm@google.com>
Reviewed-by: 's avatarRobert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 950100a9
...@@ -86,6 +86,7 @@ var importerTests = [...]importerTest{ ...@@ -86,6 +86,7 @@ var importerTests = [...]importerTest{
{pkgpath: "aliases", name: "C0", want: "type C0 struct{f1 C1; f2 C1}"}, {pkgpath: "aliases", name: "C0", want: "type C0 struct{f1 C1; f2 C1}"},
{pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"}, {pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"},
{pkgpath: "issue27856", name: "M", want: "type M struct{E F}"}, {pkgpath: "issue27856", name: "M", want: "type M struct{E F}"},
{pkgpath: "v1reflect", name: "Type", want: "type Type interface{Align() int; AssignableTo(u Type) bool; Bits() int; ChanDir() ChanDir; Elem() Type; Field(i int) StructField; FieldAlign() int; FieldByIndex(index []int) StructField; FieldByName(name string) (StructField, bool); FieldByNameFunc(match func(string) bool) (StructField, bool); Implements(u Type) bool; In(i int) Type; IsVariadic() bool; Key() Type; Kind() Kind; Len() int; Method(int) Method; MethodByName(string) (Method, bool); Name() string; NumField() int; NumIn() int; NumMethod() int; NumOut() int; Out(i int) Type; PkgPath() string; Size() uintptr; String() string; common() *commonType; rawString() string; runtimeType() *runtimeType; uncommon() *uncommonType}"},
} }
func TestGoxImporter(t *testing.T) { func TestGoxImporter(t *testing.T) {
......
...@@ -29,9 +29,30 @@ type parser struct { ...@@ -29,9 +29,30 @@ type parser struct {
imports map[string]*types.Package // package path -> package object imports map[string]*types.Package // package path -> package object
typeList []types.Type // type number -> type typeList []types.Type // type number -> type
typeData []string // unparsed type data (v3 and later) typeData []string // unparsed type data (v3 and later)
fixups []fixupRecord // fixups to apply at end of parsing
initdata InitData // package init priority data initdata InitData // package init priority data
} }
// When reading V1 export data it's possible to encounter a defined
// type N1 with an underlying defined type N2 while we are still
// reading in that defined type N2; see issue #29006 for an instance
// of this. Example:
//
// type N1 N2
// type N2 struct {
// ...
// p *N1
// }
//
// To handle such cases, the parser generates a fixup record (below) and
// delays setting of N1's underlying type until parsing is complete, at
// which point fixups are applied.
type fixupRecord struct {
toUpdate *types.Named // type to modify when fixup is processed
target types.Type // type that was incomplete when fixup was created
}
func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) { func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) {
p.scanner = new(scanner.Scanner) p.scanner = new(scanner.Scanner)
p.initScanner(filename, src) p.initScanner(filename, src)
...@@ -504,8 +525,16 @@ func (p *parser) parseNamedType(nlist []int) types.Type { ...@@ -504,8 +525,16 @@ func (p *parser) parseNamedType(nlist []int) types.Type {
underlying := p.parseType(pkg) underlying := p.parseType(pkg)
if nt.Underlying() == nil { if nt.Underlying() == nil {
if underlying.Underlying() == nil {
if p.version != "v1" {
p.errorf("internal error: unexpected fixup required for %v", nt)
}
fix := fixupRecord{toUpdate: nt, target: underlying}
p.fixups = append(p.fixups, fix)
} else {
nt.SetUnderlying(underlying.Underlying()) nt.SetUnderlying(underlying.Underlying())
} }
}
if p.tok == '\n' { if p.tok == '\n' {
p.next() p.next()
...@@ -1175,6 +1204,13 @@ func (p *parser) parsePackage() *types.Package { ...@@ -1175,6 +1204,13 @@ func (p *parser) parsePackage() *types.Package {
for p.tok != scanner.EOF { for p.tok != scanner.EOF {
p.parseDirective() p.parseDirective()
} }
for _, f := range p.fixups {
if f.target.Underlying() == nil {
p.errorf("internal error: fixup can't be applied, loop required")
}
f.toUpdate.SetUnderlying(f.target.Underlying())
}
p.fixups = nil
for _, typ := range p.typeList { for _, typ := range p.typeList {
if it, ok := typ.(*types.Interface); ok { if it, ok := typ.(*types.Interface); ok {
it.Complete() it.Complete()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment