]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
go/internal/gccgoimporter: support embedded field in pointer loop
authorIan Lance Taylor <ian@gcc.gnu.org>
Tue, 10 Sep 2019 20:26:11 +0000 (20:26 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 10 Sep 2019 20:26:11 +0000 (20:26 +0000)
    Backport of https://golang.org/cl/194440.  Original description:

        If an embedded field refers to a type via a pointer, the parser needs
        to know the name of the embedded field. It is possible that the
        pointer type is not yet resolved. This CL fixes the parser to handle
        that case by setting the pointer element type to the unresolved named
        type while the pointer is being resolved.

    Updates golang/go#34182

    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/194562

From-SVN: r275607

libgo/go/go/internal/gccgoimporter/importer_test.go
libgo/go/go/internal/gccgoimporter/parser.go
libgo/go/go/internal/gccgoimporter/testdata/issue34182.go [new file with mode: 0644]
libgo/go/go/internal/gccgoimporter/testdata/issue34182.gox [new file with mode: 0644]

index 58fa8c8cf5ccad8aeede19bc01e18c19b886ec31..eb070c137ff1cf24dea8b02b37cd3ba35c1e044d 100644 (file)
@@ -91,6 +91,7 @@ var importerTests = [...]importerTest{
        {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}"},
        {pkgpath: "nointerface", name: "I", want: "type I int"},
        {pkgpath: "issue29198", name: "FooServer", want: "type FooServer struct{FooServer *FooServer; user string; ctx context.Context}"},
+       {pkgpath: "issue34182", name: "T1", want: "type T1 struct{f *T2}"},
 }
 
 func TestGoxImporter(t *testing.T) {
index 42f43a19fb77873b77e56c6c6256850a70e279a3..ab731cbbfc47825bb8aef9ba5f1ddb63c7d457c8 100644 (file)
@@ -248,7 +248,7 @@ func (p *parser) parseField(pkg *types.Package) (field *types.Var, tag string) {
                case *types.Named:
                        name = typ.Obj().Name()
                default:
-                       p.error("anonymous field expected")
+                       p.error("embedded field expected")
                }
        }
        field = types.NewField(token.NoPos, pkg, name, typ, anon)
@@ -451,8 +451,12 @@ func (p *parser) reserve(n int) {
        }
 }
 
-// update sets the type map entries for the given type numbers nlist to t.
-func (p *parser) update(t types.Type, nlist []int) {
+// update sets the type map entries for the entries in nlist to t.
+// An entry in nlist can be a type number in p.typeList,
+// used to resolve named types, or it can be a *types.Pointer,
+// used to resolve pointers to named types in case they are referenced
+// by embedded fields.
+func (p *parser) update(t types.Type, nlist []interface{}) {
        if len(nlist) != 0 {
                if t == reserved {
                        p.errorf("internal error: update(%v) invoked on reserved", nlist)
@@ -462,20 +466,34 @@ func (p *parser) update(t types.Type, nlist []int) {
                }
        }
        for _, n := range nlist {
-               if p.typeList[n] == t {
-                       continue
-               }
-               if p.typeList[n] != reserved {
-                       p.errorf("internal error: update(%v): %d not reserved", nlist, n)
+               switch n := n.(type) {
+               case int:
+                       if p.typeList[n] == t {
+                               continue
+                       }
+                       if p.typeList[n] != reserved {
+                               p.errorf("internal error: update(%v): %d not reserved", nlist, n)
+                       }
+                       p.typeList[n] = t
+               case *types.Pointer:
+                       if *n != (types.Pointer{}) {
+                               elem := n.Elem()
+                               if elem == t {
+                                       continue
+                               }
+                               p.errorf("internal error: update: pointer already set to %v, expected %v", elem, t)
+                       }
+                       *n = *types.NewPointer(t)
+               default:
+                       p.errorf("internal error: %T on nlist", n)
                }
-               p.typeList[n] = t
        }
 }
 
 // NamedType = TypeName [ "=" ] Type { Method } .
 // TypeName  = ExportedName .
 // Method    = "func" "(" Param ")" Name ParamList ResultList [InlineBody] ";" .
-func (p *parser) parseNamedType(nlist []int) types.Type {
+func (p *parser) parseNamedType(nlist []interface{}) types.Type {
        pkg, name := p.parseExportedName()
        scope := pkg.Scope()
        obj := scope.Lookup(name)
@@ -582,7 +600,7 @@ func (p *parser) parseInt() int {
 }
 
 // ArrayOrSliceType = "[" [ int ] "]" Type .
-func (p *parser) parseArrayOrSliceType(pkg *types.Package, nlist []int) types.Type {
+func (p *parser) parseArrayOrSliceType(pkg *types.Package, nlist []interface{}) types.Type {
        p.expect('[')
        if p.tok == ']' {
                p.next()
@@ -605,7 +623,7 @@ func (p *parser) parseArrayOrSliceType(pkg *types.Package, nlist []int) types.Ty
 }
 
 // MapType = "map" "[" Type "]" Type .
-func (p *parser) parseMapType(pkg *types.Package, nlist []int) types.Type {
+func (p *parser) parseMapType(pkg *types.Package, nlist []interface{}) types.Type {
        p.expectKeyword("map")
 
        t := new(types.Map)
@@ -621,7 +639,7 @@ func (p *parser) parseMapType(pkg *types.Package, nlist []int) types.Type {
 }
 
 // ChanType = "chan" ["<-" | "-<"] Type .
-func (p *parser) parseChanType(pkg *types.Package, nlist []int) types.Type {
+func (p *parser) parseChanType(pkg *types.Package, nlist []interface{}) types.Type {
        p.expectKeyword("chan")
 
        t := new(types.Chan)
@@ -648,7 +666,7 @@ func (p *parser) parseChanType(pkg *types.Package, nlist []int) types.Type {
 }
 
 // StructType = "struct" "{" { Field } "}" .
-func (p *parser) parseStructType(pkg *types.Package, nlist []int) types.Type {
+func (p *parser) parseStructType(pkg *types.Package, nlist []interface{}) types.Type {
        p.expectKeyword("struct")
 
        t := new(types.Struct)
@@ -714,7 +732,7 @@ func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
 }
 
 // FunctionType = ParamList ResultList .
-func (p *parser) parseFunctionType(pkg *types.Package, nlist []int) *types.Signature {
+func (p *parser) parseFunctionType(pkg *types.Package, nlist []interface{}) *types.Signature {
        t := new(types.Signature)
        p.update(t, nlist)
 
@@ -740,7 +758,7 @@ func (p *parser) parseFunc(pkg *types.Package) *types.Func {
 }
 
 // InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" .
-func (p *parser) parseInterfaceType(pkg *types.Package, nlist []int) types.Type {
+func (p *parser) parseInterfaceType(pkg *types.Package, nlist []interface{}) types.Type {
        p.expectKeyword("interface")
 
        t := new(types.Interface)
@@ -767,7 +785,7 @@ func (p *parser) parseInterfaceType(pkg *types.Package, nlist []int) types.Type
 }
 
 // PointerType = "*" ("any" | Type) .
-func (p *parser) parsePointerType(pkg *types.Package, nlist []int) types.Type {
+func (p *parser) parsePointerType(pkg *types.Package, nlist []interface{}) types.Type {
        p.expect('*')
        if p.tok == scanner.Ident {
                p.expectKeyword("any")
@@ -779,13 +797,13 @@ func (p *parser) parsePointerType(pkg *types.Package, nlist []int) types.Type {
        t := new(types.Pointer)
        p.update(t, nlist)
 
-       *t = *types.NewPointer(p.parseType(pkg))
+       *t = *types.NewPointer(p.parseType(pkg, t))
 
        return t
 }
 
 // TypeSpec = NamedType | MapType | ChanType | StructType | InterfaceType | PointerType | ArrayOrSliceType | FunctionType .
-func (p *parser) parseTypeSpec(pkg *types.Package, nlist []int) types.Type {
+func (p *parser) parseTypeSpec(pkg *types.Package, nlist []interface{}) types.Type {
        switch p.tok {
        case scanner.String:
                return p.parseNamedType(nlist)
@@ -874,13 +892,13 @@ func lookupBuiltinType(typ int) types.Type {
 //
 // parseType updates the type map to t for all type numbers n.
 //
-func (p *parser) parseType(pkg *types.Package, n ...int) types.Type {
+func (p *parser) parseType(pkg *types.Package, n ...interface{}) types.Type {
        p.expect('<')
        return p.parseTypeAfterAngle(pkg, n...)
 }
 
 // (*parser).Type after reading the "<".
-func (p *parser) parseTypeAfterAngle(pkg *types.Package, n ...int) (t types.Type) {
+func (p *parser) parseTypeAfterAngle(pkg *types.Package, n ...interface{}) (t types.Type) {
        p.expectKeyword("type")
 
        switch p.tok {
@@ -995,12 +1013,12 @@ func (p *parser) parseTypes(pkg *types.Package) {
        }
 
        for i := 1; i < int(exportedp1); i++ {
-               p.parseSavedType(pkg, i, []int{})
+               p.parseSavedType(pkg, i, nil)
        }
 }
 
 // parseSavedType parses one saved type definition.
-func (p *parser) parseSavedType(pkg *types.Package, i int, nlist []int) {
+func (p *parser) parseSavedType(pkg *types.Package, i int, nlist []interface{}) {
        defer func(s *scanner.Scanner, tok rune, lit string) {
                p.scanner = s
                p.tok = tok
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/issue34182.go b/libgo/go/go/internal/gccgoimporter/testdata/issue34182.go
new file mode 100644 (file)
index 0000000..2a5c333
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package issue34182
+
+type T1 struct {
+       f *T2
+}
+
+type T2 struct {
+       f T3
+}
+
+type T3 struct {
+       *T2
+}
diff --git a/libgo/go/go/internal/gccgoimporter/testdata/issue34182.gox b/libgo/go/go/internal/gccgoimporter/testdata/issue34182.gox
new file mode 100644 (file)
index 0000000..671a7d6
--- /dev/null
@@ -0,0 +1,13 @@
+v3;
+package issue34182
+pkgpath issue34182
+init issue34182 ~go.issue34182
+types 8 4 21 21 21 17 30 45 45
+type 1 "T1" <type 6>
+type 2 "T2" <type 7>
+type 3 "T3" <type 5>
+type 4 *<type 2>
+type 5 struct { ? <type 4>; }
+type 6 struct { .go.issue34182.f <type 4>; }
+type 7 struct { .go.issue34182.f <type 3>; }
+checksum FF02C49BAF44B06C087ED4E573F7CC880C79C208