Commit afe9837b authored by Marcel van Lohuizen's avatar Marcel van Lohuizen

cmd/compile/internal/gc: make embedded unexported structs RO

gc will need to be rebuild.

Package that assume f.PkgPath != nil means a field is unexported and
must be ignored must be revised to check for
	f.PkgPath != nil && !f.Anonymous,
so that they do try to walk into the embedded fields to look for
exported fields contained within.

Closes #12367, fixes #7363, fixes #11007, and fixes #7247.

Change-Id: I16402ee21ccfede80f277f84b3995cf26e97433d
Reviewed-on: https://go-review.googlesource.com/14085Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 34f04a67
......@@ -1180,7 +1180,8 @@ ok:
}
} else {
ot = dgostringptr(s, ot, "")
if t1.Type.Sym != nil && t1.Type.Sym.Pkg == builtinpkg {
if t1.Type.Sym != nil &&
(t1.Type.Sym.Pkg == builtinpkg || !exportname(t1.Type.Sym.Name)) {
ot = dgopkgpath(s, ot, localpkg)
} else {
ot = dgostringptr(s, ot, "")
......
......@@ -2776,14 +2776,27 @@ func TestSetBytes(t *testing.T) {
type Private struct {
x int
y **int
Z int
}
func (p *Private) m() {
}
type private struct {
Z int
z int
S string
A [1]Private
T []Private
}
func (p *private) P() {
}
type Public struct {
X int
Y **int
private
}
func (p *Public) M() {
......@@ -2791,17 +2804,30 @@ func (p *Public) M() {
func TestUnexported(t *testing.T) {
var pub Public
pub.S = "S"
pub.T = pub.A[:]
v := ValueOf(&pub)
isValid(v.Elem().Field(0))
isValid(v.Elem().Field(1))
isValid(v.Elem().Field(2))
isValid(v.Elem().FieldByName("X"))
isValid(v.Elem().FieldByName("Y"))
isValid(v.Elem().FieldByName("Z"))
isValid(v.Type().Method(0).Func)
m, _ := v.Type().MethodByName("M")
isValid(m.Func)
m, _ = v.Type().MethodByName("P")
isValid(m.Func)
isNonNil(v.Elem().Field(0).Interface())
isNonNil(v.Elem().Field(1).Interface())
isNonNil(v.Elem().Field(2).Field(2).Index(0))
isNonNil(v.Elem().FieldByName("X").Interface())
isNonNil(v.Elem().FieldByName("Y").Interface())
isNonNil(v.Elem().FieldByName("Z").Interface())
isNonNil(v.Elem().FieldByName("S").Index(0).Interface())
isNonNil(v.Type().Method(0).Func.Interface())
m, _ = v.Type().MethodByName("P")
isNonNil(m.Func.Interface())
var priv Private
v = ValueOf(&priv)
......@@ -2817,6 +2843,170 @@ func TestUnexported(t *testing.T) {
shouldPanic(func() { v.Type().Method(0).Func.Interface() })
}
func TestSetPanic(t *testing.T) {
ok := func(f func()) { f() }
bad := shouldPanic
clear := func(v Value) { v.Set(Zero(v.Type())) }
type t0 struct {
W int
}
type t1 struct {
Y int
t0
}
type T2 struct {
Z int
namedT0 t0
}
type T struct {
X int
t1
T2
NamedT1 t1
NamedT2 T2
namedT1 t1
namedT2 T2
}
// not addressable
v := ValueOf(T{})
bad(func() { clear(v.Field(0)) }) // .X
bad(func() { clear(v.Field(1)) }) // .t1
bad(func() { clear(v.Field(1).Field(0)) }) // .t1.Y
bad(func() { clear(v.Field(1).Field(1)) }) // .t1.t0
bad(func() { clear(v.Field(1).Field(1).Field(0)) }) // .t1.t0.W
bad(func() { clear(v.Field(2)) }) // .T2
bad(func() { clear(v.Field(2).Field(0)) }) // .T2.Z
bad(func() { clear(v.Field(2).Field(1)) }) // .T2.namedT0
bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
bad(func() { clear(v.Field(3)) }) // .NamedT1
bad(func() { clear(v.Field(3).Field(0)) }) // .NamedT1.Y
bad(func() { clear(v.Field(3).Field(1)) }) // .NamedT1.t0
bad(func() { clear(v.Field(3).Field(1).Field(0)) }) // .NamedT1.t0.W
bad(func() { clear(v.Field(4)) }) // .NamedT2
bad(func() { clear(v.Field(4).Field(0)) }) // .NamedT2.Z
bad(func() { clear(v.Field(4).Field(1)) }) // .NamedT2.namedT0
bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
bad(func() { clear(v.Field(5)) }) // .namedT1
bad(func() { clear(v.Field(5).Field(0)) }) // .namedT1.Y
bad(func() { clear(v.Field(5).Field(1)) }) // .namedT1.t0
bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
bad(func() { clear(v.Field(6)) }) // .namedT2
bad(func() { clear(v.Field(6).Field(0)) }) // .namedT2.Z
bad(func() { clear(v.Field(6).Field(1)) }) // .namedT2.namedT0
bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
// addressable
v = ValueOf(&T{}).Elem()
ok(func() { clear(v.Field(0)) }) // .X
bad(func() { clear(v.Field(1)) }) // .t1
ok(func() { clear(v.Field(1).Field(0)) }) // .t1.Y
bad(func() { clear(v.Field(1).Field(1)) }) // .t1.t0
ok(func() { clear(v.Field(1).Field(1).Field(0)) }) // .t1.t0.W
ok(func() { clear(v.Field(2)) }) // .T2
ok(func() { clear(v.Field(2).Field(0)) }) // .T2.Z
bad(func() { clear(v.Field(2).Field(1)) }) // .T2.namedT0
bad(func() { clear(v.Field(2).Field(1).Field(0)) }) // .T2.namedT0.W
ok(func() { clear(v.Field(3)) }) // .NamedT1
ok(func() { clear(v.Field(3).Field(0)) }) // .NamedT1.Y
bad(func() { clear(v.Field(3).Field(1)) }) // .NamedT1.t0
ok(func() { clear(v.Field(3).Field(1).Field(0)) }) // .NamedT1.t0.W
ok(func() { clear(v.Field(4)) }) // .NamedT2
ok(func() { clear(v.Field(4).Field(0)) }) // .NamedT2.Z
bad(func() { clear(v.Field(4).Field(1)) }) // .NamedT2.namedT0
bad(func() { clear(v.Field(4).Field(1).Field(0)) }) // .NamedT2.namedT0.W
bad(func() { clear(v.Field(5)) }) // .namedT1
bad(func() { clear(v.Field(5).Field(0)) }) // .namedT1.Y
bad(func() { clear(v.Field(5).Field(1)) }) // .namedT1.t0
bad(func() { clear(v.Field(5).Field(1).Field(0)) }) // .namedT1.t0.W
bad(func() { clear(v.Field(6)) }) // .namedT2
bad(func() { clear(v.Field(6).Field(0)) }) // .namedT2.Z
bad(func() { clear(v.Field(6).Field(1)) }) // .namedT2.namedT0
bad(func() { clear(v.Field(6).Field(1).Field(0)) }) // .namedT2.namedT0.W
}
type timp int
func (t timp) W() {}
func (t timp) Y() {}
func (t timp) w() {}
func (t timp) y() {}
func TestCallPanic(t *testing.T) {
type t0 interface {
W()
w()
}
type T1 interface {
Y()
y()
}
type T2 struct {
T1
t0
}
type T struct {
t0 // 0
T1 // 1
NamedT0 t0 // 2
NamedT1 T1 // 3
NamedT2 T2 // 4
namedT0 t0 // 5
namedT1 T1 // 6
namedT2 T2 // 7
}
ok := func(f func()) { f() }
bad := shouldPanic
call := func(v Value) { v.Call(nil) }
i := timp(0)
v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
ok(func() { call(v.Field(0).Method(0)) }) // .t0.W
ok(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
bad(func() { call(v.Field(0).Method(1)) }) // .t0.w
bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y
ok(func() { call(v.Field(1).Elem().Method(0)) }) // .T1.Y
bad(func() { call(v.Field(1).Method(1)) }) // .T1.y
bad(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y
ok(func() { call(v.Field(2).Method(0)) }) // .NamedT0.W
ok(func() { call(v.Field(2).Elem().Method(0)) }) // .NamedT0.W
bad(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w
bad(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w
ok(func() { call(v.Field(3).Method(0)) }) // .NamedT1.Y
ok(func() { call(v.Field(3).Elem().Method(0)) }) // .NamedT1.Y
bad(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W
ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W
ok(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W
bad(func() { call(v.Field(5).Method(0)) }) // .namedT0.W
bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
bad(func() { call(v.Field(5).Method(1)) }) // .namedT0.w
bad(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w
bad(func() { call(v.Field(6).Method(0)) }) // .namedT1.Y
bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.Y
bad(func() { call(v.Field(6).Method(0)) }) // .namedT1.y
bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.y
bad(func() { call(v.Field(7).Field(0).Method(0)) }) // .namedT2.T1.Y
bad(func() { call(v.Field(7).Field(0).Elem().Method(0)) }) // .namedT2.T1.W
bad(func() { call(v.Field(7).Field(1).Method(0)) }) // .namedT2.t0.W
bad(func() { call(v.Field(7).Field(1).Elem().Method(0)) }) // .namedT2.t0.W
}
func shouldPanic(f func()) {
defer func() {
if recover() == nil {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment