diff --git a/src/go/internal/gccgoimporter/importer_test.go b/src/go/internal/gccgoimporter/importer_test.go index beb39e6089a..37250fde413 100644 --- a/src/go/internal/gccgoimporter/importer_test.go +++ b/src/go/internal/gccgoimporter/importer_test.go @@ -96,6 +96,7 @@ var importerTests = [...]importerTest{ {pkgpath: "issue29198", name: "FooServer", gccgoVersion: 7, want: "type FooServer struct{FooServer *FooServer; user string; ctx context.Context}"}, {pkgpath: "issue30628", name: "Apple", want: "type Apple struct{hey sync.RWMutex; x int; RQ [517]struct{Count uintptr; NumBytes uintptr; Last uintptr}}"}, {pkgpath: "issue31540", name: "S", gccgoVersion: 7, want: "type S struct{b int; map[Y]Z}"}, + {pkgpath: "issue34182", name: "T1", want: "type T1 struct{f *T2}"}, } func TestGoxImporter(t *testing.T) { diff --git a/src/go/internal/gccgoimporter/parser.go b/src/go/internal/gccgoimporter/parser.go index 76f30bb9ca5..c089b5e0541 100644 --- a/src/go/internal/gccgoimporter/parser.go +++ b/src/go/internal/gccgoimporter/parser.go @@ -254,7 +254,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") } } } @@ -469,8 +469,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) @@ -480,20 +484,34 @@ func (p *parser) update(t types.Type, nlist []int) { } } for _, n := range nlist { - if p.typeList[n] == t { - continue + 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) } - if p.typeList[n] != reserved { - p.errorf("internal error: update(%v): %d not reserved", 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) @@ -504,7 +522,7 @@ func (p *parser) parseNamedType(nlist []int) types.Type { // type alias if p.tok == '=' { p.next() - p.aliases[nlist[len(nlist)-1]] = name + p.aliases[nlist[len(nlist)-1].(int)] = name if obj != nil { // use the previously imported (canonical) type t := obj.Type() @@ -603,7 +621,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() @@ -626,7 +644,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) @@ -642,7 +660,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) @@ -669,7 +687,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) @@ -736,7 +754,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) @@ -776,7 +794,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) @@ -805,7 +823,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") @@ -817,13 +835,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) @@ -912,14 +930,14 @@ 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('<') t, _ := p.parseTypeAfterAngle(pkg, n...) return t } // (*parser).Type after reading the "<". -func (p *parser) parseTypeAfterAngle(pkg *types.Package, n ...int) (t types.Type, n1 int) { +func (p *parser) parseTypeAfterAngle(pkg *types.Package, n ...interface{}) (t types.Type, n1 int) { p.expectKeyword("type") n1 = 0 @@ -962,7 +980,7 @@ func (p *parser) parseTypeAfterAngle(pkg *types.Package, n ...int) (t types.Type // parseTypeExtended is identical to parseType, but if the type in // question is a saved type, returns the index as well as the type // pointer (index returned is zero if we parsed a builtin). -func (p *parser) parseTypeExtended(pkg *types.Package, n ...int) (t types.Type, n1 int) { +func (p *parser) parseTypeExtended(pkg *types.Package, n ...interface{}) (t types.Type, n1 int) { p.expect('<') t, n1 = p.parseTypeAfterAngle(pkg, n...) return @@ -1044,12 +1062,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/src/go/internal/gccgoimporter/testdata/issue34182.go b/src/go/internal/gccgoimporter/testdata/issue34182.go new file mode 100644 index 00000000000..2a5c333a057 --- /dev/null +++ b/src/go/internal/gccgoimporter/testdata/issue34182.go @@ -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/src/go/internal/gccgoimporter/testdata/issue34182.gox b/src/go/internal/gccgoimporter/testdata/issue34182.gox new file mode 100644 index 00000000000..671a7d62d6f --- /dev/null +++ b/src/go/internal/gccgoimporter/testdata/issue34182.gox @@ -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 2 "T2" +type 3 "T3" +type 4 * +type 5 struct { ? ; } +type 6 struct { .go.issue34182.f ; } +type 7 struct { .go.issue34182.f ; } +checksum FF02C49BAF44B06C087ED4E573F7CC880C79C208