aboutsummaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2020-01-06 15:36:42 -0800
committerKeith Randall <khr@golang.org>2020-02-25 02:50:24 +0000
commit7485050c0f55492c0fdfc41f7564f3da37a1a308 (patch)
tree17962833e3ffd8b3acbf6cf7976ecc7fd48c45fc /src/reflect
parent2aa7c6c5488d3ef5d3eeb53488f74d39facd9301 (diff)
downloadgo-7485050c0f55492c0fdfc41f7564f3da37a1a308.tar.gz
go-7485050c0f55492c0fdfc41f7564f3da37a1a308.zip
reflect: when Converting between float32s, don't lose signal NaNs
When converting from float32->float64->float32, any signal NaNs get converted to quiet NaNs. Avoid that so using reflect.Value.Convert between two float32 types keeps the signal bit of NaNs. Update #36400 Change-Id: Ic4dd04c4be7189d2171d12b7e4e8f7cf2fb22bb4 Reviewed-on: https://go-review.googlesource.com/c/go/+/213497 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/reflect')
-rw-r--r--src/reflect/all_test.go11
-rw-r--r--src/reflect/value.go14
2 files changed, 25 insertions, 0 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 00c18104eb..496d0e9241 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -4163,6 +4163,17 @@ func TestConvert(t *testing.T) {
}
}
+func TestConvertNaNs(t *testing.T) {
+ const snan uint32 = 0x7f800001
+ 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 {
+ t.Errorf("signaling nan conversion got %x, want %x", got, snan)
+ }
+}
+
type ComparableStruct struct {
X int
}
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 0f5e083663..d8b5d11cbd 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -2541,6 +2541,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 {
@@ -2613,6 +2621,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)
}