cmd/compile: fix crawling of embeddable types during inline

In CL 327872, there's a fix for crawling of embeddable types directly
reached by the user, so all of its methods need to be re-exported. But
we missed the cased when an un-exported type may be reachable by
embedding in exported type. Example:

	type t struct {}
	func (t) M() {}

	func F() interface{} { return struct{ t }{} }

We generate the wrapper for "struct{ t }".M, and when inlining call to
"struct{ t }".M makes "t.M" reachable.

It works well, and only be revealed in CL 327871, when we changed
methodWrapper to always call inline.InlineCalls, thus causes the crash
in #49016, which involve dot type in inlined function.

Fixes #49016

Change-Id: If174fa5575132da5cf60e4bd052f7011c4e76c5d
Reviewed-on: https://go-review.googlesource.com/c/go/+/356254
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Cuong Manh Le 2021-10-18 14:31:48 +07:00
parent 27a1454ee0
commit 4e565f7372
9 changed files with 128 additions and 8 deletions

View File

@ -195,18 +195,35 @@ func (p *crawler) markInlBody(n *ir.Name) {
var doFlood func(n ir.Node)
doFlood = func(n ir.Node) {
t := n.Type()
if t != nil && (t.HasTParam() || t.IsFullyInstantiated()) {
// Ensure that we call markType() on any base generic type
// that is written to the export file (even if not explicitly
// marked for export), so we will call markInlBody on its
// methods, and the methods will be available for
// instantiation if needed.
p.markType(t)
if t != nil {
if t.HasTParam() || t.IsFullyInstantiated() {
// Ensure that we call markType() on any base generic type
// that is written to the export file (even if not explicitly
// marked for export), so we will call markInlBody on its
// methods, and the methods will be available for
// instantiation if needed.
p.markType(t)
}
if base.Debug.Unified == 0 {
// If a method of un-exported type is promoted and accessible by
// embedding in an exported type, it makes that type reachable.
//
// Example:
//
// type t struct {}
// func (t) M() {}
//
// func F() interface{} { return struct{ t }{} }
//
// We generate the wrapper for "struct{ t }".M, and inline call
// to "struct{ t }".M, which makes "t.M" reachable.
p.markEmbed(t)
}
}
switch n.Op() {
case ir.OMETHEXPR, ir.ODOTMETH:
p.markInlBody(ir.MethodExprName(n))
case ir.ONAME:
n := n.(*ir.Name)
switch n.Class {

View File

@ -0,0 +1,36 @@
// 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
type Node interface {
Position()
}
type noder struct{}
func (noder) Position() {}
type Scope map[int][]Node
func (s Scope) M1() Scope {
if x, ok := s[0]; ok {
return x[0].(struct {
noder
Scope
}).Scope
}
return nil
}
func (s Scope) M2() Scope {
if x, ok := s[0]; ok {
st, _ := x[0].(struct {
noder
Scope
})
return st.Scope
}
return nil
}

View File

@ -0,0 +1,13 @@
// 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
type t int
func (t) m() {}
func F1() interface{} { return struct{ t }{} }
func F2() interface{} { return *new(struct{ t }) }
func F3() interface{} { var x [1]struct{ t }; return x[0] }

View File

@ -0,0 +1,9 @@
// 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 c
import "./a"
var _ = (&a.Scope{}).M1()

View File

@ -0,0 +1,9 @@
// 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 d
import "./a"
var _ = (&a.Scope{}).M2()

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 e
import (
"./b"
)
var _ = b.F1()

View File

@ -0,0 +1,9 @@
// 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 f
import "./b"
var _ = b.F2()

View File

@ -0,0 +1,9 @@
// 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 g
import "./b"
var _ = b.F3()

View File

@ -0,0 +1,7 @@
// compiledir
// 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