diff options
author | Ian Lance Taylor <iant@golang.org> | 2018-09-24 21:46:21 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-09-24 21:46:21 +0000 |
commit | dd931d9b48647e898dc80927c532ae93cc09e192 (patch) | |
tree | 71be2295cd79b8a182f6130611658db8628772d5 /libgo/go/reflect | |
parent | 779d8a5ad09b01428726ea5a0e6c87bd9ac3c0e4 (diff) | |
download | gcc-dd931d9b48647e898dc80927c532ae93cc09e192.zip gcc-dd931d9b48647e898dc80927c532ae93cc09e192.tar.gz gcc-dd931d9b48647e898dc80927c532ae93cc09e192.tar.bz2 |
libgo: update to Go 1.11
Reviewed-on: https://go-review.googlesource.com/136435
gotools/:
* Makefile.am (mostlyclean-local): Run chmod on check-go-dir to
make sure it is writable.
(check-go-tools): Likewise.
(check-vet): Copy internal/objabi to check-vet-dir.
* Makefile.in: Rebuild.
From-SVN: r264546
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 98 | ||||
-rw-r--r-- | libgo/go/reflect/deepequal.go | 2 | ||||
-rw-r--r-- | libgo/go/reflect/set_test.go | 7 | ||||
-rw-r--r-- | libgo/go/reflect/type.go | 183 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 30 |
5 files changed, 203 insertions, 117 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 96b57ef..eb893e9 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -2536,9 +2536,9 @@ func TestFieldPkgPath(t *testing.T) { }{}) type pkgpathTest struct { - index []int - pkgPath string - anonymous bool + index []int + pkgPath string + embedded bool } checkPkgPath := func(name string, s []pkgpathTest) { @@ -2547,7 +2547,7 @@ func TestFieldPkgPath(t *testing.T) { if got, want := f.PkgPath, test.pkgPath; got != want { t.Errorf("%s: Field(%d).PkgPath = %q, want %q", name, test.index, got, want) } - if got, want := f.Anonymous, test.anonymous; got != want { + if got, want := f.Anonymous, test.embedded; got != want { t.Errorf("%s: Field(%d).Anonymous = %v, want %v", name, test.index, got, want) } } @@ -4833,7 +4833,20 @@ func (i StructI) Get() int { return int(i) } type StructIPtr int -func (i *StructIPtr) Get() int { return int(*i) } +func (i *StructIPtr) Get() int { return int(*i) } +func (i *StructIPtr) Set(v int) { *(*int)(i) = v } + +type SettableStruct struct { + SettableField int +} + +func (p *SettableStruct) Set(v int) { p.SettableField = v } + +type SettablePointer struct { + SettableField *int +} + +func (p *SettablePointer) Set(v int) { *p.SettableField = v } /* gccgo does not yet support StructOf with methods. @@ -4843,6 +4856,9 @@ func TestStructOfWithInterface(t *testing.T) { type Iface interface { Get() int } + type IfaceSet interface { + Set(int) + } tests := []struct { name string typ Type @@ -4904,7 +4920,7 @@ func TestStructOfWithInterface(t *testing.T) { }) // We currently do not correctly implement methods - // for anonymous fields other than the first. + // for embedded fields other than the first. // Therefore, for now, we expect those methods // to not exist. See issues 15924 and 20824. // When those issues are fixed, this test of panic @@ -4950,6 +4966,76 @@ func TestStructOfWithInterface(t *testing.T) { } } } + + // Test an embedded nil pointer with pointer methods. + fields := []StructField{{ + Name: "StructIPtr", + Anonymous: true, + Type: PtrTo(TypeOf(StructIPtr(want))), + }} + rt := StructOf(fields) + rv := New(rt).Elem() + // This should panic since the pointer is nil. + shouldPanic(func() { + rv.Interface().(IfaceSet).Set(want) + }) + + // Test an embedded nil pointer to a struct with pointer methods. + + fields = []StructField{{ + Name: "SettableStruct", + Anonymous: true, + Type: PtrTo(TypeOf(SettableStruct{})), + }} + rt = StructOf(fields) + rv = New(rt).Elem() + // This should panic since the pointer is nil. + shouldPanic(func() { + rv.Interface().(IfaceSet).Set(want) + }) + + // The behavior is different if there is a second field, + // since now an interface value holds a pointer to the struct + // rather than just holding a copy of the struct. + fields = []StructField{ + { + Name: "SettableStruct", + Anonymous: true, + Type: PtrTo(TypeOf(SettableStruct{})), + }, + { + Name: "EmptyStruct", + Anonymous: true, + Type: StructOf(nil), + }, + } + // With the current implementation this is expected to panic. + // Ideally it should work and we should be able to see a panic + // if we call the Set method. + shouldPanic(func() { + StructOf(fields) + }) + + // Embed a field that can be stored directly in an interface, + // with a second field. + fields = []StructField{ + { + Name: "SettablePointer", + Anonymous: true, + Type: TypeOf(SettablePointer{}), + }, + { + Name: "EmptyStruct", + Anonymous: true, + Type: StructOf(nil), + }, + } + // With the current implementation this is expected to panic. + // Ideally it should work and we should be able to call the + // Set and Get methods. + shouldPanic(func() { + StructOf(fields) + }) } */ diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go index 2fdd6a3..5b6694d 100644 --- a/libgo/go/reflect/deepequal.go +++ b/libgo/go/reflect/deepequal.go @@ -116,7 +116,7 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { for _, k := range v1.MapKeys() { val1 := v1.MapIndex(k) val2 := v2.MapIndex(k) - if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) { + if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(val1, val2, visited, depth+1) { return false } } diff --git a/libgo/go/reflect/set_test.go b/libgo/go/reflect/set_test.go index 7c39623..a633e6e 100644 --- a/libgo/go/reflect/set_test.go +++ b/libgo/go/reflect/set_test.go @@ -14,8 +14,6 @@ import ( "unsafe" ) -type MyBuffer bytes.Buffer - func TestImplicitMapConversion(t *testing.T) { // Test implicit conversions in MapIndex and SetMapIndex. { @@ -102,10 +100,7 @@ func TestImplicitMapConversion(t *testing.T) { } { // convert identical underlying types - // TODO(rsc): Should be able to define MyBuffer here. - // 6l prints very strange messages about .this.Bytes etc - // when we do that though, so MyBuffer is defined - // at top level. + type MyBuffer bytes.Buffer m := make(map[*MyBuffer]*bytes.Buffer) mv := ValueOf(m) b1 := new(MyBuffer) diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index bbbef91..da7796f 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -68,14 +68,15 @@ type Type interface { // NumMethod returns the number of exported methods in the type's method set. NumMethod() int - // Name returns the type's name within its package. - // It returns an empty string for unnamed types. + // Name returns the type's name within its package for a defined type. + // For other (non-defined) types it returns the empty string. Name() string - // PkgPath returns a named type's package path, that is, the import path + // PkgPath returns a defined type's package path, that is, the import path // that uniquely identifies the package, such as "encoding/base64". - // If the type was predeclared (string, error) or unnamed (*T, struct{}, []int), - // the package path will be the empty string. + // If the type was predeclared (string, error) or not defined (*T, struct{}, + // []int, or A where A is an alias for a non-defined type), the package path + // will be the empty string. PkgPath() string // Size returns the number of bytes needed to store @@ -166,13 +167,13 @@ type Type interface { // the field was found. // // FieldByNameFunc considers the fields in the struct itself - // and then the fields in any anonymous structs, in breadth first order, + // and then the fields in any embedded structs, in breadth first order, // stopping at the shallowest nesting depth containing one or more // fields satisfying the match function. If multiple fields at that depth // satisfy the match function, they cancel each other // and FieldByNameFunc returns no match. // This behavior mirrors Go's handling of name lookup in - // structs containing anonymous fields. + // structs containing embedded fields. FieldByNameFunc(match func(string) bool) (StructField, bool) // In returns the type of a function type's i'th input parameter. @@ -258,9 +259,7 @@ const ( ) // rtype is the common implementation of most values. -// It is embedded in other, public struct types, but always -// with a unique tag like `reflect:"array"` or `reflect:"ptr"` -// so that code cannot convert from, say, *arrayType to *ptrType. +// It is embedded in other struct types. // // rtype must be kept in sync with ../runtime/type.go:/^type._type. type rtype struct { @@ -290,10 +289,10 @@ type method struct { tfn unsafe.Pointer // fn used for normal method call } -// uncommonType is present only for types with names or methods -// (if T is a named type, the uncommonTypes for T and *T have methods). +// uncommonType is present only for defined types or types with methods +// (if T is a defined type, the uncommonTypes for T and *T have methods). // Using a pointer to this struct reduces the overall size required -// to describe an unnamed type with no methods. +// to describe a non-defined type with no methods. type uncommonType struct { name *string // name of type pkgPath *string // import path; nil for built-in types like int, string @@ -311,7 +310,7 @@ const ( // arrayType represents a fixed array type. type arrayType struct { - rtype `reflect:"array"` + rtype elem *rtype // array element type slice *rtype // slice type len uintptr @@ -319,14 +318,14 @@ type arrayType struct { // chanType represents a channel type. type chanType struct { - rtype `reflect:"chan"` - elem *rtype // channel element type - dir uintptr // channel direction (ChanDir) + rtype + elem *rtype // channel element type + dir uintptr // channel direction (ChanDir) } // funcType represents a function type. type funcType struct { - rtype `reflect:"func"` + rtype dotdotdot bool // last input parameter is ... in []*rtype // input parameter types out []*rtype // output parameter types @@ -341,13 +340,13 @@ type imethod struct { // interfaceType represents an interface type. type interfaceType struct { - rtype `reflect:"interface"` + rtype methods []imethod // sorted by hash } // mapType represents a map type. type mapType struct { - rtype `reflect:"map"` + rtype key *rtype // map key type elem *rtype // map element (value) type bucket *rtype // internal bucket structure @@ -362,36 +361,36 @@ type mapType struct { // ptrType represents a pointer type. type ptrType struct { - rtype `reflect:"ptr"` - elem *rtype // pointer element (pointed at) type + rtype + elem *rtype // pointer element (pointed at) type } // sliceType represents a slice type. type sliceType struct { - rtype `reflect:"slice"` - elem *rtype // slice element type + rtype + elem *rtype // slice element type } // Struct field type structField struct { - name *string // name is always non-empty - pkgPath *string // nil for exported Names; otherwise import path - typ *rtype // type of field - tag *string // nil if no tag - offsetAnon uintptr // byte offset of field<<1 | isAnonymous + name *string // name is always non-empty + pkgPath *string // nil for exported Names; otherwise import path + typ *rtype // type of field + tag *string // nil if no tag + offsetEmbed uintptr // byte offset of field<<1 | isAnonymous } func (f *structField) offset() uintptr { - return f.offsetAnon >> 1 + return f.offsetEmbed >> 1 } -func (f *structField) anon() bool { - return f.offsetAnon&1 != 0 +func (f *structField) embedded() bool { + return f.offsetEmbed&1 != 0 } // structType represents a struct type. type structType struct { - rtype `reflect:"struct"` + rtype fields []structField // sorted by offset } @@ -478,6 +477,39 @@ func (t *uncommonType) Name() string { return *t.name } +var methodCache sync.Map // map[*uncommonType][]method + +func (t *uncommonType) exportedMethods() []method { + methodsi, found := methodCache.Load(t) + if found { + return methodsi.([]method) + } + + allm := t.methods + allExported := true + for _, m := range allm { + if m.pkgPath != nil { + allExported = false + break + } + } + var methods []method + if allExported { + methods = allm + } else { + methods = make([]method, 0, len(allm)) + for _, m := range allm { + if m.pkgPath == nil { + methods = append(methods, m) + } + } + methods = methods[:len(methods):len(methods)] + } + + methodsi, _ = methodCache.LoadOrStore(t, methods) + return methodsi.([]method) +} + func (t *rtype) rawString() string { return *t.string } func (t *rtype) String() string { @@ -520,41 +552,12 @@ func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 } func (t *rtype) common() *rtype { return t } -var methodCache sync.Map // map[*rtype][]method - func (t *rtype) exportedMethods() []method { - methodsi, found := methodCache.Load(t) - if found { - return methodsi.([]method) - } - ut := t.uncommon() if ut == nil { return nil } - allm := ut.methods - allExported := true - for _, m := range allm { - if m.pkgPath != nil { - allExported = false - break - } - } - var methods []method - if allExported { - methods = allm - } else { - methods = make([]method, 0, len(allm)) - for _, m := range allm { - if m.pkgPath == nil { - methods = append(methods, m) - } - } - methods = methods[:len(methods):len(methods)] - } - - methodsi, _ = methodCache.LoadOrStore(t, methods) - return methodsi.([]method) + return ut.exportedMethods() } func (t *rtype) NumMethod() int { @@ -562,9 +565,6 @@ func (t *rtype) NumMethod() int { tt := (*interfaceType)(unsafe.Pointer(t)) return tt.NumMethod() } - if t.uncommonType == nil { - return 0 // avoid methodCache synchronization - } return len(t.exportedMethods()) } @@ -907,7 +907,7 @@ func (t *structType) Field(i int) (f StructField) { p := &t.fields[i] f.Type = toType(p.typ) f.Name = *p.name - f.Anonymous = p.anon() + f.Anonymous = p.embedded() if p.pkgPath != nil { f.PkgPath = *p.pkgPath } @@ -1001,11 +1001,11 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel visited[t] = true for i := range t.fields { f := &t.fields[i] - // Find name and (for anonymous field) type for field f. + // Find name and (for embedded field) type for field f. fname := *f.name var ntyp *rtype - if f.anon() { - // Anonymous field of type T or *T. + if f.embedded() { + // Embedded field of type T or *T. ntyp = f.typ if ntyp.Kind() == Ptr { ntyp = ntyp.Elem().common() @@ -1062,20 +1062,20 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel // FieldByName returns the struct field with the given name // and a boolean to indicate if the field was found. func (t *structType) FieldByName(name string) (f StructField, present bool) { - // Quick check for top-level name, or struct without anonymous fields. - hasAnon := false + // Quick check for top-level name, or struct without embedded fields. + hasEmbeds := false if name != "" { for i := range t.fields { tf := &t.fields[i] if *tf.name == name { return t.Field(i), true } - if tf.anon() { - hasAnon = true + if tf.embedded() { + hasEmbeds = true } } } - if !hasAnon { + if !hasEmbeds { return } return t.FieldByNameFunc(func(s string) bool { return s == name }) @@ -1274,7 +1274,7 @@ func directlyAssignable(T, V *rtype) bool { return true } - // Otherwise at least one of T and V must be unnamed + // Otherwise at least one of T and V must not be defined // and they must have the same kind. if T.Name() != "" && V.Name() != "" || T.Kind() != V.Kind() { return false @@ -1383,7 +1383,7 @@ func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool { if cmpTags && tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) { return false } - if tf.offsetAnon != vf.offsetAnon { + if tf.offsetEmbed != vf.offsetEmbed { return false } } @@ -1715,7 +1715,7 @@ func needKeyUpdate(t *rtype) bool { } } -// Make sure these routines stay in sync with ../../runtime/hashmap.go! +// Make sure these routines stay in sync with ../../runtime/map.go! // These types exist only for GC, so we only fill out GC relevant info. // Currently, that's just size and the GC program. We also fill in string // for possible debugging use. @@ -1726,7 +1726,7 @@ const ( ) func bucketOf(ktyp, etyp *rtype) *rtype { - // See comment on hmap.overflow in ../runtime/hashmap.go. + // See comment on hmap.overflow in ../runtime/map.go. var kind uint8 if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 && ktyp.size <= maxKeySize && etyp.size <= maxValSize { @@ -1907,8 +1907,9 @@ func isValidFieldName(fieldName string) bool { // The Offset and Index fields are ignored and computed as they would be // by the compiler. // -// StructOf currently does not generate wrapper methods for embedded fields. -// This limitation may be lifted in a future version. +// StructOf currently does not generate wrapper methods for embedded +// fields and panics if passed unexported StructFields. +// These limitations may be lifted in a future version. func StructOf(fields []StructField) Type { var ( hash = uint32(12) @@ -1949,7 +1950,7 @@ func StructOf(fields []StructField) Type { // Update string and hash name := *f.name hash = (hash << 1) + ft.hash - if !f.anon() { + if !f.embedded() { repr = append(repr, (" " + name)...) } else { // Embedded field @@ -1958,7 +1959,7 @@ func StructOf(fields []StructField) Type { // Embedded ** and *interface{} are illegal elem := ft.Elem() if k := elem.Kind(); k == Ptr || k == Interface { - panic("reflect.StructOf: illegal anonymous field type " + ft.String()) + panic("reflect.StructOf: illegal embedded field type " + ft.String()) } name = elem.String() } else { @@ -2012,7 +2013,7 @@ func StructOf(fields []StructField) Type { typalign = int8(ft.fieldAlign) } size = offset + ft.size - f.offsetAnon |= offset << 1 + f.offsetEmbed |= offset << 1 if ft.size == 0 { lastzero = size @@ -2197,9 +2198,9 @@ func runtimeStructField(field StructField) structField { panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath") } - offsetAnon := uintptr(0) + offsetEmbed := uintptr(0) if field.Anonymous { - offsetAnon |= 1 + offsetEmbed |= 1 } s := field.Name @@ -2212,11 +2213,11 @@ func runtimeStructField(field StructField) structField { } return structField{ - name: name, - pkgPath: nil, - typ: field.Type.common(), - tag: tag, - offsetAnon: offsetAnon, + name: name, + pkgPath: nil, + typ: field.Type.common(), + tag: tag, + offsetEmbed: offsetEmbed, } } diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 3682b39..5ddd30d 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -632,7 +632,7 @@ func (v Value) Field(i int) Value { fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind()) // Using an unexported field forces flagRO. if field.pkgPath != nil { - if field.anon() { + if field.embedded() { fl |= flagEmbedRO } else { fl |= flagStickyRO @@ -1078,7 +1078,7 @@ func overflowFloat32(x float64) bool { } // OverflowInt reports whether the int64 x cannot be represented by v's type. -// It panics if v's Kind is not Int, Int8, int16, Int32, or Int64. +// It panics if v's Kind is not Int, Int8, Int16, Int32, or Int64. func (v Value) OverflowInt(x int64) bool { k := v.kind() switch k { @@ -1942,7 +1942,7 @@ func MakeSlice(typ Type, len, cap int) Value { } s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap} - return Value{typ.common(), unsafe.Pointer(&s), flagIndir | flag(Slice)} + return Value{typ.(*rtype), unsafe.Pointer(&s), flagIndir | flag(Slice)} } // MakeChan creates a new channel with the specified type and buffer size. @@ -1956,8 +1956,9 @@ func MakeChan(typ Type, buffer int) Value { if typ.ChanDir() != BothDir { panic("reflect.MakeChan: unidirectional channel type") } - ch := makechan(typ.(*rtype), buffer) - return Value{typ.common(), unsafe.Pointer(&ch), flag(Chan) | flagIndir} + t := typ.(*rtype) + ch := makechan(t, buffer) + return Value{t, unsafe.Pointer(&ch), flag(Chan) | flagIndir} } // MakeMap creates a new map with the specified type. @@ -1971,8 +1972,9 @@ func MakeMapWithSize(typ Type, n int) Value { if typ.Kind() != Map { panic("reflect.MakeMapWithSize of non-map type") } - m := makemap(typ.(*rtype), n) - return Value{typ.common(), unsafe.Pointer(&m), flag(Map) | flagIndir} + t := typ.(*rtype) + m := makemap(t, n) + return Value{t, unsafe.Pointer(&m), flag(Map) | flagIndir} } // Indirect returns the value that v points to. @@ -2010,10 +2012,10 @@ func Zero(typ Type) Value { if typ == nil { panic("reflect: Zero(nil)") } - t := typ.common() + t := typ.(*rtype) fl := flag(t.Kind()) if ifaceIndir(t) { - return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir} + return Value{t, unsafe_New(t), fl | flagIndir} } return Value{t, nil, fl} } @@ -2024,16 +2026,18 @@ func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") } - ptr := unsafe_New(typ.(*rtype)) + t := typ.(*rtype) + ptr := unsafe_New(t) fl := flag(Ptr) - return Value{typ.common().ptrTo(), ptr, fl} + return Value{t.ptrTo(), ptr, fl} } // NewAt returns a Value representing a pointer to a value of the // specified type, using p as that pointer. func NewAt(typ Type, p unsafe.Pointer) Value { fl := flag(Ptr) - return Value{typ.common().ptrTo(), p, fl} + t := typ.(*rtype) + return Value{t.ptrTo(), p, fl} } // assignTo returns a value v that can be assigned directly to typ. @@ -2155,7 +2159,7 @@ func convertOp(dst, src *rtype) func(Value, Type) Value { return cvtDirect } - // dst and src are unnamed pointer types with same underlying base type. + // dst and src are non-defined pointer types with same underlying base type. if dst.Kind() == Ptr && dst.Name() == "" && src.Kind() == Ptr && src.Name() == "" && haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common(), false) { |