Skip to content

Commit 7b177b1

Browse files
committed
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 <[email protected]>
1 parent 6e59c73 commit 7b177b1

File tree

2 files changed

+66
-22
lines changed

2 files changed

+66
-22
lines changed

src/cmd/compile/internal/gc/subr.go

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,25 +1516,20 @@ func adddot(n *Node) *Node {
15161516
return n
15171517
}
15181518

1519-
// code to help generate trampoline
1520-
// functions for methods on embedded
1521-
// subtypes.
1522-
// these are approx the same as
1523-
// the corresponding adddot routines
1524-
// except that they expect to be called
1525-
// with unique tasks and they return
1526-
// the actual methods.
1519+
// Code to help generate trampoline functions for methods on embedded
1520+
// types. These are approx the same as the corresponding adddot
1521+
// routines except that they expect to be called with unique tasks and
1522+
// they return the actual methods.
1523+
15271524
type Symlink struct {
1528-
field *types.Field
1529-
followptr bool
1525+
field *types.Field
15301526
}
15311527

15321528
var slist []Symlink
15331529

1534-
func expand0(t *types.Type, followptr bool) {
1530+
func expand0(t *types.Type) {
15351531
u := t
15361532
if u.IsPtr() {
1537-
followptr = true
15381533
u = u.Elem()
15391534
}
15401535

@@ -1544,7 +1539,7 @@ func expand0(t *types.Type, followptr bool) {
15441539
continue
15451540
}
15461541
f.Sym.SetUniq(true)
1547-
slist = append(slist, Symlink{field: f, followptr: followptr})
1542+
slist = append(slist, Symlink{field: f})
15481543
}
15491544

15501545
return
@@ -1557,24 +1552,23 @@ func expand0(t *types.Type, followptr bool) {
15571552
continue
15581553
}
15591554
f.Sym.SetUniq(true)
1560-
slist = append(slist, Symlink{field: f, followptr: followptr})
1555+
slist = append(slist, Symlink{field: f})
15611556
}
15621557
}
15631558
}
15641559

1565-
func expand1(t *types.Type, top, followptr bool) {
1560+
func expand1(t *types.Type, top bool) {
15661561
if t.Recur() {
15671562
return
15681563
}
15691564
t.SetRecur(true)
15701565

15711566
if !top {
1572-
expand0(t, followptr)
1567+
expand0(t)
15731568
}
15741569

15751570
u := t
15761571
if u.IsPtr() {
1577-
followptr = true
15781572
u = u.Elem()
15791573
}
15801574

@@ -1586,7 +1580,7 @@ func expand1(t *types.Type, top, followptr bool) {
15861580
if f.Sym == nil {
15871581
continue
15881582
}
1589-
expand1(f.Type, false, followptr)
1583+
expand1(f.Type, false)
15901584
}
15911585
}
15921586

@@ -1606,7 +1600,7 @@ func expandmeth(t *types.Type) {
16061600

16071601
// generate all reachable methods
16081602
slist = slist[:0]
1609-
expand1(t, true, false)
1603+
expand1(t, true)
16101604

16111605
// check each method to be uniquely reachable
16121606
var ms []*types.Field
@@ -1615,7 +1609,8 @@ func expandmeth(t *types.Type) {
16151609
sl.field.Sym.SetUniq(false)
16161610

16171611
var f *types.Field
1618-
if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil {
1612+
path, _ := dotpath(sl.field.Sym, t, &f, false)
1613+
if path == nil {
16191614
continue
16201615
}
16211616

@@ -1627,8 +1622,11 @@ func expandmeth(t *types.Type) {
16271622
// add it to the base type method list
16281623
f = f.Copy()
16291624
f.Embedded = 1 // needs a trampoline
1630-
if sl.followptr {
1631-
f.Embedded = 2
1625+
for _, d := range path {
1626+
if d.field.Type.IsPtr() {
1627+
f.Embedded = 2
1628+
break
1629+
}
16321630
}
16331631
ms = append(ms, f)
16341632
}

test/fixedbugs/issue24547.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// run
2+
3+
// Copyright 2018 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
// When computing method sets with shadowed methods, make sure we
8+
// compute whether a method promotion involved a pointer traversal
9+
// based on the promoted method, not the shadowed method.
10+
11+
package main
12+
13+
import (
14+
"bytes"
15+
"fmt"
16+
)
17+
18+
type mystruct struct {
19+
f int
20+
}
21+
22+
func (t mystruct) String() string {
23+
return "FAIL"
24+
}
25+
26+
func main() {
27+
type deep struct {
28+
mystruct
29+
}
30+
s := struct {
31+
deep
32+
*bytes.Buffer
33+
}{
34+
deep{},
35+
bytes.NewBufferString("ok"),
36+
}
37+
38+
if got := s.String(); got != "ok" {
39+
panic(got)
40+
}
41+
42+
var i fmt.Stringer = s
43+
if got := i.String(); got != "ok" {
44+
panic(got)
45+
}
46+
}

0 commit comments

Comments
 (0)