]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR go/66138 (json decoder Decode function fails for some structure return values)
authorIan Lance Taylor <ian@gcc.gnu.org>
Sat, 7 Nov 2015 01:24:57 +0000 (01:24 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Sat, 7 Nov 2015 01:24:57 +0000 (01:24 +0000)
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

gcc/go/gofrontend/MERGE
libgo/go/encoding/json/decode_test.go
libgo/go/encoding/json/encode.go
libgo/go/encoding/xml/marshal_test.go
libgo/go/encoding/xml/typeinfo.go
libgo/go/reflect/export_test.go
libgo/go/reflect/type.go
libgo/go/reflect/value.go

index b17ca93b24ca567913ed4015f89c894d6348e278..f325bb33ecbfb73330f187a674cff8858ffbf0f2 100644 (file)
@@ -1,4 +1,4 @@
-10c1d6756ed1dcc814c49921c2a5e27f4677e0e6
+012ab5cb2ef1c26e8023ce90d3a2bba174da7b30
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 8aa158f08cdade6f9fe7f2d3caa91382bb646a1a..51b15ef997cb4f593185971652ffa74723519b5a 100644 (file)
@@ -118,6 +118,7 @@ type Top struct {
        Loop
        Embed0p // has Point with X, Y, used
        Embed0q // has Point with Z, used
+       embed   // contains exported field
 }
 
 type Embed0 struct {
@@ -148,6 +149,10 @@ type Embed0q struct {
        Point
 }
 
+type embed struct {
+       Q int
+}
+
 type Loop struct {
        Loop1 int `json:",omitempty"`
        Loop2 int `json:",omitempty"`
@@ -331,7 +336,8 @@ var unmarshalTests = []unmarshalTest{
                        "Loop2": 14,
                        "X": 15,
                        "Y": 16,
-                       "Z": 17
+                       "Z": 17,
+                       "Q": 18
                }`,
                ptr: new(Top),
                out: Top{
@@ -361,6 +367,9 @@ var unmarshalTests = []unmarshalTest{
                        Embed0q: Embed0q{
                                Point: Point{Z: 17},
                        },
+                       embed: embed{
+                               Q: 18,
+                       },
                },
        },
        {
@@ -507,12 +516,15 @@ func TestMarshalEmbeds(t *testing.T) {
                Embed0q: Embed0q{
                        Point: Point{Z: 17},
                },
+               embed: embed{
+                       Q: 18,
+               },
        }
        b, err := Marshal(top)
        if err != nil {
                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 {
                t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want)
        }
index 90782deb70be7aedbcc837d5427a201bb7ff35da..e829a930768ba1e00793fdda131fed156834cdfc 100644 (file)
@@ -1022,7 +1022,7 @@ func typeFields(t reflect.Type) []field {
                        // Scan f.typ for fields to include.
                        for i := 0; i < f.typ.NumField(); i++ {
                                sf := f.typ.Field(i)
-                               if sf.PkgPath != "" { // unexported
+                               if sf.PkgPath != "" && !sf.Anonymous { // unexported
                                        continue
                                }
                                tag := sf.Tag.Get("json")
index 66675d7abc409e8f39f4ffa523e098589cb6e1a3..ef6c20e949b3139f4973c323c52cdf393610cdc7 100644 (file)
@@ -139,6 +139,7 @@ type EmbedA struct {
        EmbedC
        EmbedB EmbedB
        FieldA string
+       embedD
 }
 
 type EmbedB struct {
@@ -153,6 +154,11 @@ type EmbedC struct {
        FieldC  string
 }
 
+type embedD struct {
+       fieldD string
+       FieldE string // Promoted and visible when embedD is embedded.
+}
+
 type NameCasing struct {
        XMLName struct{} `xml:"casing"`
        Xy      string
@@ -711,6 +717,9 @@ var marshalTests = []struct {
                                },
                        },
                        FieldA: "A.A",
+                       embedD: embedD{
+                               FieldE: "A.D.E",
+                       },
                },
                ExpectXML: `<EmbedA>` +
                        `<FieldB>A.C.B</FieldB>` +
@@ -724,6 +733,7 @@ var marshalTests = []struct {
                        `<FieldC>A.B.C.C</FieldC>` +
                        `</EmbedB>` +
                        `<FieldA>A.A</FieldA>` +
+                       `<FieldE>A.D.E</FieldE>` +
                        `</EmbedA>`,
        },
 
index 22248d20a6d669e348c93f7d4b5feb558eee8e6d..6766b88f09a194546589ca2f320dcc063d62ea0f 100644 (file)
@@ -60,7 +60,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
                n := typ.NumField()
                for i := 0; i < n; i++ {
                        f := typ.Field(i)
-                       if f.PkgPath != "" || f.Tag.Get("xml") == "-" {
+                       if (f.PkgPath != "" && !f.Anonymous) || f.Tag.Get("xml") == "-" {
                                continue // Private field
                        }
 
index 89473d352a72b14865fbe9937c1c403862ee188b..bdbd60074acbff39bf4775979923937374cbf334 100644 (file)
@@ -6,13 +6,13 @@ package reflect
 
 // MakeRO returns a copy of v with the read-only flag set.
 func MakeRO(v Value) Value {
-       v.flag |= flagRO
+       v.flag |= flagStickyRO
        return v
 }
 
 // IsRO reports whether v's read-only flag is set.
 func IsRO(v Value) bool {
-       return v.flag&flagRO != 0
+       return v.flag&flagStickyRO != 0
 }
 
 var CallGC = &callGC
index e488938a13f1822c3b1f65b08a5ee2356d3ac809..180a364de35e48b25d884d92d75d975777109d12 100644 (file)
@@ -516,7 +516,7 @@ func (t *uncommonType) Method(i int) (m Method) {
        fl := flag(Func)
        if p.pkgPath != nil {
                m.PkgPath = *p.pkgPath
-               fl |= flagRO
+               fl |= flagStickyRO
        }
        mt := p.typ
        m.Type = toType(mt)
index a924d8639a228a0e4d311998bf9efd590ce85d61..8374370cfa66db4e9bc6afb23db21b9d6a7268c0 100644 (file)
@@ -44,7 +44,8 @@ type Value struct {
 
        // flag holds metadata about the value.
        // 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
        //      - flagAddr: v.CanAddr is true (implies flagIndir)
        //      - flagMethod: v is a method value.
@@ -67,12 +68,14 @@ type flag uintptr
 const (
        flagKindWidth        = 5 // there are 27 kinds
        flagKindMask    flag = 1<<flagKindWidth - 1
-       flagRO          flag = 1 << 5
-       flagIndir       flag = 1 << 6
-       flagAddr        flag = 1 << 7
-       flagMethod      flag = 1 << 8
-       flagMethodFn    flag = 1 << 9 // gccgo: first fn parameter is always pointer
-       flagMethodShift      = 10
+       flagStickyRO    flag = 1 << 5
+       flagEmbedRO     flag = 1 << 6
+       flagIndir       flag = 1 << 7
+       flagAddr        flag = 1 << 8
+       flagMethod      flag = 1 << 9
+       flagMethodFn    flag = 1 << 10 // gccgo: first fn parameter is always pointer
+       flagMethodShift      = 11
+       flagRO          flag = flagStickyRO | flagEmbedRO
 )
 
 func (f flag) kind() Kind {
@@ -617,11 +620,15 @@ func (v Value) Field(i int) Value {
        field := &tt.fields[i]
        typ := field.typ
 
-       // Inherit permission bits from v.
-       fl := v.flag&(flagRO|flagIndir|flagAddr) | flag(typ.Kind())
+       // Inherit permission bits from v, but clear flagEmbedRO.
+       fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
        // Using an unexported field forces flagRO.
        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,
        // 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() {
                panic("reflect: Method on nil interface value")
        }
-       fl := v.flag & (flagRO | flagIndir)
+       fl := v.flag & (flagStickyRO | flagIndir) // Clear flagEmbedRO
        fl |= flag(Func)
        fl |= flag(i)<<flagMethodShift | flagMethod
        return Value{v.typ, v.ptr, fl}