]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix crawling of embeddable types during inline
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Mon, 18 Oct 2021 07:31:48 +0000 (14:31 +0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Wed, 20 Oct 2021 17:26:58 +0000 (17:26 +0000)
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>
src/cmd/compile/internal/typecheck/crawler.go
test/fixedbugs/issue49016.dir/a.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/b.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/c.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/d.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/e.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/f.go [new file with mode: 0644]
test/fixedbugs/issue49016.dir/g.go [new file with mode: 0644]
test/fixedbugs/issue49016.go [new file with mode: 0644]

index 667e76e1305d924813b806f402cc7a628bbcd9de..b214ef22799dc84c1edb40c16e0594343f03db6e 100644 (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 {
diff --git a/test/fixedbugs/issue49016.dir/a.go b/test/fixedbugs/issue49016.dir/a.go
new file mode 100644 (file)
index 0000000..36639b7
--- /dev/null
@@ -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
+}
diff --git a/test/fixedbugs/issue49016.dir/b.go b/test/fixedbugs/issue49016.dir/b.go
new file mode 100644 (file)
index 0000000..1dd63f8
--- /dev/null
@@ -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] }
diff --git a/test/fixedbugs/issue49016.dir/c.go b/test/fixedbugs/issue49016.dir/c.go
new file mode 100644 (file)
index 0000000..2cc6681
--- /dev/null
@@ -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()
diff --git a/test/fixedbugs/issue49016.dir/d.go b/test/fixedbugs/issue49016.dir/d.go
new file mode 100644 (file)
index 0000000..e933dc0
--- /dev/null
@@ -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()
diff --git a/test/fixedbugs/issue49016.dir/e.go b/test/fixedbugs/issue49016.dir/e.go
new file mode 100644 (file)
index 0000000..5f43179
--- /dev/null
@@ -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()
diff --git a/test/fixedbugs/issue49016.dir/f.go b/test/fixedbugs/issue49016.dir/f.go
new file mode 100644 (file)
index 0000000..2cd978e
--- /dev/null
@@ -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()
diff --git a/test/fixedbugs/issue49016.dir/g.go b/test/fixedbugs/issue49016.dir/g.go
new file mode 100644 (file)
index 0000000..b90353f
--- /dev/null
@@ -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()
diff --git a/test/fixedbugs/issue49016.go b/test/fixedbugs/issue49016.go
new file mode 100644 (file)
index 0000000..b83fbd7
--- /dev/null
@@ -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