Skip to content

Commit 7485050

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 2aa7c6c commit 7485050

File tree

2 files changed

+25
-0
lines changed

2 files changed

+25
-0
lines changed

src/reflect/all_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4163,6 +4163,17 @@ func TestConvert(t *testing.T) {
41634163
}
41644164
}
41654165

4166+
func TestConvertNaNs(t *testing.T) {
4167+
const snan uint32 = 0x7f800001
4168+
type myFloat32 float32
4169+
x := V(myFloat32(math.Float32frombits(snan)))
4170+
y := x.Convert(TypeOf(float32(0)))
4171+
z := y.Interface().(float32)
4172+
if got := math.Float32bits(z); got != snan {
4173+
t.Errorf("signaling nan conversion got %x, want %x", got, snan)
4174+
}
4175+
}
4176+
41664177
type ComparableStruct struct {
41674178
X int
41684179
}

src/reflect/value.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2541,6 +2541,14 @@ func makeFloat(f flag, v float64, t Type) Value {
25412541
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
25422542
}
25432543

2544+
// makeFloat returns a Value of type t equal to v, where t is a float32 type.
2545+
func makeFloat32(f flag, v float32, t Type) Value {
2546+
typ := t.common()
2547+
ptr := unsafe_New(typ)
2548+
*(*float32)(ptr) = v
2549+
return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
2550+
}
2551+
25442552
// makeComplex returns a Value of type t equal to v (possibly truncated to complex64),
25452553
// where t is a complex64 or complex128 type.
25462554
func makeComplex(f flag, v complex128, t Type) Value {
@@ -2613,6 +2621,12 @@ func cvtUintFloat(v Value, t Type) Value {
26132621

26142622
// convertOp: floatXX -> floatXX
26152623
func cvtFloat(v Value, t Type) Value {
2624+
if v.Type().Kind() == Float32 && t.Kind() == Float32 {
2625+
// Don't do any conversion if both types have underlying type float32.
2626+
// This avoids converting to float64 and back, which will
2627+
// convert a signaling NaN to a quiet NaN. See issue 36400.
2628+
return makeFloat32(v.flag.ro(), *(*float32)(v.ptr), t)
2629+
}
26162630
return makeFloat(v.flag.ro(), v.Float(), t)
26172631
}
26182632

0 commit comments

Comments
 (0)