]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/gc: export interface embedding information
authorMatthew Dempsky <mdempsky@google.com>
Mon, 20 Mar 2017 19:14:16 +0000 (12:14 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 21 Mar 2017 02:35:40 +0000 (02:35 +0000)
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>
src/cmd/compile/internal/gc/bexport.go
src/cmd/compile/internal/gc/bimport.go
src/go/internal/gcimporter/bimport.go
src/go/internal/gcimporter/gcimporter_test.go
test/fixedbugs/issue16369.go

index 24e043cacb6251118a81ff5952398f1cd3da9e58..4e72cf3452d72812532489f1aebee8014727092c 100644 (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) {
index e417536fc82f77c8a1a0869901be2674ce847b3c..671c0242171862fc28f19e507882df771788c1dd 100644 (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
 }
 
index e38570d97bbf1aa20849ec80909cd9f197288ac3..3414f73155faf09bc9ae5dcf6ba84ddd96d009ba 100644 (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
                }
index a0697faeb682d9af97808e6775ba7196e65f17de..f9a80cd232ffaf8de8b3f3820cf3924e36db46da 100644 (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
 }
index 3ff2e6334189ba70080ed4479aee89c1ac3bf644..e97f4a0e110736d25d83e34ffaf1c046e745a78d 100644 (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
        })
 }