cmd/compile: fix crawler for unexported fields with instantiated types

In markType() in crawler.go, mark the type of a unexported field if it
is a fully-instantiated type, since we create and instantiate the
methods of any fully-instantiated type that we see during import. As
before, we still do not mark the type of an unexported field if that
type is not generic. Fixes #48454 and most recent issue described in
48337. The included test is similar to the case in 48454.

Fixes #48454
Fixes #48337

Change-Id: I77a2a62b9e2647876facfa6f004201e8f699c905
Reviewed-on: https://go-review.googlesource.com/c/go/+/351315
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2021-09-18 20:02:08 -07:00
parent 812c99f86a
commit f6b5ffb5e1
5 changed files with 65 additions and 8 deletions

View file

@ -10,10 +10,12 @@ import (
"cmd/compile/internal/types"
)
// crawlExports crawls the type/object graph rooted at the given list
// of exported objects. Any functions that are found to be potentially
// callable by importers are marked with ExportInline so that
// iexport.go knows to re-export their inline body.
// crawlExports crawls the type/object graph rooted at the given list of exported
// objects. It descends through all parts of types and follows any methods on defined
// types. Any functions that are found to be potentially callable by importers are
// marked with ExportInline, so that iexport.go knows to re-export their inline body.
// Also, any function or global referenced by a function marked by ExportInline() is
// marked for export (whether its name is exported or not).
func crawlExports(exports []*ir.Name) {
p := crawler{
marked: make(map[*types.Type]bool),
@ -29,7 +31,7 @@ type crawler struct {
embedded map[*types.Type]bool // types already seen by markEmbed
}
// markObject visits a reachable object.
// markObject visits a reachable object (function, method, global type, or global variable)
func (p *crawler) markObject(n *ir.Name) {
if n.Op() == ir.ONAME && n.Class == ir.PFUNC {
p.markInlBody(n)
@ -97,7 +99,12 @@ func (p *crawler) markType(t *types.Type) {
break
}
for _, f := range t.FieldSlice() {
if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
// Mark the type of a unexported field if it is a
// fully-instantiated type, since we create and instantiate
// the methods of any fully-instantiated type that we see
// during import (see end of typecheck.substInstType).
if types.IsExported(f.Sym.Name) || f.Embedded != 0 ||
isPtrFullyInstantiated(f.Type) {
p.markType(f.Type)
}
}
@ -108,8 +115,6 @@ func (p *crawler) markType(t *types.Type) {
}
case types.TINTER:
// TODO(danscales) - will have to deal with the types in interface
// elements here when implemented in types2 and represented in types1.
for _, f := range t.AllMethods().Slice() {
if types.IsExported(f.Sym.Name) {
p.markType(f.Type)
@ -226,3 +231,10 @@ func (p *crawler) markInlBody(n *ir.Name) {
// because after inlining they might be callable.
ir.VisitList(fn.Inl.Body, doFlood)
}
// isPtrFullyInstantiated returns true if t is a fully-instantiated type, or it is a
// pointer to a fully-instantiated type.
func isPtrFullyInstantiated(t *types.Type) bool {
return t.IsPtr() && t.Elem().IsFullyInstantiated() ||
t.IsFullyInstantiated()
}

View file

@ -0,0 +1,16 @@
// Copyright 2021 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 a
import "sync"
type Val[T any] struct {
mu sync.RWMutex
val T
}
func (v *Val[T]) Has() {
v.mu.RLock()
}

View file

@ -0,0 +1,11 @@
// Copyright 2021 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 b
import "a"
type Session struct {
privateField a.Val[string]
}

View file

@ -0,0 +1,11 @@
// Copyright 2021 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 main
import "b"
func main() {
var _ b.Session
}

View file

@ -0,0 +1,7 @@
// rundir -G=3
// Copyright 2021 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 ignored