aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/reflect
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-07-27 22:27:54 -0700
committerIan Lance Taylor <iant@golang.org>2020-08-01 11:21:40 -0700
commitf75af8c1464e948b5e166cf5ab09ebf0d82fc253 (patch)
tree3ba3299859b504bdeb477727471216bd094a0191 /libgo/go/reflect
parent75a23e59031fe673fc3b2e60fd1fe5f4c70ecb85 (diff)
downloadgcc-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.go323
-rw-r--r--libgo/go/reflect/swapper.go7
-rw-r--r--libgo/go/reflect/value.go118
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