mirror of
https://github.com/golang/go
synced 2024-11-12 08:20:22 -07:00
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: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
950100a95c
commit
13aa235ae0
@ -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 {
|
|||||||
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,7 +525,15 @@ func (p *parser) parseNamedType(nlist []int) types.Type {
|
|||||||
|
|
||||||
underlying := p.parseType(pkg)
|
underlying := p.parseType(pkg)
|
||||||
if nt.Underlying() == nil {
|
if nt.Underlying() == nil {
|
||||||
nt.SetUnderlying(underlying.Underlying())
|
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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.tok == '\n' {
|
if p.tok == '\n' {
|
||||||
@ -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()
|
||||||
|
BIN
src/go/internal/gccgoimporter/testdata/v1reflect.gox
vendored
Normal file
BIN
src/go/internal/gccgoimporter/testdata/v1reflect.gox
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user