aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/reflect
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-01-18 19:04:36 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-01-18 19:04:36 +0000
commit4f4a855d82a889cebcfca150a7a43909bcb6a346 (patch)
treef12bae0781920fa34669fe30b6f4615a86d9fb80 /libgo/go/reflect
parent225220d668dafb8262db7012bced688acbe63b33 (diff)
downloadgcc-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.go146
-rw-r--r--libgo/go/reflect/example_test.go18
-rw-r--r--libgo/go/reflect/type.go3
-rw-r--r--libgo/go/reflect/value.go110
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)