diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-12-23 09:57:37 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-12-30 15:13:24 -0800 |
commit | cfcbb4227fb20191e04eb8d7766ae6202f526afd (patch) | |
tree | e2effea96f6f204451779f044415c2385e45042b /libgo/go/reflect | |
parent | 0696141107d61483f38482b941549959a0d7f613 (diff) | |
download | gcc-cfcbb4227fb20191e04eb8d7766ae6202f526afd.tar.gz |
libgo: update to Go1.16beta1 release
This does not yet include support for the //go:embed directive added
in this release.
* Makefile.am (check-runtime): Don't create check-runtime-dir.
(mostlyclean-local): Don't remove check-runtime-dir.
(check-go-tool, check-vet): Copy in go.mod and modules.txt.
(check-cgo-test, check-carchive-test): Add go.mod file.
* Makefile.in: Regenerate.
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/280172
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 249 | ||||
-rw-r--r-- | libgo/go/reflect/deepequal.go | 18 | ||||
-rw-r--r-- | libgo/go/reflect/type.go | 65 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 37 |
4 files changed, 318 insertions, 51 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index 68efab6e145..11193022911 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -74,6 +74,10 @@ var typeTests = []pair{ {struct{ x ([]int8) }{}, "[]int8"}, {struct{ x (map[string]int32) }{}, "map[string]int32"}, {struct{ x (chan<- string) }{}, "chan<- string"}, + {struct{ x (chan<- chan string) }{}, "chan<- chan string"}, + {struct{ x (chan<- <-chan string) }{}, "chan<- <-chan string"}, + {struct{ x (<-chan <-chan string) }{}, "<-chan <-chan string"}, + {struct{ x (chan (<-chan string)) }{}, "chan (<-chan string)"}, {struct { x struct { c chan *int32 @@ -1721,6 +1725,14 @@ func TestSelectMaxCases(t *testing.T) { _, _, _ = Select(sCases) } +func TestSelectNop(t *testing.T) { + // "select { default: }" should always return the default case. + chosen, _, _ := Select([]SelectCase{{Dir: SelectDefault}}) + if chosen != 0 { + t.Fatalf("expected Select to return 0, but got %#v", chosen) + } +} + func BenchmarkSelect(b *testing.B) { channel := make(chan int) close(channel) @@ -4005,9 +4017,12 @@ var convertTests = []struct { {V(int16(-3)), V(string("\uFFFD"))}, {V(int32(-4)), V(string("\uFFFD"))}, {V(int64(-5)), V(string("\uFFFD"))}, + {V(int64(-1 << 32)), V(string("\uFFFD"))}, + {V(int64(1 << 32)), V(string("\uFFFD"))}, {V(uint(0x110001)), V(string("\uFFFD"))}, {V(uint32(0x110002)), V(string("\uFFFD"))}, {V(uint64(0x110003)), V(string("\uFFFD"))}, + {V(uint64(1 << 32)), V(string("\uFFFD"))}, {V(uintptr(0x110004)), V(string("\uFFFD"))}, // named string @@ -4263,24 +4278,6 @@ var gFloat32 float32 func TestConvertNaNs(t *testing.T) { const snan uint32 = 0x7f800001 - - // Test to see if a store followed by a load of a signaling NaN - // maintains the signaling bit. The only platform known to fail - // this test is 386,GO386=387. The real test below will always fail - // if the platform can't even store+load a float without mucking - // with the bits. - gFloat32 = math.Float32frombits(snan) - runtime.Gosched() // make sure we don't optimize the store/load away - r := math.Float32bits(gFloat32) - if r != snan { - // This should only happen on 386,GO386=387. We have no way to - // test for 387, so we just make sure we're at least on 386. - if runtime.GOARCH != "386" { - t.Errorf("store/load of sNaN not faithful") - } - t.Skip("skipping test, float store+load not faithful") - } - type myFloat32 float32 x := V(myFloat32(math.Float32frombits(snan))) y := x.Convert(TypeOf(float32(0))) @@ -5519,6 +5516,18 @@ func TestChanOf(t *testing.T) { // check that type already in binary is found type T1 int checkSameType(t, ChanOf(BothDir, TypeOf(T1(1))), (chan T1)(nil)) + + // Check arrow token association in undefined chan types. + var left chan<- chan T + var right chan (<-chan T) + tLeft := ChanOf(SendDir, ChanOf(BothDir, TypeOf(T("")))) + tRight := ChanOf(BothDir, ChanOf(RecvDir, TypeOf(T("")))) + if tLeft != TypeOf(left) { + t.Errorf("chan<-chan: have %s, want %T", tLeft, left) + } + if tRight != TypeOf(right) { + t.Errorf("chan<-chan: have %s, want %T", tRight, right) + } } func TestChanOfDir(t *testing.T) { @@ -6010,6 +6019,14 @@ func TestReflectMethodTraceback(t *testing.T) { } } +func TestSmallZero(t *testing.T) { + type T [10]byte + typ := TypeOf(T{}) + if allocs := testing.AllocsPerRun(100, func() { Zero(typ) }); allocs > 0 { + t.Errorf("Creating small zero values caused %f allocs, want 0", allocs) + } +} + func TestBigZero(t *testing.T) { const size = 1 << 10 var v [size]byte @@ -6021,6 +6038,27 @@ func TestBigZero(t *testing.T) { } } +func TestZeroSet(t *testing.T) { + type T [16]byte + type S struct { + a uint64 + T T + b uint64 + } + v := S{ + a: 0xaaaaaaaaaaaaaaaa, + T: T{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}, + b: 0xbbbbbbbbbbbbbbbb, + } + ValueOf(&v).Elem().Field(1).Set(Zero(TypeOf(T{}))) + if v != (S{ + a: 0xaaaaaaaaaaaaaaaa, + b: 0xbbbbbbbbbbbbbbbb, + }) { + t.Fatalf("Setting a field to a Zero value didn't work") + } +} + func TestFieldByIndexNil(t *testing.T) { type P struct { F int @@ -6480,12 +6518,9 @@ func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) { // Repeat the bitmap for the slice size, trimming scalars in // the last element. bits = rep(cap, bits) - for len(bits) > 2 && bits[len(bits)-1] == 0 { + for len(bits) > 0 && bits[len(bits)-1] == 0 { bits = bits[:len(bits)-1] } - if len(bits) == 2 && bits[0] == 0 && bits[1] == 0 { - bits = bits[:0] - } if !bytes.Equal(heapBits, bits) { t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits) } @@ -7169,6 +7204,176 @@ func TestMapIterDelete1(t *testing.T) { } } +func TestStructTagLookup(t *testing.T) { + var tests = []struct { + tag StructTag + key string + expectedValue string + expectedOK bool + }{ + { + tag: `json:"json_value_1"`, + key: "json", + expectedValue: "json_value_1", + expectedOK: true, + }, + { + tag: `json:"json_value_2" xml:"xml_value_2"`, + key: "json", + expectedValue: "json_value_2", + expectedOK: true, + }, + { + tag: `json:"json_value_3" xml:"xml_value_3"`, + key: "xml", + expectedValue: "xml_value_3", + expectedOK: true, + }, + { + tag: `bson json:"shared_value_4"`, + key: "json", + expectedValue: "shared_value_4", + expectedOK: true, + }, + { + tag: `bson json:"shared_value_5"`, + key: "bson", + expectedValue: "shared_value_5", + expectedOK: true, + }, + { + tag: `json bson xml form:"field_1,omitempty" other:"value_1"`, + key: "xml", + expectedValue: "field_1,omitempty", + expectedOK: true, + }, + { + tag: `json bson xml form:"field_2,omitempty" other:"value_2"`, + key: "form", + expectedValue: "field_2,omitempty", + expectedOK: true, + }, + { + tag: `json bson xml form:"field_3,omitempty" other:"value_3"`, + key: "other", + expectedValue: "value_3", + expectedOK: true, + }, + { + tag: `json bson xml form:"field_4" other:"value_4"`, + key: "json", + expectedValue: "field_4", + expectedOK: true, + }, + { + tag: `json bson xml form:"field_5" other:"value_5"`, + key: "non_existing", + expectedValue: "", + expectedOK: false, + }, + { + tag: `json "json_6"`, + key: "json", + expectedValue: "", + expectedOK: false, + }, + { + tag: `json:"json_7" bson "bson_7"`, + key: "json", + expectedValue: "json_7", + expectedOK: true, + }, + { + tag: `json:"json_8" xml "xml_8"`, + key: "xml", + expectedValue: "", + expectedOK: false, + }, + { + tag: `json bson xml form "form_9" other:"value_9"`, + key: "bson", + expectedValue: "", + expectedOK: false, + }, + { + tag: `json bson xml form "form_10" other:"value_10"`, + key: "other", + expectedValue: "", + expectedOK: false, + }, + { + tag: `json bson xml form:"form_11" other "value_11"`, + key: "json", + expectedValue: "form_11", + expectedOK: true, + }, + { + tag: `tag1`, + key: "tag1", + expectedValue: "", + expectedOK: false, + }, + { + tag: `tag2 :"hello_2"`, + key: "tag2", + expectedValue: "", + expectedOK: false, + }, + { + tag: `tag3: "hello_3"`, + key: "tag3", + expectedValue: "", + expectedOK: false, + }, + { + tag: "json\x7fbson: \"hello_4\"", + key: "json", + expectedValue: "", + expectedOK: false, + }, + { + tag: "json\x7fbson: \"hello_5\"", + key: "bson", + expectedValue: "", + expectedOK: false, + }, + { + tag: "json bson:\x7f\"hello_6\"", + key: "json", + expectedValue: "", + expectedOK: false, + }, + { + tag: "json bson:\x7f\"hello_7\"", + key: "bson", + expectedValue: "", + expectedOK: false, + }, + { + tag: "json\x09bson:\"hello_8\"", + key: "json", + expectedValue: "", + expectedOK: false, + }, + { + tag: "a\x7fb json:\"val\"", + key: "json", + expectedValue: "", + expectedOK: false, + }, + } + + for _, test := range tests { + v, ok := test.tag.Lookup(test.key) + if v != test.expectedValue { + t.Errorf("struct tag lookup failed, got %s, want %s", v, test.expectedValue) + } + if ok != test.expectedOK { + t.Errorf("struct tag lookup failed, got %t, want %t", ok, test.expectedOK) + } + } +} + // iterateToString returns the set of elements // returned by an iterator in readable form. func iterateToString(it *MapIter) string { diff --git a/libgo/go/reflect/deepequal.go b/libgo/go/reflect/deepequal.go index b99c345e7bf..d951d8d9997 100644 --- a/libgo/go/reflect/deepequal.go +++ b/libgo/go/reflect/deepequal.go @@ -21,7 +21,7 @@ type visit struct { // Tests for deep equality using reflected types. The map argument tracks // comparisons that have already been seen, which allows short circuiting on // recursive types. -func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { +func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool { if !v1.IsValid() || !v2.IsValid() { return v1.IsValid() == v2.IsValid() } @@ -29,8 +29,6 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { return false } - // if depth > 10 { panic("deepValueEqual") } // for debugging - // We want to avoid putting more in the visited map than we need to. // For any possible reference cycle that might be encountered, // hard(v1, v2) needs to return true for at least one of the types in the cycle, @@ -89,7 +87,7 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { switch v1.Kind() { case Array: for i := 0; i < v1.Len(); i++ { - if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) { + if !deepValueEqual(v1.Index(i), v2.Index(i), visited) { return false } } @@ -105,7 +103,7 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { return true } for i := 0; i < v1.Len(); i++ { - if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) { + if !deepValueEqual(v1.Index(i), v2.Index(i), visited) { return false } } @@ -114,15 +112,15 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool { if v1.IsNil() || v2.IsNil() { return v1.IsNil() == v2.IsNil() } - return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1) + return deepValueEqual(v1.Elem(), v2.Elem(), visited) case Ptr: if v1.Pointer() == v2.Pointer() { return true } - return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1) + return deepValueEqual(v1.Elem(), v2.Elem(), visited) case Struct: for i, n := 0, v1.NumField(); i < n; i++ { - if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) { + if !deepValueEqual(v1.Field(i), v2.Field(i), visited) { return false } } @@ -140,7 +138,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(val1, val2, visited, depth+1) { + if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(val1, val2, visited) { return false } } @@ -217,5 +215,5 @@ func DeepEqual(x, y interface{}) bool { if v1.Type() != v2.Type() { return false } - return deepValueEqual(v1, v2, make(map[visit]bool), 0) + return deepValueEqual(v1, v2, make(map[visit]bool)) } diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 73c09d4bb34..1118088fb42 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -49,13 +49,13 @@ type Type interface { // It panics if i is not in the range [0, NumMethod()). // // For a non-interface type T or *T, the returned Method's Type and Func - // fields describe a function whose first argument is the receiver. + // fields describe a function whose first argument is the receiver, + // and only exported methods are accessible. // // For an interface type, the returned Method's Type field gives the // method signature, without a receiver, and the Func field is nil. // - // Only exported methods are accessible and they are sorted in - // lexicographic order. + // Methods are sorted in lexicographic order. Method(int) Method // MethodByName returns the method with that name in the type's @@ -68,7 +68,9 @@ type Type interface { // method signature, without a receiver, and the Func field is nil. MethodByName(string) (Method, bool) - // NumMethod returns the number of exported methods in the type's method set. + // NumMethod returns the number of methods accessible using Method. + // + // Note that NumMethod counts unexported methods only for interface types. NumMethod() int // Name returns the type's name within its package for a defined type. @@ -840,12 +842,16 @@ type StructField struct { // A StructTag is the tag string in a struct field. // -// By convention, tag strings are a concatenation of -// optionally space-separated key:"value" pairs. -// Each key is a non-empty string consisting of non-control -// characters other than space (U+0020 ' '), quote (U+0022 '"'), -// and colon (U+003A ':'). Each value is quoted using U+0022 '"' -// characters and Go string literal syntax. +// By convention, tag strings are a mapping of keys to values. +// The format is key:"value". Each key is a non-empty string consisting +// of non-control characters other than space (U+0020 ' '), +// quote (U+0022 '"'), and colon (U+003A ':'). Each value is quoted +// using U+0022 '"' characters and Go string literal syntax. +// Multiple key-value mappings are separated by zero or more spaces, as in +// key1:"value1" key2:"value2" +// Multiple keys may map to a single shared value by separating the keys +// with spaces, as in +// key1 key2:"value" type StructTag string // Get returns the value associated with key in the tag string. @@ -868,6 +874,9 @@ func (tag StructTag) Lookup(key string) (value string, ok bool) { // When modifying this code, also update the validateStructTag code // in cmd/vet/structtag.go. + // keyFound indicates that such key on the left side has already been found. + var keyFound bool + for tag != "" { // Skip leading space. i := 0 @@ -887,11 +896,29 @@ func (tag StructTag) Lookup(key string) (value string, ok bool) { for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { i++ } - if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { + if i == 0 || i+1 >= len(tag) || tag[i] < ' ' || tag[i] == 0x7f { break } name := string(tag[:i]) - tag = tag[i+1:] + tag = tag[i:] + + // If we found a space char here - assume that we have a tag with + // multiple keys. + if tag[0] == ' ' { + if name == key { + keyFound = true + } + continue + } + + // Spaces were filtered above so we assume that here we have + // only valid tag value started with `:"`. + if tag[0] != ':' || tag[1] != '"' { + break + } + + // Remove the colon leaving tag at the start of the quoted string. + tag = tag[1:] // Scan quoted string to find value. i = 1 @@ -907,7 +934,7 @@ func (tag StructTag) Lookup(key string) (value string, ok bool) { qvalue := string(tag[:i+1]) tag = tag[i+1:] - if key == name { + if key == name || keyFound { value, err := strconv.Unquote(qvalue) if err != nil { break @@ -1438,7 +1465,6 @@ func ChanOf(dir ChanDir, t Type) Type { } // Look in known types. - // TODO: Precedence when constructing string. var s string switch dir { default: @@ -1448,7 +1474,16 @@ func ChanOf(dir ChanDir, t Type) Type { case RecvDir: s = "<-chan " + *typ.string case BothDir: - s = "chan " + *typ.string + typeStr := *typ.string + if typeStr[0] == '<' { + // typ is recv chan, need parentheses as "<-" associates with leftmost + // chan possible, see: + // * https://golang.org/ref/spec#Channel_types + // * https://github.com/golang/go/issues/39897 + s = "chan (" + typeStr + ")" + } else { + s = "chan " + typeStr + } } if tt := lookupType(s); tt != nil { ch := (*chanType)(unsafe.Pointer(toType(tt).(*rtype))) diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 1394dd308c4..0b4f094f1b7 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -1364,7 +1364,11 @@ func (v Value) Set(x Value) { } x = x.assignTo("reflect.Set", v.typ, target) if x.flag&flagIndir != 0 { - typedmemmove(v.typ, v.ptr, x.ptr) + if x.ptr == unsafe.Pointer(&zeroVal[0]) { + typedmemclr(v.typ, v.ptr) + } else { + typedmemmove(v.typ, v.ptr, x.ptr) + } } else { *(*unsafe.Pointer)(v.ptr) = x.ptr } @@ -2171,11 +2175,24 @@ func Zero(typ Type) Value { t := typ.(*rtype) fl := flag(t.Kind()) if ifaceIndir(t) { - return Value{t, unsafe_New(t), fl | flagIndir} + var p unsafe.Pointer + if t.size <= maxZero { + p = unsafe.Pointer(&zeroVal[0]) + } else { + p = unsafe_New(t) + } + return Value{t, p, fl | flagIndir} } return Value{t, nil, fl} } +// must match declarations in runtime/map.go. +const maxZero = 1024 + +// Using linkname here doesn't work for gofrontend. +// //go:linkname zeroVal runtime.zeroVal +var zeroVal [maxZero]byte + // New returns a Value representing a pointer to a new zero value // for the specified type. That is, the returned Value's Type is PtrTo(typ). func New(typ Type) Value { @@ -2466,12 +2483,20 @@ func cvtComplex(v Value, t Type) Value { // convertOp: intXX -> string func cvtIntString(v Value, t Type) Value { - return makeString(v.flag.ro(), string(rune(v.Int())), t) + s := "\uFFFD" + if x := v.Int(); int64(rune(x)) == x { + s = string(rune(x)) + } + return makeString(v.flag.ro(), s, t) } // convertOp: uintXX -> string func cvtUintString(v Value, t Type) Value { - return makeString(v.flag.ro(), string(rune(v.Uint())), t) + s := "\uFFFD" + if x := v.Uint(); uint64(rune(x)) == x { + s = string(rune(x)) + } + return makeString(v.flag.ro(), s, t) } // convertOp: []byte -> string @@ -2592,6 +2617,10 @@ func memmove(dst, src unsafe.Pointer, size uintptr) //go:noescape func typedmemmove(t *rtype, dst, src unsafe.Pointer) +// typedmemclr zeros the value at ptr of type t. +//go:noescape +func typedmemclr(t *rtype, ptr unsafe.Pointer) + // typedslicecopy copies a slice of elemType values from src to dst, // returning the number of elements copied. //go:noescape |