cmd/compile/internal/gc: export interface embedding information

Fixes #16369.

Change-Id: I23f8c36370d0da37ac5b5126d012d22f78782782
Reviewed-on: https://go-review.googlesource.com/38392
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2017-03-20 12:14:16 -07:00
parent 07de3465be
commit ee272bbf36
5 changed files with 50 additions and 52 deletions

View file

@ -753,39 +753,7 @@ func (p *exporter) typ(t *Type) {
case TINTER:
p.tag(interfaceTag)
// gc doesn't separate between embedded interfaces
// and methods declared explicitly with an interface
p.int(0) // no embedded interfaces
// Because the compiler flattens interfaces containing
// embedded interfaces, it is possible to create interface
// types that recur through an unnamed type.
// If trackAllTypes is disabled, such recursion is not
// detected, leading to a stack overflow during export
// (issue #16369).
// As a crude work-around we terminate deep recursion
// through interface types with an empty interface and
// report an error.
// This will catch endless recursion, but is unlikely
// to trigger for valid, deeply nested types given the
// high threshold.
// It would be ok to continue without reporting an error
// since the export format is valid. But a subsequent
// import would import an incorrect type. The textual
// exporter does not report an error but importing the
// resulting package will lead to a syntax error during
// import.
// TODO(gri) remove this once we have a permanent fix
// for the issue.
if p.nesting > 100 {
p.int(0) // 0 methods to indicate empty interface
yyerrorl(t.Pos, "cannot export unnamed recursive interface")
break
}
p.nesting++
p.methodList(t)
p.nesting--
case TMAP:
p.tag(mapTag)
@ -830,18 +798,44 @@ func (p *exporter) field(f *Field) {
}
func (p *exporter) methodList(t *Type) {
if p.trace && t.NumFields() > 0 {
p.tracef("methods {>")
defer p.tracef("<\n} ")
var embeddeds, methods []*Field
for _, m := range t.Methods().Slice() {
if m.Sym != nil {
methods = append(methods, m)
} else {
embeddeds = append(embeddeds, m)
}
}
p.int(t.NumFields())
for _, m := range t.Fields().Slice() {
if p.trace && len(embeddeds) > 0 {
p.tracef("embeddeds {>")
}
p.int(len(embeddeds))
for _, m := range embeddeds {
if p.trace {
p.tracef("\n")
}
p.pos(m.Nname)
p.typ(m.Type)
}
if p.trace && len(embeddeds) > 0 {
p.tracef("<\n} ")
}
if p.trace && len(methods) > 0 {
p.tracef("methods {>")
}
p.int(len(methods))
for _, m := range methods {
if p.trace {
p.tracef("\n")
}
p.method(m)
}
if p.trace && len(methods) > 0 {
p.tracef("<\n} ")
}
}
func (p *exporter) method(m *Field) {

View file

@ -526,9 +526,6 @@ func (p *importer) typ() *Type {
functypefield0(t, nil, params, result)
case interfaceTag:
if p.int() != 0 {
formatErrorf("unexpected embedded interface")
}
if ml := p.methodList(); len(ml) == 0 {
t = Types[TINTER]
} else {
@ -604,12 +601,18 @@ func (p *importer) field() *Field {
}
func (p *importer) methodList() (methods []*Field) {
if n := p.int(); n > 0 {
methods = make([]*Field, n)
for i := range methods {
methods[i] = p.method()
}
for n := p.int(); n > 0; n-- {
f := newField()
f.Nname = newname(nblank.Sym)
f.Nname.Pos = p.pos()
f.Type = p.typ()
methods = append(methods, f)
}
for n := p.int(); n > 0; n-- {
methods = append(methods, p.method())
}
return
}

View file

@ -492,12 +492,13 @@ func (p *importer) typ(parent *types.Package) types.Type {
p.record(nil)
}
// no embedded interfaces with gc compiler
if p.int() != 0 {
errorf("unexpected embedded interface")
var embeddeds []*types.Named
for n := p.int(); n > 0; n-- {
p.pos()
embeddeds = append(embeddeds, p.typ(parent).(*types.Named))
}
t := types.NewInterface(p.methodList(parent), nil)
t := types.NewInterface(p.methodList(parent), embeddeds)
if p.trackAllTypes {
p.typList[n] = t
}

View file

@ -205,7 +205,7 @@ var importedObjectTests = []struct {
}{
{"math.Pi", "const Pi untyped float"},
{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
{"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
{"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
{"math.Sin", "func Sin(x float64) float64"},
// TODO(gri) add more tests
}

View file

@ -1,4 +1,4 @@
// errorcheck
// compile
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@ -7,7 +7,7 @@
package p
type T interface {
M(interface { // ERROR "cannot export unnamed recursive interface"
M(interface {
T
})
}