mirror of
https://github.com/golang/go
synced 2024-10-14 20:05:36 +00:00
cmd/compile: fix method set computation for shadowed methods
In expandmeth, we call expand1/expand0 to build a list of all candidate methods to promote, and then we use dotpath to prune down which names actually resolve to a promoted method and how. However, previously we still computed "followsptr" based on the expand1/expand0 traversal (which is depth-first), rather than dotpath (which is breadth-first). The result is that we could sometimes end up miscomputing whether a particular promoted method involves a pointer traversal, which could result in bad code generation for method trampolines. Fixes #24547. Change-Id: I57dc014466d81c165b05d78b98610dc3765b7a90 Reviewed-on: https://go-review.googlesource.com/102618 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
6e59c73a9f
commit
7b177b1a03
|
@ -1516,25 +1516,20 @@ func adddot(n *Node) *Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// code to help generate trampoline
|
// Code to help generate trampoline functions for methods on embedded
|
||||||
// functions for methods on embedded
|
// types. These are approx the same as the corresponding adddot
|
||||||
// subtypes.
|
// routines except that they expect to be called with unique tasks and
|
||||||
// these are approx the same as
|
// they return the actual methods.
|
||||||
// the corresponding adddot routines
|
|
||||||
// except that they expect to be called
|
|
||||||
// with unique tasks and they return
|
|
||||||
// the actual methods.
|
|
||||||
type Symlink struct {
|
type Symlink struct {
|
||||||
field *types.Field
|
field *types.Field
|
||||||
followptr bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var slist []Symlink
|
var slist []Symlink
|
||||||
|
|
||||||
func expand0(t *types.Type, followptr bool) {
|
func expand0(t *types.Type) {
|
||||||
u := t
|
u := t
|
||||||
if u.IsPtr() {
|
if u.IsPtr() {
|
||||||
followptr = true
|
|
||||||
u = u.Elem()
|
u = u.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1544,7 +1539,7 @@ func expand0(t *types.Type, followptr bool) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.Sym.SetUniq(true)
|
f.Sym.SetUniq(true)
|
||||||
slist = append(slist, Symlink{field: f, followptr: followptr})
|
slist = append(slist, Symlink{field: f})
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -1557,24 +1552,23 @@ func expand0(t *types.Type, followptr bool) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f.Sym.SetUniq(true)
|
f.Sym.SetUniq(true)
|
||||||
slist = append(slist, Symlink{field: f, followptr: followptr})
|
slist = append(slist, Symlink{field: f})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expand1(t *types.Type, top, followptr bool) {
|
func expand1(t *types.Type, top bool) {
|
||||||
if t.Recur() {
|
if t.Recur() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.SetRecur(true)
|
t.SetRecur(true)
|
||||||
|
|
||||||
if !top {
|
if !top {
|
||||||
expand0(t, followptr)
|
expand0(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
u := t
|
u := t
|
||||||
if u.IsPtr() {
|
if u.IsPtr() {
|
||||||
followptr = true
|
|
||||||
u = u.Elem()
|
u = u.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1586,7 +1580,7 @@ func expand1(t *types.Type, top, followptr bool) {
|
||||||
if f.Sym == nil {
|
if f.Sym == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
expand1(f.Type, false, followptr)
|
expand1(f.Type, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1606,7 +1600,7 @@ func expandmeth(t *types.Type) {
|
||||||
|
|
||||||
// generate all reachable methods
|
// generate all reachable methods
|
||||||
slist = slist[:0]
|
slist = slist[:0]
|
||||||
expand1(t, true, false)
|
expand1(t, true)
|
||||||
|
|
||||||
// check each method to be uniquely reachable
|
// check each method to be uniquely reachable
|
||||||
var ms []*types.Field
|
var ms []*types.Field
|
||||||
|
@ -1615,7 +1609,8 @@ func expandmeth(t *types.Type) {
|
||||||
sl.field.Sym.SetUniq(false)
|
sl.field.Sym.SetUniq(false)
|
||||||
|
|
||||||
var f *types.Field
|
var f *types.Field
|
||||||
if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil {
|
path, _ := dotpath(sl.field.Sym, t, &f, false)
|
||||||
|
if path == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1627,8 +1622,11 @@ func expandmeth(t *types.Type) {
|
||||||
// add it to the base type method list
|
// add it to the base type method list
|
||||||
f = f.Copy()
|
f = f.Copy()
|
||||||
f.Embedded = 1 // needs a trampoline
|
f.Embedded = 1 // needs a trampoline
|
||||||
if sl.followptr {
|
for _, d := range path {
|
||||||
f.Embedded = 2
|
if d.field.Type.IsPtr() {
|
||||||
|
f.Embedded = 2
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ms = append(ms, f)
|
ms = append(ms, f)
|
||||||
}
|
}
|
||||||
|
|
46
test/fixedbugs/issue24547.go
Normal file
46
test/fixedbugs/issue24547.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// run
|
||||||
|
|
||||||
|
// Copyright 2018 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.
|
||||||
|
|
||||||
|
// When computing method sets with shadowed methods, make sure we
|
||||||
|
// compute whether a method promotion involved a pointer traversal
|
||||||
|
// based on the promoted method, not the shadowed method.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mystruct struct {
|
||||||
|
f int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t mystruct) String() string {
|
||||||
|
return "FAIL"
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type deep struct {
|
||||||
|
mystruct
|
||||||
|
}
|
||||||
|
s := struct {
|
||||||
|
deep
|
||||||
|
*bytes.Buffer
|
||||||
|
}{
|
||||||
|
deep{},
|
||||||
|
bytes.NewBufferString("ok"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := s.String(); got != "ok" {
|
||||||
|
panic(got)
|
||||||
|
}
|
||||||
|
|
||||||
|
var i fmt.Stringer = s
|
||||||
|
if got := i.String(); got != "ok" {
|
||||||
|
panic(got)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue