mirror of git://gcc.gnu.org/git/gcc.git
re PR go/66138 (json decoder Decode function fails for some structure return values)
PR go/66138
reflect, encoding/json, encoding/xml: fix unexported embedded structs
Bring in three changes from the master Go repository. These changes
will be in Go 1.6, but they are appropriate for gccgo now because they
resolve a long-standing discrepancy between how gc and gccgo handle the
PkgPath field for embedded unexported struct fields. The core issue is
described at https://golang.org/cl/7247. This has been reported against
gccgo as https://gcc.gnu.org/PR66138.
The three changes being brought over are:
https://golang.org/cl/14010
reflect: adjust access to unexported embedded structs
This CL changes reflect to allow access to exported fields and
methods in unexported embedded structs for gccgo and after gc
has been adjusted to disallow access to embedded unexported structs.
Adresses #12367, #7363, #11007, and #7247.
https://golang.org/cl/14011
encoding/json: check for exported fields in embedded structs
Addresses issue #12367.
https://golang.org/cl/14012
encoding/xml: check for exported fields in embedded structs
Addresses issue #12367.
Reviewed-on: https://go-review.googlesource.com/16723
From-SVN: r229907
This commit is contained in:
parent
39f02a1f52
commit
f5eb9a8ec6
|
|
@ -1,4 +1,4 @@
|
||||||
10c1d6756ed1dcc814c49921c2a5e27f4677e0e6
|
012ab5cb2ef1c26e8023ce90d3a2bba174da7b30
|
||||||
|
|
||||||
The first line of this file holds the git revision number of the last
|
The first line of this file holds the git revision number of the last
|
||||||
merge done from the gofrontend repository.
|
merge done from the gofrontend repository.
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ type Top struct {
|
||||||
Loop
|
Loop
|
||||||
Embed0p // has Point with X, Y, used
|
Embed0p // has Point with X, Y, used
|
||||||
Embed0q // has Point with Z, used
|
Embed0q // has Point with Z, used
|
||||||
|
embed // contains exported field
|
||||||
}
|
}
|
||||||
|
|
||||||
type Embed0 struct {
|
type Embed0 struct {
|
||||||
|
|
@ -148,6 +149,10 @@ type Embed0q struct {
|
||||||
Point
|
Point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type embed struct {
|
||||||
|
Q int
|
||||||
|
}
|
||||||
|
|
||||||
type Loop struct {
|
type Loop struct {
|
||||||
Loop1 int `json:",omitempty"`
|
Loop1 int `json:",omitempty"`
|
||||||
Loop2 int `json:",omitempty"`
|
Loop2 int `json:",omitempty"`
|
||||||
|
|
@ -331,7 +336,8 @@ var unmarshalTests = []unmarshalTest{
|
||||||
"Loop2": 14,
|
"Loop2": 14,
|
||||||
"X": 15,
|
"X": 15,
|
||||||
"Y": 16,
|
"Y": 16,
|
||||||
"Z": 17
|
"Z": 17,
|
||||||
|
"Q": 18
|
||||||
}`,
|
}`,
|
||||||
ptr: new(Top),
|
ptr: new(Top),
|
||||||
out: Top{
|
out: Top{
|
||||||
|
|
@ -361,6 +367,9 @@ var unmarshalTests = []unmarshalTest{
|
||||||
Embed0q: Embed0q{
|
Embed0q: Embed0q{
|
||||||
Point: Point{Z: 17},
|
Point: Point{Z: 17},
|
||||||
},
|
},
|
||||||
|
embed: embed{
|
||||||
|
Q: 18,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -507,12 +516,15 @@ func TestMarshalEmbeds(t *testing.T) {
|
||||||
Embed0q: Embed0q{
|
Embed0q: Embed0q{
|
||||||
Point: Point{Z: 17},
|
Point: Point{Z: 17},
|
||||||
},
|
},
|
||||||
|
embed: embed{
|
||||||
|
Q: 18,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
b, err := Marshal(top)
|
b, err := Marshal(top)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17}"
|
want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17,\"Q\":18}"
|
||||||
if string(b) != want {
|
if string(b) != want {
|
||||||
t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want)
|
t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1022,7 +1022,7 @@ func typeFields(t reflect.Type) []field {
|
||||||
// Scan f.typ for fields to include.
|
// Scan f.typ for fields to include.
|
||||||
for i := 0; i < f.typ.NumField(); i++ {
|
for i := 0; i < f.typ.NumField(); i++ {
|
||||||
sf := f.typ.Field(i)
|
sf := f.typ.Field(i)
|
||||||
if sf.PkgPath != "" { // unexported
|
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tag := sf.Tag.Get("json")
|
tag := sf.Tag.Get("json")
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ type EmbedA struct {
|
||||||
EmbedC
|
EmbedC
|
||||||
EmbedB EmbedB
|
EmbedB EmbedB
|
||||||
FieldA string
|
FieldA string
|
||||||
|
embedD
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmbedB struct {
|
type EmbedB struct {
|
||||||
|
|
@ -153,6 +154,11 @@ type EmbedC struct {
|
||||||
FieldC string
|
FieldC string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type embedD struct {
|
||||||
|
fieldD string
|
||||||
|
FieldE string // Promoted and visible when embedD is embedded.
|
||||||
|
}
|
||||||
|
|
||||||
type NameCasing struct {
|
type NameCasing struct {
|
||||||
XMLName struct{} `xml:"casing"`
|
XMLName struct{} `xml:"casing"`
|
||||||
Xy string
|
Xy string
|
||||||
|
|
@ -711,6 +717,9 @@ var marshalTests = []struct {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
FieldA: "A.A",
|
FieldA: "A.A",
|
||||||
|
embedD: embedD{
|
||||||
|
FieldE: "A.D.E",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ExpectXML: `<EmbedA>` +
|
ExpectXML: `<EmbedA>` +
|
||||||
`<FieldB>A.C.B</FieldB>` +
|
`<FieldB>A.C.B</FieldB>` +
|
||||||
|
|
@ -724,6 +733,7 @@ var marshalTests = []struct {
|
||||||
`<FieldC>A.B.C.C</FieldC>` +
|
`<FieldC>A.B.C.C</FieldC>` +
|
||||||
`</EmbedB>` +
|
`</EmbedB>` +
|
||||||
`<FieldA>A.A</FieldA>` +
|
`<FieldA>A.A</FieldA>` +
|
||||||
|
`<FieldE>A.D.E</FieldE>` +
|
||||||
`</EmbedA>`,
|
`</EmbedA>`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
|
||||||
n := typ.NumField()
|
n := typ.NumField()
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
f := typ.Field(i)
|
f := typ.Field(i)
|
||||||
if f.PkgPath != "" || f.Tag.Get("xml") == "-" {
|
if (f.PkgPath != "" && !f.Anonymous) || f.Tag.Get("xml") == "-" {
|
||||||
continue // Private field
|
continue // Private field
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ package reflect
|
||||||
|
|
||||||
// MakeRO returns a copy of v with the read-only flag set.
|
// MakeRO returns a copy of v with the read-only flag set.
|
||||||
func MakeRO(v Value) Value {
|
func MakeRO(v Value) Value {
|
||||||
v.flag |= flagRO
|
v.flag |= flagStickyRO
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsRO reports whether v's read-only flag is set.
|
// IsRO reports whether v's read-only flag is set.
|
||||||
func IsRO(v Value) bool {
|
func IsRO(v Value) bool {
|
||||||
return v.flag&flagRO != 0
|
return v.flag&flagStickyRO != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var CallGC = &callGC
|
var CallGC = &callGC
|
||||||
|
|
|
||||||
|
|
@ -516,7 +516,7 @@ func (t *uncommonType) Method(i int) (m Method) {
|
||||||
fl := flag(Func)
|
fl := flag(Func)
|
||||||
if p.pkgPath != nil {
|
if p.pkgPath != nil {
|
||||||
m.PkgPath = *p.pkgPath
|
m.PkgPath = *p.pkgPath
|
||||||
fl |= flagRO
|
fl |= flagStickyRO
|
||||||
}
|
}
|
||||||
mt := p.typ
|
mt := p.typ
|
||||||
m.Type = toType(mt)
|
m.Type = toType(mt)
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ type Value struct {
|
||||||
|
|
||||||
// flag holds metadata about the value.
|
// flag holds metadata about the value.
|
||||||
// The lowest bits are flag bits:
|
// The lowest bits are flag bits:
|
||||||
// - flagRO: obtained via unexported field, so read-only
|
// - flagStickyRO: obtained via unexported not embedded field, so read-only
|
||||||
|
// - flagEmbedRO: obtained via unexported embedded field, so read-only
|
||||||
// - flagIndir: val holds a pointer to the data
|
// - flagIndir: val holds a pointer to the data
|
||||||
// - flagAddr: v.CanAddr is true (implies flagIndir)
|
// - flagAddr: v.CanAddr is true (implies flagIndir)
|
||||||
// - flagMethod: v is a method value.
|
// - flagMethod: v is a method value.
|
||||||
|
|
@ -67,12 +68,14 @@ type flag uintptr
|
||||||
const (
|
const (
|
||||||
flagKindWidth = 5 // there are 27 kinds
|
flagKindWidth = 5 // there are 27 kinds
|
||||||
flagKindMask flag = 1<<flagKindWidth - 1
|
flagKindMask flag = 1<<flagKindWidth - 1
|
||||||
flagRO flag = 1 << 5
|
flagStickyRO flag = 1 << 5
|
||||||
flagIndir flag = 1 << 6
|
flagEmbedRO flag = 1 << 6
|
||||||
flagAddr flag = 1 << 7
|
flagIndir flag = 1 << 7
|
||||||
flagMethod flag = 1 << 8
|
flagAddr flag = 1 << 8
|
||||||
flagMethodFn flag = 1 << 9 // gccgo: first fn parameter is always pointer
|
flagMethod flag = 1 << 9
|
||||||
flagMethodShift = 10
|
flagMethodFn flag = 1 << 10 // gccgo: first fn parameter is always pointer
|
||||||
|
flagMethodShift = 11
|
||||||
|
flagRO flag = flagStickyRO | flagEmbedRO
|
||||||
)
|
)
|
||||||
|
|
||||||
func (f flag) kind() Kind {
|
func (f flag) kind() Kind {
|
||||||
|
|
@ -617,11 +620,15 @@ func (v Value) Field(i int) Value {
|
||||||
field := &tt.fields[i]
|
field := &tt.fields[i]
|
||||||
typ := field.typ
|
typ := field.typ
|
||||||
|
|
||||||
// Inherit permission bits from v.
|
// Inherit permission bits from v, but clear flagEmbedRO.
|
||||||
fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind())
|
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
|
||||||
// Using an unexported field forces flagRO.
|
// Using an unexported field forces flagRO.
|
||||||
if field.pkgPath != nil {
|
if field.pkgPath != nil {
|
||||||
fl |= flagRO
|
if field.name == nil {
|
||||||
|
fl |= flagEmbedRO
|
||||||
|
} else {
|
||||||
|
fl |= flagStickyRO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Either flagIndir is set and v.ptr points at struct,
|
// Either flagIndir is set and v.ptr points at struct,
|
||||||
// or flagIndir is not set and v.ptr is the actual struct data.
|
// or flagIndir is not set and v.ptr is the actual struct data.
|
||||||
|
|
@ -986,7 +993,7 @@ func (v Value) Method(i int) Value {
|
||||||
if v.typ.Kind() == Interface && v.IsNil() {
|
if v.typ.Kind() == Interface && v.IsNil() {
|
||||||
panic("reflect: Method on nil interface value")
|
panic("reflect: Method on nil interface value")
|
||||||
}
|
}
|
||||||
fl := v.flag & (flagRO | flagIndir)
|
fl := v.flag & (flagStickyRO | flagIndir) // Clear flagEmbedRO
|
||||||
fl |= flag(Func)
|
fl |= flag(Func)
|
||||||
fl |= flag(i)<<flagMethodShift | flagMethod
|
fl |= flag(i)<<flagMethodShift | flagMethod
|
||||||
return Value{v.typ, v.ptr, fl}
|
return Value{v.typ, v.ptr, fl}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue