diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-07-27 22:27:54 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-08-01 11:21:40 -0700 |
commit | f75af8c1464e948b5e166cf5ab09ebf0d82fc253 (patch) | |
tree | 3ba3299859b504bdeb477727471216bd094a0191 /libgo/go/reflect | |
parent | 75a23e59031fe673fc3b2e60fd1fe5f4c70ecb85 (diff) | |
download | gcc-f75af8c1464e948b5e166cf5ab09ebf0d82fc253.zip gcc-f75af8c1464e948b5e166cf5ab09ebf0d82fc253.tar.gz gcc-f75af8c1464e948b5e166cf5ab09ebf0d82fc253.tar.bz2 |
libgo: update to go1.15rc1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/245157
Diffstat (limited to 'libgo/go/reflect')
-rw-r--r-- | libgo/go/reflect/all_test.go | 323 | ||||
-rw-r--r-- | libgo/go/reflect/swapper.go | 7 | ||||
-rw-r--r-- | libgo/go/reflect/value.go | 118 |
3 files changed, 308 insertions, 140 deletions
diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index e5ec052..ee37359 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -350,6 +350,7 @@ func TestCanSetField(t *testing.T) { } type testCase struct { + // -1 means Addr().Elem() of current value index []int canSet bool } @@ -360,17 +361,33 @@ func TestCanSetField(t *testing.T) { val: ValueOf(&S1{}), cases: []testCase{ {[]int{0}, false}, + {[]int{0, -1}, false}, {[]int{0, 0}, false}, + {[]int{0, 0, -1}, false}, + {[]int{0, -1, 0}, false}, + {[]int{0, -1, 0, -1}, false}, {[]int{0, 1}, true}, + {[]int{0, 1, -1}, true}, + {[]int{0, -1, 1}, true}, + {[]int{0, -1, 1, -1}, true}, {[]int{1}, false}, + {[]int{1, -1}, false}, {[]int{2}, true}, + {[]int{2, -1}, true}, }, }, { val: ValueOf(&S2{embed: &embed{}}), cases: []testCase{ {[]int{0}, false}, + {[]int{0, -1}, false}, {[]int{0, 0}, false}, + {[]int{0, 0, -1}, false}, + {[]int{0, -1, 0}, false}, + {[]int{0, -1, 0, -1}, false}, {[]int{0, 1}, true}, + {[]int{0, 1, -1}, true}, + {[]int{0, -1, 1}, true}, + {[]int{0, -1, 1, -1}, true}, {[]int{1}, false}, {[]int{2}, true}, }, @@ -378,8 +395,15 @@ func TestCanSetField(t *testing.T) { val: ValueOf(&S3{}), cases: []testCase{ {[]int{0}, true}, + {[]int{0, -1}, true}, {[]int{0, 0}, false}, + {[]int{0, 0, -1}, false}, + {[]int{0, -1, 0}, false}, + {[]int{0, -1, 0, -1}, false}, {[]int{0, 1}, true}, + {[]int{0, 1, -1}, true}, + {[]int{0, -1, 1}, true}, + {[]int{0, -1, 1, -1}, true}, {[]int{1}, false}, {[]int{2}, true}, }, @@ -387,8 +411,15 @@ func TestCanSetField(t *testing.T) { val: ValueOf(&S4{Embed: &Embed{}}), cases: []testCase{ {[]int{0}, true}, + {[]int{0, -1}, true}, {[]int{0, 0}, false}, + {[]int{0, 0, -1}, false}, + {[]int{0, -1, 0}, false}, + {[]int{0, -1, 0, -1}, false}, {[]int{0, 1}, true}, + {[]int{0, 1, -1}, true}, + {[]int{0, -1, 1}, true}, + {[]int{0, -1, 1, -1}, true}, {[]int{1}, false}, {[]int{2}, true}, }, @@ -402,7 +433,11 @@ func TestCanSetField(t *testing.T) { if f.Kind() == Ptr { f = f.Elem() } - f = f.Field(i) + if i == -1 { + f = f.Addr().Elem() + } else { + f = f.Field(i) + } } if got := f.CanSet(); got != tc.canSet { t.Errorf("CanSet() = %v, want %v", got, tc.canSet) @@ -1657,6 +1692,55 @@ func TestSelect(t *testing.T) { } } +func TestSelectMaxCases(t *testing.T) { + var sCases []SelectCase + channel := make(chan int) + close(channel) + for i := 0; i < 65536; i++ { + sCases = append(sCases, SelectCase{ + Dir: SelectRecv, + Chan: ValueOf(channel), + }) + } + // Should not panic + _, _, _ = Select(sCases) + sCases = append(sCases, SelectCase{ + Dir: SelectRecv, + Chan: ValueOf(channel), + }) + defer func() { + if err := recover(); err != nil { + if err.(string) != "reflect.Select: too many cases (max 65536)" { + t.Fatalf("unexpected error from select call with greater than max supported cases") + } + } else { + t.Fatalf("expected select call to panic with greater than max supported cases") + } + }() + // Should panic + _, _, _ = Select(sCases) +} + +func BenchmarkSelect(b *testing.B) { + channel := make(chan int) + close(channel) + var cases []SelectCase + for i := 0; i < 8; i++ { + cases = append(cases, SelectCase{ + Dir: SelectRecv, + Chan: ValueOf(channel), + }) + } + for _, numCases := range []int{1, 4, 8} { + b.Run(strconv.Itoa(numCases), func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, _, _ = Select(cases[:numCases]) + } + }) + } +} + // selectWatch and the selectWatcher are a watchdog mechanism for running Select. // If the selectWatcher notices that the select has been blocked for >1 second, it prints // an error describing the select and panics the entire test binary. @@ -2001,7 +2085,7 @@ func TestMakeFuncValidReturnAssignments(t *testing.T) { func TestMakeFuncInvalidReturnAssignments(t *testing.T) { // Type doesn't implement the required interface. - shouldPanic(func() { + shouldPanic("", func() { var f func() error f = MakeFunc(TypeOf(f), func([]Value) []Value { return []Value{ValueOf(int(7))} @@ -2009,7 +2093,7 @@ func TestMakeFuncInvalidReturnAssignments(t *testing.T) { f() }) // Assigning to an interface with additional methods. - shouldPanic(func() { + shouldPanic("", func() { var f func() io.ReadWriteCloser f = MakeFunc(TypeOf(f), func([]Value) []Value { var w io.WriteCloser = &WC{} @@ -2018,7 +2102,7 @@ func TestMakeFuncInvalidReturnAssignments(t *testing.T) { f() }) // Directional channels can't be assigned to bidirectional ones. - shouldPanic(func() { + shouldPanic("", func() { var f func() chan int f = MakeFunc(TypeOf(f), func([]Value) []Value { var c <-chan int = make(chan int) @@ -2027,7 +2111,7 @@ func TestMakeFuncInvalidReturnAssignments(t *testing.T) { f() }) // Two named types which are otherwise identical. - shouldPanic(func() { + shouldPanic("", func() { type T struct{ a, b, c int } type U struct{ a, b, c int } var f func() T @@ -2491,7 +2575,7 @@ func TestMethod5(t *testing.T) { var tnil Tinter vnil := ValueOf(&tnil).Elem() - shouldPanic(func() { vnil.Method(0) }) + shouldPanic("Method", func() { vnil.Method(0) }) } func TestInterfaceSet(t *testing.T) { @@ -3203,9 +3287,9 @@ func TestSlice3(t *testing.T) { t.Errorf("xs.Slice3(3, 5, 7)[0:4] = %v", v[0:4]) } rv := ValueOf(&xs).Elem() - shouldPanic(func() { rv.Slice3(1, 2, 1) }) - shouldPanic(func() { rv.Slice3(1, 1, 11) }) - shouldPanic(func() { rv.Slice3(2, 2, 1) }) + shouldPanic("Slice3", func() { rv.Slice3(1, 2, 1) }) + shouldPanic("Slice3", func() { rv.Slice3(1, 1, 11) }) + shouldPanic("Slice3", func() { rv.Slice3(2, 2, 1) }) xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80} v = ValueOf(&xa).Elem().Slice3(2, 5, 6).Interface().([]int) @@ -3219,13 +3303,13 @@ func TestSlice3(t *testing.T) { t.Errorf("xs.Slice(2, 5, 6)[0:4] = %v", v[0:4]) } rv = ValueOf(&xa).Elem() - shouldPanic(func() { rv.Slice3(1, 2, 1) }) - shouldPanic(func() { rv.Slice3(1, 1, 11) }) - shouldPanic(func() { rv.Slice3(2, 2, 1) }) + shouldPanic("Slice3", func() { rv.Slice3(1, 2, 1) }) + shouldPanic("Slice3", func() { rv.Slice3(1, 1, 11) }) + shouldPanic("Slice3", func() { rv.Slice3(2, 2, 1) }) s := "hello world" rv = ValueOf(&s).Elem() - shouldPanic(func() { rv.Slice3(1, 2, 3) }) + shouldPanic("Slice3", func() { rv.Slice3(1, 2, 3) }) rv = ValueOf(&xs).Elem() rv = rv.Slice3(3, 5, 7) @@ -3242,11 +3326,11 @@ func TestSetLenCap(t *testing.T) { xa := [8]int{10, 20, 30, 40, 50, 60, 70, 80} vs := ValueOf(&xs).Elem() - shouldPanic(func() { vs.SetLen(10) }) - shouldPanic(func() { vs.SetCap(10) }) - shouldPanic(func() { vs.SetLen(-1) }) - shouldPanic(func() { vs.SetCap(-1) }) - shouldPanic(func() { vs.SetCap(6) }) // smaller than len + shouldPanic("SetLen", func() { vs.SetLen(10) }) + shouldPanic("SetCap", func() { vs.SetCap(10) }) + shouldPanic("SetLen", func() { vs.SetLen(-1) }) + shouldPanic("SetCap", func() { vs.SetCap(-1) }) + shouldPanic("SetCap", func() { vs.SetCap(6) }) // smaller than len vs.SetLen(5) if len(xs) != 5 || cap(xs) != 8 { t.Errorf("after SetLen(5), len, cap = %d, %d, want 5, 8", len(xs), cap(xs)) @@ -3259,12 +3343,12 @@ func TestSetLenCap(t *testing.T) { if len(xs) != 5 || cap(xs) != 5 { t.Errorf("after SetCap(5), len, cap = %d, %d, want 5, 5", len(xs), cap(xs)) } - shouldPanic(func() { vs.SetCap(4) }) // smaller than len - shouldPanic(func() { vs.SetLen(6) }) // bigger than cap + shouldPanic("SetCap", func() { vs.SetCap(4) }) // smaller than len + shouldPanic("SetLen", func() { vs.SetLen(6) }) // bigger than cap va := ValueOf(&xa).Elem() - shouldPanic(func() { va.SetLen(8) }) - shouldPanic(func() { va.SetCap(8) }) + shouldPanic("SetLen", func() { va.SetLen(8) }) + shouldPanic("SetCap", func() { va.SetCap(8) }) } func TestVariadic(t *testing.T) { @@ -3422,16 +3506,16 @@ func TestUnexported(t *testing.T) { isValid(v.Elem().Field(1)) isValid(v.Elem().FieldByName("x")) isValid(v.Elem().FieldByName("y")) - shouldPanic(func() { v.Elem().Field(0).Interface() }) - shouldPanic(func() { v.Elem().Field(1).Interface() }) - shouldPanic(func() { v.Elem().FieldByName("x").Interface() }) - shouldPanic(func() { v.Elem().FieldByName("y").Interface() }) - shouldPanic(func() { v.Type().Method(0) }) + shouldPanic("Interface", func() { v.Elem().Field(0).Interface() }) + shouldPanic("Interface", func() { v.Elem().Field(1).Interface() }) + shouldPanic("Interface", func() { v.Elem().FieldByName("x").Interface() }) + shouldPanic("Interface", func() { v.Elem().FieldByName("y").Interface() }) + shouldPanic("Method", func() { v.Type().Method(0) }) } func TestSetPanic(t *testing.T) { ok := func(f func()) { f() } - bad := shouldPanic + bad := func(f func()) { shouldPanic("Set", f) } clear := func(v Value) { v.Set(Zero(v.Type())) } type t0 struct { @@ -3548,56 +3632,75 @@ func TestCallPanic(t *testing.T) { namedT2 T2 // 7 } ok := func(f func()) { f() } - bad := shouldPanic + badCall := func(f func()) { shouldPanic("Call", f) } + badMethod := func(f func()) { shouldPanic("Method", f) } call := func(v Value) { v.Call(nil) } i := timp(0) v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}}) - ok(func() { call(v.Field(0).Method(0)) }) // .t0.W - bad(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W - bad(func() { call(v.Field(0).Method(1)) }) // .t0.w - bad(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w - ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y - ok(func() { call(v.Field(1).Elem().Method(0)) }) // .T1.Y - bad(func() { call(v.Field(1).Method(1)) }) // .T1.y - bad(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y - - ok(func() { call(v.Field(2).Method(0)) }) // .NamedT0.W - ok(func() { call(v.Field(2).Elem().Method(0)) }) // .NamedT0.W - bad(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w - bad(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w - - ok(func() { call(v.Field(3).Method(0)) }) // .NamedT1.Y - ok(func() { call(v.Field(3).Elem().Method(0)) }) // .NamedT1.Y - bad(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y - bad(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y - - ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y - ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W - ok(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W - bad(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W - - bad(func() { call(v.Field(5).Method(0)) }) // .namedT0.W - bad(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W - bad(func() { call(v.Field(5).Method(1)) }) // .namedT0.w - bad(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w - - bad(func() { call(v.Field(6).Method(0)) }) // .namedT1.Y - bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.Y - bad(func() { call(v.Field(6).Method(0)) }) // .namedT1.y - bad(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.y - - bad(func() { call(v.Field(7).Field(0).Method(0)) }) // .namedT2.T1.Y - bad(func() { call(v.Field(7).Field(0).Elem().Method(0)) }) // .namedT2.T1.W - bad(func() { call(v.Field(7).Field(1).Method(0)) }) // .namedT2.t0.W - bad(func() { call(v.Field(7).Field(1).Elem().Method(0)) }) // .namedT2.t0.W -} - -func shouldPanic(f func()) { + badCall(func() { call(v.Field(0).Method(0)) }) // .t0.W + badCall(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W + badCall(func() { call(v.Field(0).Method(1)) }) // .t0.w + badMethod(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w + ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y + ok(func() { call(v.Field(1).Elem().Method(0)) }) // .T1.Y + badCall(func() { call(v.Field(1).Method(1)) }) // .T1.y + badMethod(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y + + ok(func() { call(v.Field(2).Method(0)) }) // .NamedT0.W + ok(func() { call(v.Field(2).Elem().Method(0)) }) // .NamedT0.W + badCall(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w + badMethod(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w + + ok(func() { call(v.Field(3).Method(0)) }) // .NamedT1.Y + ok(func() { call(v.Field(3).Elem().Method(0)) }) // .NamedT1.Y + badCall(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y + badMethod(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y + + ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y + ok(func() { call(v.Field(4).Field(0).Elem().Method(0)) }) // .NamedT2.T1.W + badCall(func() { call(v.Field(4).Field(1).Method(0)) }) // .NamedT2.t0.W + badCall(func() { call(v.Field(4).Field(1).Elem().Method(0)) }) // .NamedT2.t0.W + + badCall(func() { call(v.Field(5).Method(0)) }) // .namedT0.W + badCall(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W + badCall(func() { call(v.Field(5).Method(1)) }) // .namedT0.w + badMethod(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w + + badCall(func() { call(v.Field(6).Method(0)) }) // .namedT1.Y + badCall(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.Y + badCall(func() { call(v.Field(6).Method(0)) }) // .namedT1.y + badCall(func() { call(v.Field(6).Elem().Method(0)) }) // .namedT1.y + + badCall(func() { call(v.Field(7).Field(0).Method(0)) }) // .namedT2.T1.Y + badCall(func() { call(v.Field(7).Field(0).Elem().Method(0)) }) // .namedT2.T1.W + badCall(func() { call(v.Field(7).Field(1).Method(0)) }) // .namedT2.t0.W + badCall(func() { call(v.Field(7).Field(1).Elem().Method(0)) }) // .namedT2.t0.W +} + +func shouldPanic(expect string, f func()) { defer func() { - if recover() == nil { + r := recover() + if r == nil { panic("did not panic") } + if expect != "" { + var s string + switch r := r.(type) { + case string: + s = r + case *ValueError: + s = r.Error() + default: + panic(fmt.Sprintf("panicked with unexpected type %T", r)) + } + if !strings.HasPrefix(s, "reflect") { + panic(`panic string does not start with "reflect": ` + s) + } + if !strings.Contains(s, expect) { + panic(`panic string does not contain "` + expect + `": ` + s) + } + } }() f() } @@ -4150,6 +4253,40 @@ func TestConvert(t *testing.T) { } } +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))) + z := y.Interface().(float32) + if got := math.Float32bits(z); got != snan { + if runtime.GOARCH == "386" { + t.Skip("skipping test, float conversion not faithful") + } + t.Errorf("signaling nan conversion got %x, want %x", got, snan) + } +} + type ComparableStruct struct { X int } @@ -4401,7 +4538,7 @@ func TestArrayOfAlg(t *testing.T) { at = ArrayOf(6, TypeOf([]int(nil))) v1 = New(at).Elem() - shouldPanic(func() { _ = v1.Interface() == v1.Interface() }) + shouldPanic("", func() { _ = v1.Interface() == v1.Interface() }) } func TestArrayOfGenericAlg(t *testing.T) { @@ -4545,23 +4682,23 @@ func TestSliceOfGC(t *testing.T) { func TestStructOfFieldName(t *testing.T) { // invalid field name "1nvalid" - shouldPanic(func() { + shouldPanic("has invalid name", func() { StructOf([]StructField{ - {Name: "valid", Type: TypeOf("")}, + {Name: "Valid", Type: TypeOf("")}, {Name: "1nvalid", Type: TypeOf("")}, }) }) // invalid field name "+" - shouldPanic(func() { + shouldPanic("has invalid name", func() { StructOf([]StructField{ - {Name: "val1d", Type: TypeOf("")}, + {Name: "Val1d", Type: TypeOf("")}, {Name: "+", Type: TypeOf("")}, }) }) // no field name - shouldPanic(func() { + shouldPanic("has no name", func() { StructOf([]StructField{ {Name: "", Type: TypeOf("")}, }) @@ -4689,19 +4826,19 @@ func TestStructOf(t *testing.T) { } // check duplicate names - shouldPanic(func() { + shouldPanic("duplicate field", func() { StructOf([]StructField{ - {Name: "string", Type: TypeOf("")}, - {Name: "string", Type: TypeOf("")}, + {Name: "string", PkgPath: "p", Type: TypeOf("")}, + {Name: "string", PkgPath: "p", Type: TypeOf("")}, }) }) - shouldPanic(func() { + shouldPanic("has no name", func() { StructOf([]StructField{ {Type: TypeOf("")}, - {Name: "string", Type: TypeOf("")}, + {Name: "string", PkgPath: "p", Type: TypeOf("")}, }) }) - shouldPanic(func() { + shouldPanic("has no name", func() { StructOf([]StructField{ {Type: TypeOf("")}, {Type: TypeOf("")}, @@ -4924,7 +5061,7 @@ func TestStructOfAlg(t *testing.T) { st = StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf([]int(nil))}}) v1 = New(st).Elem() - shouldPanic(func() { _ = v1.Interface() == v1.Interface() }) + shouldPanic("", func() { _ = v1.Interface() == v1.Interface() }) } func TestStructOfGenericAlg(t *testing.T) { @@ -5258,7 +5395,7 @@ func TestStructOfWithInterface(t *testing.T) { rt := StructOf(fields) rv := New(rt).Elem() // This should panic since the pointer is nil. - shouldPanic(func() { + shouldPanic("", func() { rv.Interface().(IfaceSet).Set(want) }) @@ -5272,7 +5409,7 @@ func TestStructOfWithInterface(t *testing.T) { rt = StructOf(fields) rv = New(rt).Elem() // This should panic since the pointer is nil. - shouldPanic(func() { + shouldPanic("", func() { rv.Interface().(IfaceSet).Set(want) }) @@ -5294,7 +5431,7 @@ func TestStructOfWithInterface(t *testing.T) { // 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() { + shouldPanic("", func() { StructOf(fields) }) @@ -5315,7 +5452,7 @@ func TestStructOfWithInterface(t *testing.T) { // 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() { + shouldPanic("", func() { StructOf(fields) }) } @@ -5349,7 +5486,7 @@ func TestStructOfDifferentPkgPath(t *testing.T) { Type: TypeOf(int(0)), }, } - shouldPanic(func() { + shouldPanic("different PkgPath", func() { StructOf(fields) }) } @@ -5466,7 +5603,7 @@ func TestMapOf(t *testing.T) { checkSameType(t, MapOf(TypeOf(V(0)), TypeOf(K(""))), map[V]K(nil)) // check that invalid key type panics - shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) }) + shouldPanic("invalid key type", func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) }) } func TestMapOfGCKeys(t *testing.T) { @@ -5598,8 +5735,8 @@ func TestFuncOf(t *testing.T) { // check that variadic requires last element be a slice. FuncOf([]Type{TypeOf(1), TypeOf(""), SliceOf(TypeOf(false))}, nil, true) - shouldPanic(func() { FuncOf([]Type{TypeOf(0), TypeOf(""), TypeOf(false)}, nil, true) }) - shouldPanic(func() { FuncOf(nil, nil, true) }) + shouldPanic("must be slice", func() { FuncOf([]Type{TypeOf(0), TypeOf(""), TypeOf(false)}, nil, true) }) + shouldPanic("must be slice", func() { FuncOf(nil, nil, true) }) } type B1 struct { @@ -6845,7 +6982,7 @@ func TestUnaddressableField(t *testing.T) { } lv := ValueOf(&localBuffer).Elem() rv := ValueOf(b) - shouldPanic(func() { + shouldPanic("Set", func() { lv.Set(rv) }) } diff --git a/libgo/go/reflect/swapper.go b/libgo/go/reflect/swapper.go index 016f95d..0cf4066 100644 --- a/libgo/go/reflect/swapper.go +++ b/libgo/go/reflect/swapper.go @@ -4,7 +4,10 @@ package reflect -import "unsafe" +import ( + "internal/unsafeheader" + "unsafe" +) // Swapper returns a function that swaps the elements in the provided // slice. @@ -58,7 +61,7 @@ func Swapper(slice interface{}) func(i, j int) { } } - s := (*sliceHeader)(v.ptr) + s := (*unsafeheader.Slice)(v.ptr) tmp := unsafe_New(typ) // swap scratch space return func(i, j int) { diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 7c6a3e8..e60f84f 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -5,6 +5,7 @@ package reflect import ( + "internal/unsafeheader" "math" "runtime" "unsafe" @@ -178,6 +179,17 @@ func methodName() string { return f.Name() } +// methodNameSkip is like methodName, but skips another stack frame. +// This is a separate function so that reflect.flag.mustBe will be inlined. +func methodNameSkip() string { + pc, _, _, _ := runtime.Caller(3) + f := runtime.FuncForPC(pc) + if f == nil { + return "unknown method" + } + return f.Name() +} + // emptyInterface is the header for an interface{} value. type emptyInterface struct { typ *rtype @@ -217,10 +229,10 @@ func (f flag) mustBeExported() { func (f flag) mustBeExportedSlow() { if f == 0 { - panic(&ValueError{methodName(), Invalid}) + panic(&ValueError{methodNameSkip(), Invalid}) } if f&flagRO != 0 { - panic("reflect: " + methodName() + " using value obtained using unexported field") + panic("reflect: " + methodNameSkip() + " using value obtained using unexported field") } } @@ -235,14 +247,14 @@ func (f flag) mustBeAssignable() { func (f flag) mustBeAssignableSlow() { if f == 0 { - panic(&ValueError{methodName(), Invalid}) + panic(&ValueError{methodNameSkip(), Invalid}) } // Assignable if addressable and not read-only. if f&flagRO != 0 { - panic("reflect: " + methodName() + " using value obtained using unexported field") + panic("reflect: " + methodNameSkip() + " using value obtained using unexported field") } if f&flagAddr == 0 { - panic("reflect: " + methodName() + " using unaddressable value") + panic("reflect: " + methodNameSkip() + " using unaddressable value") } } @@ -255,7 +267,10 @@ func (v Value) Addr() Value { if v.flag&flagAddr == 0 { panic("reflect.Value.Addr of unaddressable value") } - return Value{v.typ.ptrTo(), v.ptr, v.flag.ro() | flag(Ptr)} + // Preserve flagRO instead of using v.flag.ro() so that + // v.Addr().Elem() is equivalent to v (#32772) + fl := v.flag & flagRO + return Value{v.typ.ptrTo(), v.ptr, fl | flag(Ptr)} } // Bool returns v's underlying value. @@ -563,7 +578,7 @@ func (v Value) Cap() int { return chancap(v.pointer()) case Slice: // Slice is always bigger than a word; assume flagIndir. - return (*sliceHeader)(v.ptr).Cap + return (*unsafeheader.Slice)(v.ptr).Cap } panic(&ValueError{"reflect.Value.Cap", v.kind()}) } @@ -742,7 +757,7 @@ func (v Value) Index(i int) Value { case Slice: // Element flag same as Elem of Ptr. // Addressable, indirect, possibly read-only. - s := (*sliceHeader)(v.ptr) + s := (*unsafeheader.Slice)(v.ptr) if uint(i) >= uint(s.Len) { panic("reflect: slice index out of range") } @@ -753,7 +768,7 @@ func (v Value) Index(i int) Value { return Value{typ, val, fl} case String: - s := (*stringHeader)(v.ptr) + s := (*unsafeheader.String)(v.ptr) if uint(i) >= uint(s.Len) { panic("reflect: string index out of range") } @@ -950,10 +965,10 @@ func (v Value) Len() int { return maplen(v.pointer()) case Slice: // Slice is bigger than a word; assume flagIndir. - return (*sliceHeader)(v.ptr).Len + return (*unsafeheader.Slice)(v.ptr).Len case String: // String is bigger than a word; assume flagIndir. - return (*stringHeader)(v.ptr).Len + return (*unsafeheader.String)(v.ptr).Len } panic(&ValueError{"reflect.Value.Len", v.kind()}) } @@ -1122,7 +1137,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 & (flagStickyRO | flagIndir) // Clear flagEmbedRO + fl := v.flag.ro() | (v.flag & flagIndir) fl |= flag(Func) fl |= flag(i)<<flagMethodShift | flagMethod return Value{v.typ, v.ptr, fl} @@ -1429,7 +1444,7 @@ func (v Value) SetInt(x int64) { func (v Value) SetLen(n int) { v.mustBeAssignable() v.mustBe(Slice) - s := (*sliceHeader)(v.ptr) + s := (*unsafeheader.Slice)(v.ptr) if uint(n) > uint(s.Cap) { panic("reflect: slice length out of range in SetLen") } @@ -1442,7 +1457,7 @@ func (v Value) SetLen(n int) { func (v Value) SetCap(n int) { v.mustBeAssignable() v.mustBe(Slice) - s := (*sliceHeader)(v.ptr) + s := (*unsafeheader.Slice)(v.ptr) if n < s.Len || n > s.Cap { panic("reflect: slice capacity out of range in SetCap") } @@ -1544,18 +1559,18 @@ func (v Value) Slice(i, j int) Value { case Slice: typ = (*sliceType)(unsafe.Pointer(v.typ)) - s := (*sliceHeader)(v.ptr) + s := (*unsafeheader.Slice)(v.ptr) base = s.Data cap = s.Cap case String: - s := (*stringHeader)(v.ptr) + s := (*unsafeheader.String)(v.ptr) if i < 0 || j < i || j > s.Len { panic("reflect.Value.Slice: string slice index out of bounds") } - var t stringHeader + var t unsafeheader.String if i < s.Len { - t = stringHeader{arrayAt(s.Data, i, 1, "i < s.Len"), j - i} + t = unsafeheader.String{Data: arrayAt(s.Data, i, 1, "i < s.Len"), Len: j - i} } return Value{v.typ, unsafe.Pointer(&t), v.flag} } @@ -1567,8 +1582,8 @@ func (v Value) Slice(i, j int) Value { // Declare slice so that gc can see the base pointer in it. var x []unsafe.Pointer - // Reinterpret as *sliceHeader to edit. - s := (*sliceHeader)(unsafe.Pointer(&x)) + // Reinterpret as *unsafeheader.Slice to edit. + s := (*unsafeheader.Slice)(unsafe.Pointer(&x)) s.Len = j - i s.Cap = cap - i if cap-i > 0 { @@ -1606,7 +1621,7 @@ func (v Value) Slice3(i, j, k int) Value { case Slice: typ = (*sliceType)(unsafe.Pointer(v.typ)) - s := (*sliceHeader)(v.ptr) + s := (*unsafeheader.Slice)(v.ptr) base = s.Data cap = s.Cap } @@ -1619,8 +1634,8 @@ func (v Value) Slice3(i, j, k int) Value { // can see the base pointer in it. var x []unsafe.Pointer - // Reinterpret as *sliceHeader to edit. - s := (*sliceHeader)(unsafe.Pointer(&x)) + // Reinterpret as *unsafeheader.Slice to edit. + s := (*unsafeheader.Slice)(unsafe.Pointer(&x)) s.Len = j - i s.Cap = k - i if k-i > 0 { @@ -1757,12 +1772,6 @@ type StringHeader struct { Len int } -// stringHeader is a safe version of StringHeader used within this package. -type stringHeader struct { - Data unsafe.Pointer - Len int -} - // SliceHeader is the runtime representation of a slice. // It cannot be used safely or portably and its representation may // change in a later release. @@ -1775,13 +1784,6 @@ type SliceHeader struct { Cap int } -// sliceHeader is a safe version of SliceHeader used within this package. -type sliceHeader struct { - Data unsafe.Pointer - Len int - Cap int -} - func typesMustMatch(what string, t1, t2 Type) { if t1 != t2 { panic(what + ": " + t1.String() + " != " + t2.String()) @@ -1882,22 +1884,22 @@ func Copy(dst, src Value) int { typesMustMatch("reflect.Copy", de, se) } - var ds, ss sliceHeader + var ds, ss unsafeheader.Slice if dk == Array { ds.Data = dst.ptr ds.Len = dst.Len() ds.Cap = ds.Len } else { - ds = *(*sliceHeader)(dst.ptr) + ds = *(*unsafeheader.Slice)(dst.ptr) } if sk == Array { ss.Data = src.ptr ss.Len = src.Len() ss.Cap = ss.Len } else if sk == Slice { - ss = *(*sliceHeader)(src.ptr) + ss = *(*unsafeheader.Slice)(src.ptr) } else { - sh := *(*stringHeader)(src.ptr) + sh := *(*unsafeheader.String)(src.ptr) ss.Data = sh.Data ss.Len = sh.Len ss.Cap = sh.Len @@ -1964,11 +1966,23 @@ type SelectCase struct { // and, if that case was a receive operation, the value received and a // boolean indicating whether the value corresponds to a send on the channel // (as opposed to a zero value received because the channel is closed). +// Select supports a maximum of 65536 cases. func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { + if len(cases) > 65536 { + panic("reflect.Select: too many cases (max 65536)") + } // NOTE: Do not trust that caller is not modifying cases data underfoot. // The range is safe because the caller cannot modify our copy of the len // and each iteration makes its own copy of the value c. - runcases := make([]runtimeSelect, len(cases)) + var runcases []runtimeSelect + if len(cases) > 4 { + // Slice is heap allocated due to runtime dependent capacity. + runcases = make([]runtimeSelect, len(cases)) + } else { + // Slice can be stack allocated due to constant capacity. + runcases = make([]runtimeSelect, len(cases), 4) + } + haveDefault := false for i, c := range cases { rc := &runcases[i] @@ -2073,7 +2087,7 @@ func MakeSlice(typ Type, len, cap int) Value { panic("reflect.MakeSlice: len > cap") } - s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap} + s := unsafeheader.Slice{Data: unsafe_NewArray(typ.Elem().(*rtype), cap), Len: len, Cap: cap} return Value{typ.(*rtype), unsafe.Pointer(&s), flagIndir | flag(Slice)} } @@ -2346,6 +2360,14 @@ func makeFloat(f flag, v float64, t Type) Value { return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} } +// makeFloat returns a Value of type t equal to v, where t is a float32 type. +func makeFloat32(f flag, v float32, t Type) Value { + typ := t.common() + ptr := unsafe_New(typ) + *(*float32)(ptr) = v + return Value{typ, ptr, f | flagIndir | flag(typ.Kind())} +} + // makeComplex returns a Value of type t equal to v (possibly truncated to complex64), // where t is a complex64 or complex128 type. func makeComplex(f flag, v complex128, t Type) Value { @@ -2418,6 +2440,12 @@ func cvtUintFloat(v Value, t Type) Value { // convertOp: floatXX -> floatXX func cvtFloat(v Value, t Type) Value { + if v.Type().Kind() == Float32 && t.Kind() == Float32 { + // Don't do any conversion if both types have underlying type float32. + // This avoids converting to float64 and back, which will + // convert a signaling NaN to a quiet NaN. See issue 36400. + return makeFloat32(v.flag.ro(), *(*float32)(v.ptr), t) + } return makeFloat(v.flag.ro(), v.Float(), t) } @@ -2428,12 +2456,12 @@ func cvtComplex(v Value, t Type) Value { // convertOp: intXX -> string func cvtIntString(v Value, t Type) Value { - return makeString(v.flag.ro(), string(v.Int()), t) + return makeString(v.flag.ro(), string(rune(v.Int())), t) } // convertOp: uintXX -> string func cvtUintString(v Value, t Type) Value { - return makeString(v.flag.ro(), string(v.Uint()), t) + return makeString(v.flag.ro(), string(rune(v.Uint())), t) } // convertOp: []byte -> string @@ -2557,7 +2585,7 @@ func typedmemmove(t *rtype, dst, src unsafe.Pointer) // typedslicecopy copies a slice of elemType values from src to dst, // returning the number of elements copied. //go:noescape -func typedslicecopy(elemType *rtype, dst, src sliceHeader) int +func typedslicecopy(elemType *rtype, dst, src unsafeheader.Slice) int //go:noescape func typehash(t *rtype, p unsafe.Pointer, h uintptr) uintptr |