From: Matthew Dempsky Date: Mon, 20 Mar 2017 19:14:16 +0000 (-0700) Subject: cmd/compile/internal/gc: export interface embedding information X-Git-Tag: go1.9beta1~1075 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ee272bbf36afa97b51669e1e8d1aed4fcb7013ab;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 24e043cacb..4e72cf3452 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -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) { diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index e417536fc8..671c024217 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -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 } diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go index e38570d97b..3414f73155 100644 --- a/src/go/internal/gcimporter/bimport.go +++ b/src/go/internal/gcimporter/bimport.go @@ -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 } diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go index a0697faeb6..f9a80cd232 100644 --- a/src/go/internal/gcimporter/gcimporter_test.go +++ b/src/go/internal/gcimporter/gcimporter_test.go @@ -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 } diff --git a/test/fixedbugs/issue16369.go b/test/fixedbugs/issue16369.go index 3ff2e63341..e97f4a0e11 100644 --- a/test/fixedbugs/issue16369.go +++ b/test/fixedbugs/issue16369.go @@ -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 }) }