diff --git a/stl/inc/xlocnum b/stl/inc/xlocnum index 47a0b964ee1..a14c070a63e 100644 --- a/stl/inc/xlocnum +++ b/stl/inc/xlocnum @@ -1376,7 +1376,7 @@ protected: const auto _Ngen = static_cast(_CSTD sprintf_s( &_Buf[0], _Buf.size(), _Ffmt(_Fmt, 0, _Iosbase.flags()), static_cast(_Precision), _Val)); - return _Fput(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen); + return _Fput_v2(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen, (_STD isnan)(_Val)); } virtual _OutIt __CLR_OR_THIS_CALL do_put( @@ -1400,7 +1400,7 @@ protected: const auto _Ngen = static_cast(_CSTD sprintf_s( &_Buf[0], _Buf.size(), _Ffmt(_Fmt, 'L', _Iosbase.flags()), static_cast(_Precision), _Val)); - return _Fput(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen); + return _Fput_v2(_Dest, _Iosbase, _Fill, _Buf.c_str(), _Ngen, (_STD isnan)(_Val)); } #pragma warning(pop) @@ -1462,7 +1462,13 @@ private: } _OutIt __CLRCALL_OR_CDECL _Fput(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const char* _Buf, - size_t _Count) const { // put formatted floating-point to _Dest + size_t _Count) const { // TRANSITION, ABI: preserved for binary compatibility + return _Fput_v2(_Dest, _Iosbase, _Fill, _Buf, _Count, false); + } + + template // TRANSITION, ABI + _OutIt _Fput_v2(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const char* _Buf, size_t _Count, + bool _Is_nan_val) const { // put formatted floating-point to _Dest auto _Prefix = static_cast(0 < _Count && (*_Buf == '+' || *_Buf == '-')); const char* _Exps; if ((_Iosbase.flags() & ios_base::floatfield) != ios_base::hexfloat) { @@ -1491,13 +1497,15 @@ private: _Groupstring[_Poff] = _Punct_fac.decimal_point(); } - size_t _Off = _Poff == _Count ? _Eoff : _Poff; - const char* _Pg = &_Grouping[0]; - while (*_Pg != CHAR_MAX && '\0' < *_Pg && static_cast(*_Pg) < _Off - _Prefix) { - // add thousands separator - _Groupstring.insert(_Off -= *_Pg, 1, _Kseparator); - if ('\0' < _Pg[1]) { - ++_Pg; // not last group, advance + if (!_Is_nan_val) { + size_t _Off = _Poff == _Count ? _Eoff : _Poff; + const char* _Pg = &_Grouping[0]; + while (*_Pg != CHAR_MAX && '\0' < *_Pg && static_cast(*_Pg) < _Off - _Prefix) { + // add thousands separator + _Groupstring.insert(_Off -= *_Pg, 1, _Kseparator); + if ('\0' < _Pg[1]) { + ++_Pg; // not last group, advance + } } } diff --git a/tests/std/test.lst b/tests/std/test.lst index 5c0b3ca9533..de424541b82 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -227,6 +227,7 @@ tests\GH_003617_vectorized_meow_element tests\GH_003676_format_large_hh_mm_ss_values tests\GH_003735_char_traits_signatures tests\GH_003840_tellg_when_reading_lf_file_in_text_mode +tests\GH_003867_output_nan tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function diff --git a/tests/std/tests/GH_003867_output_nan/env.lst b/tests/std/tests/GH_003867_output_nan/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_003867_output_nan/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_003867_output_nan/test.cpp b/tests/std/tests/GH_003867_output_nan/test.cpp new file mode 100644 index 00000000000..a0c56d286a0 --- /dev/null +++ b/tests/std/tests/GH_003867_output_nan/test.cpp @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +template +void test_gh_3867() { + // GH-3867 Writing NaN to the output stream with a set locale results in a weird output + ostringstream s; + s.imbue(locale("en-US")); + s << -numeric_limits::quiet_NaN(); + assert(s.str() == "-nan(ind)"); +} + +int main() { + test_gh_3867(); + test_gh_3867(); + test_gh_3867(); +}