Commit ee272bbf authored by Matthew Dempsky's avatar Matthew Dempsky

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: default avatarRobert Griesemer <gri@golang.org>
parent 07de3465
...@@ -753,39 +753,7 @@ func (p *exporter) typ(t *Type) { ...@@ -753,39 +753,7 @@ func (p *exporter) typ(t *Type) {
case TINTER: case TINTER:
p.tag(interfaceTag) 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.methodList(t)
p.nesting--
case TMAP: case TMAP:
p.tag(mapTag) p.tag(mapTag)
...@@ -830,18 +798,44 @@ func (p *exporter) field(f *Field) { ...@@ -830,18 +798,44 @@ func (p *exporter) field(f *Field) {
} }
func (p *exporter) methodList(t *Type) { func (p *exporter) methodList(t *Type) {
if p.trace && t.NumFields() > 0 { var embeddeds, methods []*Field
p.tracef("methods {>")
defer p.tracef("<\n} ") for _, m := range t.Methods().Slice() {
if m.Sym != nil {
methods = append(methods, m)
} else {
embeddeds = append(embeddeds, m)
}
} }
p.int(t.NumFields()) if p.trace && len(embeddeds) > 0 {
for _, m := range t.Fields().Slice() { 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 { if p.trace {
p.tracef("\n") p.tracef("\n")
} }
p.method(m) p.method(m)
} }
if p.trace && len(methods) > 0 {
p.tracef("<\n} ")
}
} }
func (p *exporter) method(m *Field) { func (p *exporter) method(m *Field) {
......
...@@ -526,9 +526,6 @@ func (p *importer) typ() *Type { ...@@ -526,9 +526,6 @@ func (p *importer) typ() *Type {
functypefield0(t, nil, params, result) functypefield0(t, nil, params, result)
case interfaceTag: case interfaceTag:
if p.int() != 0 {
formatErrorf("unexpected embedded interface")
}
if ml := p.methodList(); len(ml) == 0 { if ml := p.methodList(); len(ml) == 0 {
t = Types[TINTER] t = Types[TINTER]
} else { } else {
...@@ -604,12 +601,18 @@ func (p *importer) field() *Field { ...@@ -604,12 +601,18 @@ func (p *importer) field() *Field {
} }
func (p *importer) methodList() (methods []*Field) { func (p *importer) methodList() (methods []*Field) {
if n := p.int(); n > 0 { for n := p.int(); n > 0; n-- {
methods = make([]*Field, n) f := newField()
for i := range methods { f.Nname = newname(nblank.Sym)
methods[i] = p.method() 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 return
} }
......
...@@ -492,12 +492,13 @@ func (p *importer) typ(parent *types.Package) types.Type { ...@@ -492,12 +492,13 @@ func (p *importer) typ(parent *types.Package) types.Type {
p.record(nil) p.record(nil)
} }
// no embedded interfaces with gc compiler var embeddeds []*types.Named
if p.int() != 0 { for n := p.int(); n > 0; n-- {
errorf("unexpected embedded interface") 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 { if p.trackAllTypes {
p.typList[n] = t p.typList[n] = t
} }
......
...@@ -205,7 +205,7 @@ var importedObjectTests = []struct { ...@@ -205,7 +205,7 @@ var importedObjectTests = []struct {
}{ }{
{"math.Pi", "const Pi untyped float"}, {"math.Pi", "const Pi untyped float"},
{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"}, {"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"}, {"math.Sin", "func Sin(x float64) float64"},
// TODO(gri) add more tests // TODO(gri) add more tests
} }
......
// errorcheck // compile
// Copyright 2016 The Go Authors. All rights reserved. // Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
package p package p
type T interface { type T interface {
M(interface { // ERROR "cannot export unnamed recursive interface" M(interface {
T T
}) })
} }
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