diff options
author | Ian Lance Taylor <iant@golang.org> | 2019-01-18 19:04:36 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-01-18 19:04:36 +0000 |
commit | 4f4a855d82a889cebcfca150a7a43909bcb6a346 (patch) | |
tree | f12bae0781920fa34669fe30b6f4615a86d9fb80 /libgo/go/reflect | |
parent | 225220d668dafb8262db7012bced688acbe63b33 (diff) | |
download | gcc-4f4a855d82a889cebcfca150a7a43909bcb6a346.zip gcc-4f4a855d82a889cebcfca150a7a43909bcb6a346.tar.gz gcc-4f4a855d82a889cebcfca150a7a43909bcb6a346.tar.bz2 |
libgo: update to Go1.12beta2
Reviewed-on: https://go-review.googlesource.com/c/158019
gotools/:
* Makefile.am (go_cmd_vet_files): Update for Go1.12beta2 release.
(GOTOOLS_TEST_TIMEOUT): Increase to 600.
(check-runtime): Export LD_LIBRARY_PATH before computing GOARCH
and GOOS.
(check-vet): Copy golang.org/x/tools into check-vet-dir.
* Makefile.in: Regenerate.
gcc/testsuite/:
* go.go-torture/execute/names-1.go: Stop using debug/xcoff, which
is no longer externally visible.
From-SVN: r268084
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 146 | ||||
-rw-r--r-- | libgo/go/reflect/example_test.go | 18 | ||||
-rw-r--r-- | libgo/go/reflect/type.go | 3 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 110 |
4 files changed, 254 insertions, 23 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 472988f..599ab27 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -1009,6 +1009,7 @@ func TestIsNil(t *testing.T) { struct{ x func() bool }{}, struct{ x chan int }{}, struct{ x []string }{}, + struct{ x unsafe.Pointer }{}, } for _, ts := range doNil { ty := TypeOf(ts).Field(0).Type @@ -1696,9 +1697,9 @@ func TestCallReturnsEmpty(t *testing.T) { // nonzero-sized frame and zero-sized return value. runtime.GC() var finalized uint32 - f := func() (emptyStruct, *int) { - i := new(int) - runtime.SetFinalizer(i, func(*int) { atomic.StoreUint32(&finalized, 1) }) + f := func() (emptyStruct, *[2]int64) { + i := new([2]int64) // big enough to not be tinyalloc'd, so finalizer always runs when i dies + runtime.SetFinalizer(i, func(*[2]int64) { atomic.StoreUint32(&finalized, 1) }) return emptyStruct{}, i } v := ValueOf(f).Call(nil)[0] // out[0] should not alias out[1]'s memory, so the finalizer should run. @@ -5039,6 +5040,21 @@ func TestStructOfWithInterface(t *testing.T) { } */ +func TestStructOfTooManyFields(t *testing.T) { + if runtime.Compiler == "gccgo" { + t.Skip("gccgo does not yet implement embedded fields with methods") + } + + // Bug Fix: #25402 - this should not panic + tt := StructOf([]StructField{ + {Name: "Time", Type: TypeOf(time.Time{}), Anonymous: true}, + }) + + if _, present := tt.MethodByName("After"); !present { + t.Errorf("Expected method `After` to be found") + } +} + func TestChanOf(t *testing.T) { // check construction and use of type not in binary type T string @@ -6009,7 +6025,8 @@ func TestFuncLayout(t *testing.T) { func verifyGCBits(t *testing.T, typ Type, bits []byte) { heapBits := GCBits(New(typ).Interface()) if !bytes.Equal(heapBits, bits) { - t.Errorf("heapBits incorrect for %v\nhave %v\nwant %v", typ, heapBits, bits) + _, _, line, _ := runtime.Caller(1) + t.Errorf("line %d: heapBits incorrect for %v\nhave %v\nwant %v", line, typ, heapBits, bits) } } @@ -6610,3 +6627,124 @@ func TestIssue22073(t *testing.T) { // Shouldn't panic. m.Call(nil) } + +func TestMapIterNonEmptyMap(t *testing.T) { + m := map[string]int{"one": 1, "two": 2, "three": 3} + iter := ValueOf(m).MapRange() + if got, want := iterateToString(iter), `[one: 1, three: 3, two: 2]`; got != want { + t.Errorf("iterator returned %s (after sorting), want %s", got, want) + } +} + +func TestMapIterNilMap(t *testing.T) { + var m map[string]int + iter := ValueOf(m).MapRange() + if got, want := iterateToString(iter), `[]`; got != want { + t.Errorf("non-empty result iteratoring nil map: %s", got) + } +} + +func TestMapIterSafety(t *testing.T) { + // Using a zero MapIter causes a panic, but not a crash. + func() { + defer func() { recover() }() + new(MapIter).Key() + t.Fatal("Key did not panic") + }() + func() { + defer func() { recover() }() + new(MapIter).Value() + t.Fatal("Value did not panic") + }() + func() { + defer func() { recover() }() + new(MapIter).Next() + t.Fatal("Next did not panic") + }() + + // Calling Key/Value on a MapIter before Next + // causes a panic, but not a crash. + var m map[string]int + iter := ValueOf(m).MapRange() + + func() { + defer func() { recover() }() + iter.Key() + t.Fatal("Key did not panic") + }() + func() { + defer func() { recover() }() + iter.Value() + t.Fatal("Value did not panic") + }() + + // Calling Next, Key, or Value on an exhausted iterator + // causes a panic, but not a crash. + iter.Next() // -> false + func() { + defer func() { recover() }() + iter.Key() + t.Fatal("Key did not panic") + }() + func() { + defer func() { recover() }() + iter.Value() + t.Fatal("Value did not panic") + }() + func() { + defer func() { recover() }() + iter.Next() + t.Fatal("Next did not panic") + }() +} + +func TestMapIterNext(t *testing.T) { + // The first call to Next should reflect any + // insertions to the map since the iterator was created. + m := map[string]int{} + iter := ValueOf(m).MapRange() + m["one"] = 1 + if got, want := iterateToString(iter), `[one: 1]`; got != want { + t.Errorf("iterator returned deleted elements: got %s, want %s", got, want) + } +} + +func TestMapIterDelete0(t *testing.T) { + // Delete all elements before first iteration. + m := map[string]int{"one": 1, "two": 2, "three": 3} + iter := ValueOf(m).MapRange() + delete(m, "one") + delete(m, "two") + delete(m, "three") + if got, want := iterateToString(iter), `[]`; got != want { + t.Errorf("iterator returned deleted elements: got %s, want %s", got, want) + } +} + +func TestMapIterDelete1(t *testing.T) { + // Delete all elements after first iteration. + m := map[string]int{"one": 1, "two": 2, "three": 3} + iter := ValueOf(m).MapRange() + var got []string + for iter.Next() { + got = append(got, fmt.Sprint(iter.Key(), iter.Value())) + delete(m, "one") + delete(m, "two") + delete(m, "three") + } + if len(got) != 1 { + t.Errorf("iterator returned wrong number of elements: got %d, want 1", len(got)) + } +} + +// iterateToString returns the set of elements +// returned by an iterator in readable form. +func iterateToString(it *MapIter) string { + var got []string + for it.Next() { + line := fmt.Sprintf("%v: %v", it.Key(), it.Value()) + got = append(got, line) + } + sort.Strings(got) + return "[" + strings.Join(got, ", ") + "]" +} diff --git a/libgo/go/reflect/example_test.go b/libgo/go/reflect/example_test.go index f959b95..23c08e4 100644 --- a/libgo/go/reflect/example_test.go +++ b/libgo/go/reflect/example_test.go @@ -13,6 +13,24 @@ import ( "reflect" ) +func ExampleKind() { + for _, v := range []interface{}{"hi", 42, func() {}} { + switch v := reflect.ValueOf(v); v.Kind() { + case reflect.String: + fmt.Println(v.String()) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + fmt.Println(v.Int()) + default: + fmt.Printf("unhandled kind %s", v.Kind()) + } + } + + // Output: + // hi + // 42 + // unhandled kind func +} + func ExampleMakeFunc() { // swap is the implementation passed to MakeFunc. // It must work in terms of reflect.Values so that it is possible diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index e4a9326..ea97b7d 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -419,6 +419,7 @@ const ( kindMask = (1 << 5) - 1 ) +// String returns the name of k. func (k Kind) String() string { if int(k) < len(kindNames) { return kindNames[k] @@ -1904,7 +1905,7 @@ var structLookupCache struct { m sync.Map } -// isLetter returns true if a given 'rune' is classified as a Letter. +// isLetter reports whether a given 'rune' is classified as a Letter. func isLetter(ch rune) bool { return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch) } diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 9f05744..d3a6243 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -851,7 +851,7 @@ func (v Value) InterfaceData() [2]uintptr { func (v Value) IsNil() bool { k := v.kind() switch k { - case Chan, Func, Map, Ptr: + case Chan, Func, Map, Ptr, UnsafePointer: if v.flag&flagMethod != 0 { return false } @@ -935,14 +935,7 @@ func (v Value) MapIndex(key Value) Value { typ := tt.elem fl := (v.flag | key.flag).ro() fl |= flag(typ.Kind()) - if !ifaceIndir(typ) { - return Value{typ, *(*unsafe.Pointer)(e), fl} - } - // Copy result so future changes to the map - // won't change the underlying value. - c := unsafe_New(typ) - typedmemmove(typ, c, e) - return Value{typ, c, fl | flagIndir} + return copyVal(typ, fl, e) } // MapKeys returns a slice containing all the keys present in the map, @@ -972,20 +965,96 @@ func (v Value) MapKeys() []Value { // we can do about it. break } - if ifaceIndir(keyType) { - // Copy result so future changes to the map - // won't change the underlying value. - c := unsafe_New(keyType) - typedmemmove(keyType, c, key) - a[i] = Value{keyType, c, fl | flagIndir} - } else { - a[i] = Value{keyType, *(*unsafe.Pointer)(key), fl} - } + a[i] = copyVal(keyType, fl, key) mapiternext(it) } return a[:i] } +// A MapIter is an iterator for ranging over a map. +// See Value.MapRange. +type MapIter struct { + m Value + it unsafe.Pointer +} + +// Key returns the key of the iterator's current map entry. +func (it *MapIter) Key() Value { + if it.it == nil { + panic("MapIter.Key called before Next") + } + if mapiterkey(it.it) == nil { + panic("MapIter.Key called on exhausted iterator") + } + + t := (*mapType)(unsafe.Pointer(it.m.typ)) + ktype := t.key + return copyVal(ktype, it.m.flag.ro()|flag(ktype.Kind()), mapiterkey(it.it)) +} + +// Value returns the value of the iterator's current map entry. +func (it *MapIter) Value() Value { + if it.it == nil { + panic("MapIter.Value called before Next") + } + if mapiterkey(it.it) == nil { + panic("MapIter.Value called on exhausted iterator") + } + + t := (*mapType)(unsafe.Pointer(it.m.typ)) + vtype := t.elem + return copyVal(vtype, it.m.flag.ro()|flag(vtype.Kind()), mapitervalue(it.it)) +} + +// Next advances the map iterator and reports whether there is another +// entry. It returns false when the iterator is exhausted; subsequent +// calls to Key, Value, or Next will panic. +func (it *MapIter) Next() bool { + if it.it == nil { + it.it = mapiterinit(it.m.typ, it.m.pointer()) + } else { + if mapiterkey(it.it) == nil { + panic("MapIter.Next called on exhausted iterator") + } + mapiternext(it.it) + } + return mapiterkey(it.it) != nil +} + +// MapRange returns a range iterator for a map. +// It panics if v's Kind is not Map. +// +// Call Next to advance the iterator, and Key/Value to access each entry. +// Next returns false when the iterator is exhausted. +// MapRange follows the same iteration semantics as a range statement. +// +// Example: +// +// iter := reflect.ValueOf(m).MapRange() +// for iter.Next() { +// k := iter.Key() +// v := iter.Value() +// ... +// } +// +func (v Value) MapRange() *MapIter { + v.mustBe(Map) + return &MapIter{m: v} +} + +// copyVal returns a Value containing the map key or value at ptr, +// allocating a new variable as needed. +func copyVal(typ *rtype, fl flag, ptr unsafe.Pointer) Value { + if ifaceIndir(typ) { + // Copy result so future changes to the map + // won't change the underlying value. + c := unsafe_New(typ) + typedmemmove(typ, c, ptr) + return Value{typ, c, fl | flagIndir} + } + return Value{typ, *(*unsafe.Pointer)(ptr), fl} +} + // Method returns a function value corresponding to v's i'th method. // The arguments to a Call on the returned function should not include // a receiver; the returned function will always use v as the receiver. @@ -2395,10 +2464,15 @@ func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer) //go:noescape +func mapitervalue(it unsafe.Pointer) (value unsafe.Pointer) + +//go:noescape func mapiternext(it unsafe.Pointer) //go:noescape func maplen(m unsafe.Pointer) int + +//go:linkname call runtime.reflectcall func call(typ *funcType, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer) func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) |