From a4bb668f72effc00d22bc6be81e470891e7b3b04 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 31 May 2023 06:58:38 +0800 Subject: [PATCH 01/11] Move some components from upstream headers to downstream (#3719) Co-authored-by: Casey Carter --- stl/inc/__msvc_iter_core.hpp | 19 ++++++++++++ stl/inc/chrono | 2 +- stl/inc/type_traits | 23 -------------- stl/inc/utility | 44 ++++++++++++++------------- stl/inc/xlocnum | 34 +++++++++++++-------- stl/inc/xloctime | 4 +-- stl/inc/yvals.h | 6 ---- tests/tr1/tests/type_traits1/test.cpp | 42 ------------------------- tests/tr1/tests/utility/test.cpp | 42 +++++++++++++++++++++++++ 9 files changed, 108 insertions(+), 108 deletions(-) diff --git a/stl/inc/__msvc_iter_core.hpp b/stl/inc/__msvc_iter_core.hpp index fe41efa81c8..8a326b97c3e 100644 --- a/stl/inc/__msvc_iter_core.hpp +++ b/stl/inc/__msvc_iter_core.hpp @@ -18,6 +18,25 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN +template +struct _Has_allocator_type : false_type {}; // tests for suitable _Ty::allocator_type + +template +struct _Has_allocator_type<_Ty, _Alloc, void_t> + : is_convertible<_Alloc, typename _Ty::allocator_type>::type {}; + +_EXPORT_STD struct allocator_arg_t { // tag type for added allocator argument + explicit allocator_arg_t() = default; +}; + +_EXPORT_STD _INLINE_VAR constexpr allocator_arg_t allocator_arg{}; + +_EXPORT_STD template +struct uses_allocator : _Has_allocator_type<_Ty, _Alloc>::type {}; + +_EXPORT_STD template +_INLINE_VAR constexpr bool uses_allocator_v = uses_allocator<_Ty, _Alloc>::value; + // from _EXPORT_STD struct input_iterator_tag {}; diff --git a/stl/inc/chrono b/stl/inc/chrono index d896c9e2823..aa4db5e1c7e 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -4145,7 +4145,7 @@ namespace chrono { --_Width; } - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; char* _Ptr = _Ac; if (_First != _Last && _Width > 0) { const char _Ch = _Ctype_fac.narrow(*_First); diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 8703f28b125..13193dc15fb 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -24,29 +24,6 @@ template // TRANSITION, CWG-2518: false value attached to a dependent name (for static_assert) _INLINE_VAR constexpr bool _Always_false = false; -_EXPORT_STD template -struct integer_sequence { // sequence of integer parameters - static_assert(is_integral_v<_Ty>, "integer_sequence requires T to be an integral type."); - - using value_type = _Ty; - - _NODISCARD static constexpr size_t size() noexcept { - return sizeof...(_Vals); - } -}; - -_EXPORT_STD template -using make_integer_sequence = __make_integer_seq; - -_EXPORT_STD template -using index_sequence = integer_sequence; - -_EXPORT_STD template -using make_index_sequence = make_integer_sequence; - -_EXPORT_STD template -using index_sequence_for = make_index_sequence; - template struct _Conjunction { // handle false trait or last trait using type = _First; diff --git a/stl/inc/utility b/stl/inc/utility index 1a27f5e42e1..c3a70f4cb8d 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -31,6 +31,29 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN +_EXPORT_STD template +struct integer_sequence { // sequence of integer parameters + static_assert(is_integral_v<_Ty>, "integer_sequence requires T to be an integral type."); + + using value_type = _Ty; + + _NODISCARD static constexpr size_t size() noexcept { + return sizeof...(_Vals); + } +}; + +_EXPORT_STD template +using make_integer_sequence = __make_integer_seq; + +_EXPORT_STD template +using index_sequence = integer_sequence; + +_EXPORT_STD template +using make_index_sequence = make_integer_sequence; + +_EXPORT_STD template +using index_sequence_for = make_index_sequence; + _EXPORT_STD template _NODISCARD constexpr const _Ty&(max) (const _Ty& _Left, const _Ty& _Right, _Pr _Pred) noexcept( noexcept(_Pred(_Left, _Right))) /* strengthened */ { @@ -107,27 +130,6 @@ _EXPORT_STD struct piecewise_construct_t { // tag type for pair tuple arguments _EXPORT_STD _INLINE_VAR constexpr piecewise_construct_t piecewise_construct{}; -template -struct _Has_allocator_type : false_type {}; // tests for suitable _Ty::allocator_type - -template -struct _Has_allocator_type<_Ty, _Alloc, void_t> - : is_convertible<_Alloc, typename _Ty::allocator_type>::type {}; // tests for suitable _Ty::allocator_type - -_EXPORT_STD struct allocator_arg_t { // tag type for added allocator argument - explicit allocator_arg_t() = default; -}; - -_EXPORT_STD _INLINE_VAR constexpr allocator_arg_t allocator_arg{}; - -_EXPORT_STD template -struct uses_allocator : _Has_allocator_type<_Ty, _Alloc>::type { - // determine whether _Ty has an allocator_type member type -}; - -_EXPORT_STD template -_INLINE_VAR constexpr bool uses_allocator_v = uses_allocator<_Ty, _Alloc>::value; - _EXPORT_STD template class tuple; diff --git a/stl/inc/xlocnum b/stl/inc/xlocnum index 11b92958dbf..47a0b964ee1 100644 --- a/stl/inc/xlocnum +++ b/stl/inc/xlocnum @@ -36,6 +36,8 @@ _END_EXTERN_C_UNLESS_PURE _STD_BEGIN +_INLINE_VAR constexpr size_t _Max_int_dig = 32; // integer properties + inline double _Stodx_v3(const char* _Str, char** _Endptr, int* _Perr) noexcept { // convert string to double int& _Errno_ref = errno; // Nonzero cost, pay it once const int _Orig = _Errno_ref; @@ -364,7 +366,7 @@ protected: break; } } else { // get long value - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; const auto _Parse_result = _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field if (_Parse_result._Base < 0) { @@ -399,7 +401,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, unsigned short& _Val) const { // get unsigned short from [_First, _Last) into _Val _Adl_verify_range(_First, _Last); - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; const auto _Parse_result = _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field" @@ -451,7 +453,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, long& _Val) const { // get long from [_First, _Last) into _Val _Adl_verify_range(_First, _Last); - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; const auto _Parse_result = _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field" @@ -477,7 +479,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, unsigned long& _Val) const { // get unsigned long from [_First, _Last) into _Val _Adl_verify_range(_First, _Last); - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; const auto _Parse_result = _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field" @@ -503,7 +505,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, long long& _Val) const { // get long long from [_First, _Last) into _Val _Adl_verify_range(_First, _Last); - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; const auto _Parse_result = _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field" @@ -529,7 +531,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, unsigned long long& _Val) const { // get unsigned long long from [_First, _Last) into _Val _Adl_verify_range(_First, _Last); - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; const auto _Parse_result = _Parse_int_with_locale(_Ac, _First, _Last, _Iosbase.flags(), _Iosbase.getloc()); // gather field if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field" @@ -552,6 +554,8 @@ protected: return _First; } +#define _MAX_SIG_DIG_V2 768 +#define _MAX_EXP_DIG 8 // for parsing floating-point numbers // Size of char buffer used by num_get::do_get() for float/double/long double #define _FLOATING_BUFFER_SIZE (_MAX_EXP_DIG + _MAX_SIG_DIG_V2 + 16) @@ -607,6 +611,7 @@ protected: return _First; } #undef _FLOATING_BUFFER_SIZE +#undef _MAX_EXP_DIG virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, long double& _Val) const { // get long double from [_First, _Last) into _Val @@ -620,7 +625,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get(_InIt _First, _InIt _Last, ios_base& _Iosbase, ios_base::iostate& _State, void*& _Val) const { // get void pointer from [_First, _Last) into _Val _Adl_verify_range(_First, _Last); - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; const auto _Parse_result = _Parse_int_with_locale(_Ac, _First, _Last, ios_base::hex, _Iosbase.getloc()); // gather field if (_Parse_result._Base < 0) { // ditto "fails to convert the entire field" @@ -730,7 +735,7 @@ private: string _Groups(1, static_cast(_Seendigit)); // Groups are detected in the reversed order of _Groups. size_t _Groups_arr_idx = 0; - for (char* const _Pe = &_Ac[_MAX_INT_DIG - 1]; _First != _Last; ++_First) { // look for digits and separators + for (char* const _Pe = &_Ac[_Max_int_dig - 1]; _First != _Last; ++_First) { // look for digits and separators size_t _Idx = _STD _Find_elem(_Atoms, *_First); if (_Idx < _Dlen) { // got a digit, characterize it and add to group size *_Ptr = _Src[_Idx]; @@ -1118,6 +1123,7 @@ private: return _Parse_result._Base < 0 ? ~_Parse_result._Base : _Parse_result._Base; } +#define _MAX_SIG_DIG_V1 36 // TRANSITION, ABI // TRANSITION, ABI: Sentinel value used by num_get::do_get() // to enable correct "V2" behavior in _Getffld() and _Getffldx() #define _ENABLE_V2_BEHAVIOR 1000000000 @@ -1159,6 +1165,8 @@ private: } #undef _ENABLE_V2_BEHAVIOR +#undef _MAX_SIG_DIG_V1 +#undef _MAX_SIG_DIG_V2 }; #ifdef __clang__ @@ -1313,7 +1321,7 @@ protected: #pragma warning(disable : 4774) // format string expected in argument N is not a string literal (/Wall) virtual _OutIt __CLR_OR_THIS_CALL do_put( _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long _Val) const { // put formatted long to _Dest - char _Buf[2 * _MAX_INT_DIG]; + char _Buf[2 * _Max_int_dig]; char _Fmt[6]; return _Iput(_Dest, _Iosbase, _Fill, _Buf, @@ -1322,7 +1330,7 @@ protected: virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, unsigned long _Val) const { // put formatted unsigned long to _Dest - char _Buf[2 * _MAX_INT_DIG]; + char _Buf[2 * _Max_int_dig]; char _Fmt[6]; return _Iput(_Dest, _Iosbase, _Fill, _Buf, @@ -1331,7 +1339,7 @@ protected: virtual _OutIt __CLR_OR_THIS_CALL do_put( _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, long long _Val) const { // put formatted long long to _Dest - char _Buf[2 * _MAX_INT_DIG]; + char _Buf[2 * _Max_int_dig]; char _Fmt[8]; return _Iput(_Dest, _Iosbase, _Fill, _Buf, @@ -1340,7 +1348,7 @@ protected: virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, unsigned long long _Val) const { // put formatted unsigned long long to _Dest - char _Buf[2 * _MAX_INT_DIG]; + char _Buf[2 * _Max_int_dig]; char _Fmt[8]; return _Iput(_Dest, _Iosbase, _Fill, _Buf, @@ -1398,7 +1406,7 @@ protected: virtual _OutIt __CLR_OR_THIS_CALL do_put( _OutIt _Dest, ios_base& _Iosbase, _Elem _Fill, const void* _Val) const { // put formatted void pointer to _Dest - char _Buf[2 * _MAX_INT_DIG]; + char _Buf[2 * _Max_int_dig]; return _Iput( _Dest, _Iosbase, _Fill, _Buf, static_cast(_CSTD sprintf_s(_Buf, sizeof(_Buf), "%p", _Val))); diff --git a/stl/inc/xloctime b/stl/inc/xloctime index 5a72b853c3c..722feeb3303 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -25,7 +25,7 @@ ios_base::iostate _Getint_v2(_InIt& _First, _InIt& _Last, int _Lo, int _Hi, int& const ctype<_Elem>& _Ctype_fac) { // get integer in range [_Lo, _Hi] from [_First, _Last) _STL_INTERNAL_CHECK(0 <= _Hi && _Hi <= 9999); const int _Hi_digits = (_Hi <= 9 ? 1 : _Hi <= 99 ? 2 : _Hi <= 999 ? 3 : 4); - char _Ac[_MAX_INT_DIG]; + char _Ac[_Max_int_dig]; char* _Ep; char* _Ptr = _Ac; char _Ch; @@ -55,7 +55,7 @@ ios_base::iostate _Getint_v2(_InIt& _First, _InIt& _Last, int _Lo, int _Hi, int& *_Ptr++ = '0'; // replace one or more with single zero } - for (char* const _Pe = &_Ac[_MAX_INT_DIG - 1]; + for (char* const _Pe = &_Ac[_Max_int_dig - 1]; _First != _Last && '0' <= (_Ch = _Ctype_fac.narrow(*_First)) && _Ch <= '9' && _Digits_read < _Hi_digits; ++_Digits_read, (void) ++_First) { // copy digits *_Ptr = _Ch; diff --git a/stl/inc/yvals.h b/stl/inc/yvals.h index 59107cf8135..438543e7f27 100644 --- a/stl/inc/yvals.h +++ b/stl/inc/yvals.h @@ -318,12 +318,6 @@ _EMIT_STL_WARNING(STL4001, "/clr:pure is deprecated and will be REMOVED."); #endif #endif // _CRTDATA2_IMPORT -// integer properties -#define _MAX_EXP_DIG 8 // for parsing numerics -#define _MAX_INT_DIG 32 -#define _MAX_SIG_DIG_V1 36 // TRANSITION, ABI -#define _MAX_SIG_DIG_V2 768 - #define _LOCK_LOCALE 0 #define _LOCK_MALLOC 1 #define _LOCK_STREAM 2 diff --git a/tests/tr1/tests/type_traits1/test.cpp b/tests/tr1/tests/type_traits1/test.cpp index d07015289b0..bcae4d2ef05 100644 --- a/tests/tr1/tests/type_traits1/test.cpp +++ b/tests/tr1/tests/type_traits1/test.cpp @@ -449,46 +449,6 @@ static void t_is_member_function_pointer() { // test is_member_function_pointer< CHECK(STD is_member_function_pointer::value); } -void t_sequence() { // test integer_sequence - typedef STD integer_sequence s0; - CHECK_TYPE(size_t, s0::value_type); - CHECK_INT(s0().size(), 0); - - typedef STD integer_sequence s1; - CHECK_TYPE(size_t, s1::value_type); - CHECK_INT(s1().size(), 1); - - typedef STD integer_sequence s2; - CHECK_TYPE(size_t, s2::value_type); - CHECK_INT(s2().size(), 2); - - typedef STD make_integer_sequence si0; - CHECK_TYPE(si0, STD integer_sequence); - - typedef STD make_integer_sequence si1; - typedef STD integer_sequence si1a; - CHECK_TYPE(si1, si1a); - - typedef STD make_integer_sequence si2; - typedef STD integer_sequence si2a; - CHECK_TYPE(si2, si2a); - - typedef STD make_index_sequence<2> si2b; - - typedef STD index_sequence_for si2d; - CHECK_TYPE(si2b, si2d); - - CHECK_TYPE(s0, STD index_sequence<>); - - CHECK_TYPE(s1, STD index_sequence<2>); - - typedef STD index_sequence<4, 5> s2x; - CHECK_TYPE(s2, s2x); - - typedef STD index_sequence<0, 1> si2c; - CHECK_TYPE(si2b, si2c); -} - void t_aliases() { // test template aliases typedef int Ty; @@ -558,7 +518,5 @@ void test_main() { // test type traits t_is_member_object_pointer(); t_is_member_function_pointer(); - t_sequence(); - t_aliases(); } diff --git a/tests/tr1/tests/utility/test.cpp b/tests/tr1/tests/utility/test.cpp index 8112bc8d663..4539c62e4de 100644 --- a/tests/tr1/tests/utility/test.cpp +++ b/tests/tr1/tests/utility/test.cpp @@ -15,7 +15,49 @@ Pair_ic p0; void fun() { // do nothing } +void t_sequence() { // test integer_sequence + typedef STD integer_sequence s0; + CHECK_TYPE(size_t, s0::value_type); + CHECK_INT(s0().size(), 0); + + typedef STD integer_sequence s1; + CHECK_TYPE(size_t, s1::value_type); + CHECK_INT(s1().size(), 1); + + typedef STD integer_sequence s2; + CHECK_TYPE(size_t, s2::value_type); + CHECK_INT(s2().size(), 2); + + typedef STD make_integer_sequence si0; + CHECK_TYPE(si0, STD integer_sequence); + + typedef STD make_integer_sequence si1; + typedef STD integer_sequence si1a; + CHECK_TYPE(si1, si1a); + + typedef STD make_integer_sequence si2; + typedef STD integer_sequence si2a; + CHECK_TYPE(si2, si2a); + + typedef STD make_index_sequence<2> si2b; + + typedef STD index_sequence_for si2d; + CHECK_TYPE(si2b, si2d); + + CHECK_TYPE(s0, STD index_sequence<>); + + CHECK_TYPE(s1, STD index_sequence<2>); + + typedef STD index_sequence<4, 5> s2x; + CHECK_TYPE(s2, s2x); + + typedef STD index_sequence<0, 1> si2c; + CHECK_TYPE(si2b, si2c); +} + void test_main() { // test basic workings of utility definitions + t_sequence(); + Pair_ic p1 = p0, p2(3, 'a'); CHECK_INT(p1.first, 0); From 15dd2ab644eea96aeb72dcf02d825b5869be6f55 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 30 May 2023 16:31:37 -0700 Subject: [PATCH 02/11] Cleanup elements when `resize` fails in `deque(n)` (#3720) --- stl/inc/deque | 2 + .../test.cpp | 64 +++++++++++++++++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index 2fd2956fc3d..0d84db3cd8b 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -623,7 +623,9 @@ public: : _Mypair(_One_then_variadic_args_t{}, _Al) { _Alproxy_ty _Alproxy(_Getal()); _Container_proxy_ptr12<_Alproxy_ty> _Proxy(_Alproxy, _Get_data()); + _Tidy_guard _Guard{this}; resize(_Count); + _Guard._Target = nullptr; _Proxy._Release(); } diff --git a/tests/std/tests/GH_002769_handle_deque_block_pointers/test.cpp b/tests/std/tests/GH_002769_handle_deque_block_pointers/test.cpp index 2a9e63e4bcc..28d2d7abf24 100644 --- a/tests/std/tests/GH_002769_handle_deque_block_pointers/test.cpp +++ b/tests/std/tests/GH_002769_handle_deque_block_pointers/test.cpp @@ -10,7 +10,7 @@ using namespace std; -size_t fancy_counter = 0; +size_t counter = 0; template class counting_ptr { @@ -18,7 +18,7 @@ class counting_ptr { T* p_; explicit counting_ptr(T* raw_ptr) noexcept : p_(raw_ptr) { - ++fancy_counter; + ++counter; } template @@ -48,8 +48,8 @@ class counting_ptr { } ~counting_ptr() { - assert(fancy_counter != 0); - --fancy_counter; + assert(counter != 0); + --counter; } explicit operator bool() const noexcept { @@ -211,17 +211,69 @@ struct ptr_counting_allocator { #endif // !_HAS_CXX20 }; +size_t count_limit = 0; + +struct live_counter { + live_counter() { + add(); + } + live_counter(const live_counter&) { + add(); + } + live_counter& operator=(const live_counter&) = default; + ~live_counter() { + remove(); + } + + static void add() { + assert(counter <= count_limit); + if (counter == count_limit) { + throw 42; + } + ++counter; + } + static void remove() { + assert(counter <= count_limit); + assert(counter > 0); + --counter; + } +}; + +void test_gh_3717() { + // Also test GH-3717: deque(count) would leak elements if a constructor threw during resize(count) + + // make sure the counter/limit machinery works properly + assert(counter == 0); + count_limit = 8; + { + deque d{8}; + assert(counter == 8); + } + assert(counter == 0); + + // verify that deque(n) cleans up live objects on construction failure + try { + deque{16}; + assert(false); + } catch (const int i) { + assert(i == 42); + assert(counter == 0); + } +} + int main() { { deque> dq{3, 1, 4, 1, 5, 9}; dq.insert(dq.end(), {2, 6, 5, 3, 5, 8}); } - assert(fancy_counter == 0); + assert(counter == 0); { deque> dq(979, 323); dq.insert(dq.begin(), 84, 62); dq.erase(dq.begin() + 64, dq.begin() + 338); } - assert(fancy_counter == 0); + assert(counter == 0); + + test_gh_3717(); } From 29fccab68cd50f08a7073804f725ccbc13780ecf Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 31 May 2023 07:38:21 +0800 Subject: [PATCH 03/11] Remove some workaround for Clang (#3722) Co-authored-by: Casey Carter --- stl/inc/ranges | 79 +---------- stl/inc/xutility | 133 ++++++++---------- .../tests/P1208R6_source_location/test.cpp | 30 ++-- .../tests/P1522R1_difference_type/test.cpp | 8 +- 4 files changed, 79 insertions(+), 171 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index cc5c841ba97..c2013431f35 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -2340,11 +2340,6 @@ namespace ranges { _EXPORT_STD inline constexpr _Filter_fn filter; } // namespace views -#ifdef __clang__ - template // TRANSITION, LLVM-47414 - concept _Can_const_transform = range && regular_invocable>; -#endif // ^^^ workaround ^^^ - _EXPORT_STD template requires view<_Vw> && regular_invocable<_Fn&, range_reference_t<_Vw>> && _Can_reference>> @@ -2708,11 +2703,7 @@ namespace ranges { _NODISCARD constexpr _Iterator begin() const noexcept( noexcept(_RANGES begin(_Range)) && is_nothrow_move_constructible_v>) /* strengthened */ -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Can_const_transform<_Vw, _Fn> -#else // ^^^ workaround / no workaround vvv requires range && regular_invocable> -#endif // TRANSITION, LLVM-47414 { return _Iterator{*this, _RANGES begin(_Range)}; } @@ -2731,11 +2722,7 @@ namespace ranges { // clang-format off _NODISCARD constexpr auto end() const noexcept(noexcept( _RANGES end(_Range)) && is_nothrow_move_constructible_v) /* strengthened */ -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Can_const_transform<_Vw, _Fn> -#else // ^^^ workaround / no workaround vvv requires range && regular_invocable> -#endif // TRANSITION, LLVM-47414 { // clang-format on if constexpr (common_range<_Vw>) { @@ -3070,11 +3057,6 @@ namespace ranges { _EXPORT_STD inline constexpr _Take_fn take; } // namespace views -#ifdef __clang__ - template // TRANSITION, LLVM-47414 - concept _Can_take_while_const = range && indirect_unary_predicate>; -#endif // ^^^ workaround ^^^ - _EXPORT_STD template requires input_range<_Vw> && is_object_v<_Pr> && indirect_unary_predicate> class take_while_view : public view_interface> { @@ -3190,11 +3172,7 @@ namespace ranges { } _NODISCARD constexpr auto begin() const noexcept(noexcept(_RANGES begin(_Range))) /* strengthened */ -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Can_take_while_const<_Vw, _Pr> -#else // ^^^ workaround / no workaround vvv requires range && indirect_unary_predicate> -#endif // TRANSITION, LLVM-47414 { return _RANGES begin(_Range); } @@ -3211,11 +3189,7 @@ namespace ranges { _NODISCARD constexpr auto end() const noexcept( noexcept(_RANGES end(_Range)) && is_nothrow_move_constructible_v<_Sentinel>) /* strengthened */ -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Can_take_while_const<_Vw, _Pr> -#else // ^^^ workaround / no workaround vvv requires range && indirect_unary_predicate> -#endif // TRANSITION, LLVM-47414 { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_Pred, "cannot call end on a take_while_view with no predicate"); @@ -3562,12 +3536,6 @@ namespace ranges { _EXPORT_STD inline constexpr _Drop_while_fn drop_while; } // namespace views -#ifdef __clang__ - template // TRANSITION, LLVM-47414 - concept _Can_const_join = forward_range && is_reference_v> - && input_range>; -#endif // ^^^ workaround ^^^ - template _NODISCARD constexpr _Ty& _As_lvalue(_Ty&& _Val) noexcept { return static_cast<_Ty&>(_Val); @@ -3934,11 +3902,7 @@ namespace ranges { } _NODISCARD constexpr _Iterator begin() const -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Can_const_join<_Vw> -#else // ^^^ workaround / no workaround vvv requires forward_range && is_reference_v<_InnerRng> && input_range<_InnerRng> -#endif // TRANSITION, LLVM-47414 { return _Iterator{*this, _RANGES begin(_Range)}; } @@ -3953,11 +3917,7 @@ namespace ranges { } _NODISCARD constexpr auto end() const -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Can_const_join<_Vw> -#else // ^^^ workaround / no workaround vvv requires forward_range && is_reference_v<_InnerRng> && input_range<_InnerRng> -#endif // TRANSITION, LLVM-47414 { if constexpr (forward_range<_InnerRng> && common_range && common_range<_InnerRng>) { return _Iterator{*this, _RANGES end(_Range)}; @@ -3994,13 +3954,6 @@ namespace ranges { && common_reference_with, range_reference_t<_Pat>> && common_reference_with, range_rvalue_reference_t<_Pat>>; -#ifdef __clang__ - template // TRANSITION, LLVM-47414 - concept _Can_const_join_with = - forward_range && forward_range && is_reference_v> - && input_range>; -#endif // ^^^ workaround ^^^ - _EXPORT_STD template requires view<_Vw> && input_range> && view<_Pat> && _Compatible_joinable_ranges, _Pat> @@ -4450,12 +4403,8 @@ namespace ranges { } _NODISCARD constexpr auto begin() const -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Can_const_join_with<_Vw, _Pat> -#else // ^^^ workaround / no workaround vvv requires forward_range && forward_range && is_reference_v<_InnerRng> && input_range<_InnerRng> -#endif // TRANSITION, LLVM-47414 { return _Iterator{*this, _RANGES begin(_Range)}; } @@ -4472,12 +4421,8 @@ namespace ranges { } _NODISCARD constexpr auto end() const -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Can_const_join_with<_Vw, _Pat> -#else // ^^^ workaround / no workaround vvv requires forward_range && forward_range && is_reference_v<_InnerRng> && input_range<_InnerRng> -#endif // TRANSITION, LLVM-47414 { if constexpr (forward_range<_InnerRng> && common_range<_Vw> && common_range<_InnerRng>) { return _Iterator{*this, _RANGES end(_Range)}; @@ -8013,16 +7958,6 @@ namespace ranges { return _Evaluate_equality_closure(index_sequence_for<_LHSTupleTypes...>{}); } -#ifdef __clang__ - template // TRANSITION, LLVM-47414 - concept _Zip_iter_converts = - _IsConst && (convertible_to, iterator_t> && ...); - - template // TRANSITION, LLVM-47414 - concept _Zip_sent_converts = - _IsConst && (convertible_to, sentinel_t> && ...); -#endif // ^^^ workaround ^^^ - template concept _Zip_transform_constraints = move_constructible<_Func> && is_object_v<_Func> && (sizeof...(_Views) > 0) && (input_range<_Views> && ...) @@ -8074,13 +8009,8 @@ namespace ranges { constexpr _Iterator(_Iterator _Rhs) noexcept( (is_nothrow_convertible_v, iterator_t> && ...)) // strengthened -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Zip_iter_converts<_IsConst, _ViewTypes...> -#else // ^^^ workaround / no workaround vvv requires (_IsConst && (convertible_to, iterator_t> && ...)) -#endif // __clang__ - : _Current(_STD move(_Rhs._Current)) { - } + : _Current(_STD move(_Rhs._Current)) {} _NODISCARD constexpr auto operator*() const noexcept((noexcept(*(_STD declval>&>())) @@ -8285,13 +8215,8 @@ namespace ranges { constexpr _Sentinel(_Sentinel _Rhs) noexcept( (is_nothrow_convertible_v, sentinel_t> && ...)) // strengthened -#ifdef __clang__ // TRANSITION, LLVM-47414 - requires _Zip_sent_converts<_IsConst, _ViewTypes...> -#else // ^^^ workaround / no workaround vvv requires (_IsConst && (convertible_to, sentinel_t> && ...)) -#endif // __clang__ - : _End(_STD move(_Rhs._End)) { - } + : _End(_STD move(_Rhs._End)) {} template requires (sentinel_for>, diff --git a/stl/inc/xutility b/stl/inc/xutility index 82888aab50e..b66c5180f06 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1975,10 +1975,8 @@ struct _Const_sentinel<_Sent> { _EXPORT_STD template using const_sentinel = typename _Const_sentinel<_Sent>::type; -// clang-format off template concept _Not_a_const_iterator = !_Is_specialization_v<_Ty, basic_const_iterator>; -// clang-format on template struct _Basic_const_iterator_category {}; @@ -1988,18 +1986,6 @@ struct _Basic_const_iterator_category<_Iter> { using iterator_category = typename iterator_traits<_Iter>::iterator_category; }; -// TRANSITION, LLVM-55945: These are distinct concepts as a workaround -template -concept _Bci_order = _Different_from<_Ty, basic_const_iterator<_Iter>> && random_access_iterator<_Iter> - && totally_ordered_with<_Iter, _Ty>; - -template -concept _Bci_order_3way = _Bci_order<_Ty, _Iter> && three_way_comparable_with<_Iter, _Ty>; - -template -concept _Not_bci_order = - _Not_a_const_iterator<_Ty> && random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Ty>; - _EXPORT_STD template class basic_const_iterator : public _Basic_const_iterator_category<_Iter> { private: @@ -2168,55 +2154,65 @@ public: return _Current <=> _Right._Current; } - template <_Bci_order<_Iter> _Other> + template <_Different_from _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> _NODISCARD constexpr bool operator<(const _Other& _Right) const noexcept(noexcept(_Fake_copy_init(_Current < _Right))) /* strengthened */ { return _Current < _Right; } - template <_Bci_order<_Iter> _Other> + template <_Different_from _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> _NODISCARD constexpr bool operator>(const _Other& _Right) const noexcept(noexcept(_Fake_copy_init(_Current > _Right))) /* strengthened */ { return _Current > _Right; } - template <_Bci_order<_Iter> _Other> + template <_Different_from _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> _NODISCARD constexpr bool operator<=(const _Other& _Right) const noexcept(noexcept(_Fake_copy_init(_Current <= _Right))) /* strengthened */ { return _Current <= _Right; } - template <_Bci_order<_Iter> _Other> + template <_Different_from _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> _NODISCARD constexpr bool operator>=(const _Other& _Right) const noexcept(noexcept(_Fake_copy_init(_Current >= _Right))) /* strengthened */ { return _Current >= _Right; } - template <_Bci_order_3way<_Iter> _Other> + template <_Different_from _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> + && three_way_comparable_with<_Iter, _Other> _NODISCARD constexpr auto operator<=>(const _Other& _Right) const noexcept(noexcept(_Current <=> _Right)) /* strengthened */ { return _Current <=> _Right; } - template <_Not_bci_order<_Iter> _Other> + template <_Not_a_const_iterator _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> _NODISCARD_FRIEND constexpr bool operator<(const _Other& _Left, const basic_const_iterator& _Right) noexcept( noexcept(_Fake_copy_init(_Left < _Right._Current))) /* strengthened */ { return _Left < _Right._Current; } - template <_Not_bci_order<_Iter> _Other> + template <_Not_a_const_iterator _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> _NODISCARD_FRIEND constexpr bool operator>(const _Other& _Left, const basic_const_iterator& _Right) noexcept( noexcept(_Fake_copy_init(_Left > _Right._Current))) /* strengthened */ { return _Left > _Right._Current; } - template <_Not_bci_order<_Iter> _Other> + template <_Not_a_const_iterator _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> _NODISCARD_FRIEND constexpr bool operator<=(const _Other& _Left, const basic_const_iterator& _Right) noexcept( noexcept(_Fake_copy_init(_Left <= _Right._Current))) /* strengthened */ { return _Left <= _Right._Current; } - template <_Not_bci_order<_Iter> _Other> + template <_Not_a_const_iterator _Other> + requires random_access_iterator<_Iter> && totally_ordered_with<_Iter, _Other> _NODISCARD_FRIEND constexpr bool operator>=(const _Other& _Left, const basic_const_iterator& _Right) noexcept( noexcept(_Fake_copy_init(_Left >= _Right._Current))) /* strengthened */ { return _Left >= _Right._Current; @@ -2669,29 +2665,19 @@ namespace ranges { _NODISCARD constexpr auto _As_const_pointer(const _Ty* _Ptr) noexcept { return _Ptr; } - - template - using _Begin_on_const = decltype(_RANGES begin(_RANGES _Possibly_const_range(_STD declval<_Ty&>()))); - - // TRANSITION, LLVM-55945 - template - concept _Range_accessible_and_begin_adaptable = _Should_range_access<_Ty> && requires(_Ty& _Val) { - const_iterator<_Begin_on_const<_Ty>>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}; - }; - - template - using _End_on_const = decltype(_RANGES end(_RANGES _Possibly_const_range(_STD declval<_Ty&>()))); - - // TRANSITION, LLVM-55945 - template - concept _Range_accessible_and_end_adaptable = _Should_range_access<_Ty> && requires(_Ty& _Val) { - const_sentinel<_End_on_const<_Ty>>{_RANGES end(_RANGES _Possibly_const_range(_Val))}; - }; #endif // _HAS_CXX23 struct _Cbegin_fn { #if _HAS_CXX23 - template <_Range_accessible_and_begin_adaptable _Ty> + template + using _Begin_on_const = decltype(_RANGES begin(_RANGES _Possibly_const_range(_STD declval<_Ty&>()))); + + template <_Should_range_access _Ty> + requires requires(_Ty& _Val) { + typename _Begin_on_const<_Ty>; + typename const_iterator<_Begin_on_const<_Ty>>; + const_iterator<_Begin_on_const<_Ty>>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}; + } _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept( noexcept(const_iterator<_Begin_on_const<_Ty>>{_RANGES begin(_RANGES _Possibly_const_range(_Val))})) { return const_iterator<_Begin_on_const<_Ty>>{_RANGES begin(_RANGES _Possibly_const_range(_Val))}; @@ -2713,7 +2699,15 @@ namespace ranges { struct _Cend_fn { #if _HAS_CXX23 - template <_Range_accessible_and_end_adaptable _Ty> + template + using _End_on_const = decltype(_RANGES end(_RANGES _Possibly_const_range(_STD declval<_Ty&>()))); + + template <_Should_range_access _Ty> + requires requires(_Ty& _Val) { + typename _End_on_const<_Ty>; + typename const_sentinel<_End_on_const<_Ty>>; + const_sentinel<_End_on_const<_Ty>>{_RANGES end(_RANGES _Possibly_const_range(_Val))}; + } _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(noexcept(const_sentinel<_End_on_const<_Ty>>{_RANGES end(_RANGES _Possibly_const_range(_Val))})) { return const_sentinel<_End_on_const<_Ty>>{_RANGES end(_RANGES _Possibly_const_range(_Val))}; @@ -2872,29 +2866,17 @@ namespace ranges { _EXPORT_STD inline constexpr _Rend::_Cpo rend; } -#if _HAS_CXX23 - template - using _Rbegin_on_const = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(_STD declval<_Ty&>()))); - - // TRANSITION, LLVM-55945 - template - concept _Range_accessible_and_rbegin_adaptable = _Should_range_access<_Ty> && requires(_Ty& _Val) { - const_iterator<_Rbegin_on_const<_Ty>>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}; - }; - - template - using _Rend_on_const = decltype(_RANGES rend(_RANGES _Possibly_const_range(_STD declval<_Ty&>()))); - - // TRANSITION, LLVM-55945 - template - concept _Range_accessible_and_rend_adaptable = _Should_range_access<_Ty> && requires(_Ty& _Val) { - const_sentinel<_Rend_on_const<_Ty>>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}; - }; -#endif // _HAS_CXX23 - struct _Crbegin_fn { #if _HAS_CXX23 - template <_Range_accessible_and_rbegin_adaptable _Ty> + template + using _Rbegin_on_const = decltype(_RANGES rbegin(_RANGES _Possibly_const_range(_STD declval<_Ty&>()))); + + template <_Should_range_access _Ty> + requires requires(_Ty& _Val) { + typename _Rbegin_on_const<_Ty>; + typename const_iterator<_Rbegin_on_const<_Ty>>; + const_iterator<_Rbegin_on_const<_Ty>>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}; + } _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept( noexcept(const_iterator<_Rbegin_on_const<_Ty>>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))})) { return const_iterator<_Rbegin_on_const<_Ty>>{_RANGES rbegin(_RANGES _Possibly_const_range(_Val))}; @@ -2916,7 +2898,15 @@ namespace ranges { struct _Crend_fn { #if _HAS_CXX23 - template <_Range_accessible_and_rend_adaptable _Ty> + template + using _Rend_on_const = decltype(_RANGES rend(_RANGES _Possibly_const_range(_STD declval<_Ty&>()))); + + template <_Should_range_access _Ty> + requires requires(_Ty& _Val) { + typename _Rend_on_const<_Ty>; + typename const_sentinel<_Rend_on_const<_Ty>>; + const_sentinel<_Rend_on_const<_Ty>>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}; + } _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(noexcept(const_sentinel<_Rend_on_const<_Ty>>{_RANGES rend(_RANGES _Possibly_const_range(_Val))})) { return const_sentinel<_Rend_on_const<_Ty>>{_RANGES rend(_RANGES _Possibly_const_range(_Val))}; @@ -3139,17 +3129,12 @@ namespace ranges { _EXPORT_STD inline constexpr _Data::_Cpo data; } -#if _HAS_CXX23 - // TRANSITION, LLVM-55945 - template - concept _Range_accessible_and_data_adaptable = _Should_range_access<_Ty> && requires(_Ty& _Val) { - _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val))); - }; -#endif // _HAS_CXX23 - struct _Cdata_fn { #if _HAS_CXX23 - template <_Range_accessible_and_data_adaptable _Ty> + template <_Should_range_access _Ty> + requires requires(_Ty& _Val) { // + _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val))); + } _NODISCARD constexpr auto operator()(_Ty&& _Val) const noexcept(noexcept(_RANGES data(_RANGES _Possibly_const_range(_Val)))) { return _RANGES _As_const_pointer(_RANGES data(_RANGES _Possibly_const_range(_Val))); diff --git a/tests/std/tests/P1208R6_source_location/test.cpp b/tests/std/tests/P1208R6_source_location/test.cpp index 671fc0b33ee..d41dc8d3194 100644 --- a/tests/std/tests/P1208R6_source_location/test.cpp +++ b/tests/std/tests/P1208R6_source_location/test.cpp @@ -82,22 +82,26 @@ constexpr void sloc_constructor_test() { const s x; assert(x.loc.line() == __LINE__ - 1); assert(x.loc.column() == 13); +#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 + assert(x.loc.function_name() == "sloc_constructor_test"sv); +#else // ^^^ workaround / no workaround vvv if (is_constant_evaluated()) { assert(x.loc.function_name() == "int __cdecl main(void)"sv); // TRANSITION, VSO-1285783 } else { -#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 - assert(x.loc.function_name() == "sloc_constructor_test"sv); -#else // ^^^ workaround / no workaround vvv assert(x.loc.function_name() == "void __cdecl sloc_constructor_test(void)"sv); -#endif // TRANSITION, DevCom-10199227 and LLVM-58951 } +#endif // TRANSITION, DevCom-10199227 and LLVM-58951 assert(string_view{x.loc.file_name()}.ends_with(test_cpp)); } constexpr void different_constructor_test() { const s x{1}; assert(x.loc.line() == s_int_line); +#ifdef __clang__ + assert(x.loc.column() == 15); +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv assert(x.loc.column() == 5); +#endif // ^^^ !defined(__clang__) ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(x.loc.function_name() == "s"sv); #elif defined(_M_IX86) // ^^^ workaround / no workaround vvv @@ -112,20 +116,24 @@ constexpr void sub_member_test() { const s2 s; assert(s.x.loc.line() == __LINE__ - 1); assert(s.x.loc.column() == 14); +#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 + assert(s.x.loc.function_name() == "sub_member_test"sv); +#else // ^^^ workaround / no workaround vvv if (is_constant_evaluated()) { assert(s.x.loc.function_name() == "int __cdecl main(void)"sv); // TRANSITION, VSO-1285783 } else { -#if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 - assert(s.x.loc.function_name() == "sub_member_test"sv); -#else // ^^^ workaround / no workaround vvv assert(s.x.loc.function_name() == "void __cdecl sub_member_test(void)"sv); -#endif // TRANSITION, DevCom-10199227 and LLVM-58951 } +#endif // TRANSITION, DevCom-10199227 and LLVM-58951 assert(string_view{s.x.loc.file_name()}.ends_with(test_cpp)); const s2 s_i{1}; assert(s_i.x.loc.line() == s2_int_line); +#ifdef __clang__ + assert(s_i.x.loc.column() == 15); +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv assert(s_i.x.loc.column() == 5); +#endif // ^^^ !defined(__clang__) ^^^ #if defined(__clang__) || defined(__EDG__) // TRANSITION, DevCom-10199227 and LLVM-58951 assert(s_i.x.loc.function_name() == "s2"sv); #elif defined(_M_IX86) // ^^^ workaround / no workaround vvv @@ -201,21 +209,17 @@ constexpr void function_template_test() { constexpr bool test() { copy_test(); local_test(); -#ifndef __clang__ // TRANSITION, LLVM-56379 argument_test(__LINE__, 5); -#endif // __clang__ #ifdef __clang__ const auto loc = source_location::current(); argument_test(__LINE__ - 1, 22, loc); -#else // ^^^ defined(__clang__) / !defined(__clang__) +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv const auto loc = source_location::current(); argument_test(__LINE__ - 1, 39, loc); #endif // ^^^ !defined(__clang__) ^^^ -#ifndef __clang__ // TRANSITION, LLVM-56379 sloc_constructor_test(); different_constructor_test(); sub_member_test(); -#endif // __clang__ lambda_test(); function_template_test(); header_test(); diff --git a/tests/std/tests/P1522R1_difference_type/test.cpp b/tests/std/tests/P1522R1_difference_type/test.cpp index fa26a332c6a..e2a1dc731b8 100644 --- a/tests/std/tests/P1522R1_difference_type/test.cpp +++ b/tests/std/tests/P1522R1_difference_type/test.cpp @@ -41,12 +41,6 @@ namespace ordtest { #define CONSTEVAL constexpr #endif // ^^^ !_HAS_CXX20 ^^^ -#if _HAS_CXX20 && !defined(__clang__) // TRANSITION, LLVM-51840 -#define CONSTEVAL_CLANG_WORKAROUND consteval -#else // ^^^ _HAS_CXX20 && !defined(__clang__) / !_HAS_CXX20 || defined(__clang__) vvv -#define CONSTEVAL_CLANG_WORKAROUND constexpr -#endif // ^^^ !_HAS_CXX20 || defined(__clang__) ^^^ - using std::_Signed128; using std::_Unsigned128; @@ -62,7 +56,7 @@ namespace i128_udl_detail { _Unsigned128 value; }; - [[nodiscard]] CONSTEVAL_CLANG_WORKAROUND unsigned int char_to_digit(const char c) noexcept { + [[nodiscard]] CONSTEVAL unsigned int char_to_digit(const char c) noexcept { if (c >= '0' && c <= '9') { return static_cast(c - '0'); } From 349279ffaceebcc01c53b89acbaa5347a35ff9c4 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Wed, 31 May 2023 06:40:41 +0700 Subject: [PATCH 04/11] remove `operator>>` for `istream >> setfill(c)` (#3725) Co-authored-by: Stephan T. Lavavej --- stl/inc/iomanip | 9 --------- .../test.compile.pass.cpp | 16 +++++++++++----- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/stl/inc/iomanip b/stl/inc/iomanip index 60a049221ab..8884dc94bae 100644 --- a/stl/inc/iomanip +++ b/stl/inc/iomanip @@ -25,15 +25,6 @@ template struct _Fillobj { // store fill character _Fillobj(_Elem _Ch) : _Fill(_Ch) {} - template - friend basic_istream<_Elem2, _Traits>& operator>>(basic_istream<_Elem2, _Traits>& _Istr, const _Fillobj& _Manip) { - // set fill character in input stream - static_assert(is_same_v<_Elem, _Elem2>, "wrong character type for setfill"); - - _Istr.fill(_Manip._Fill); - return _Istr; - } - template friend basic_ostream<_Elem2, _Traits>& operator<<(basic_ostream<_Elem2, _Traits>& _Ostr, const _Fillobj& _Manip) { // set fill character in output stream diff --git a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp index 39008f01464..7ade4b41b17 100644 --- a/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_iterators_misc/test.compile.pass.cpp @@ -571,11 +571,11 @@ void future_test() { } #endif // _M_CEE_PURE -template -void iomanip_test_impl(IoManipIn in, IoManipOut out) { +template +void iomanip_test_impl(IoManipOut out, IoManipIn in) { stringstream ss{}; - ss << in; - ss >> out; + ss << out; + ss >> in; } template @@ -583,6 +583,12 @@ void iomanip_test_impl(IoManip iom) { iomanip_test_impl(iom, iom); } +template +void iomanip_test_impl_for_setfill(IoManip out) { + stringstream ss{}; + ss << out; +} + void iomanip_test() { auto sf = setfill('*'); long double money = 123.45; @@ -591,7 +597,7 @@ void iomanip_test() { localtime_s(&time, &t); string str = "string with \" quotes "; - iomanip_test_impl(sf); + iomanip_test_impl_for_setfill(sf); iomanip_test_impl(put_money(money), get_money(money)); iomanip_test_impl(put_time(&time, "%c %Z"), get_time(&time, "%c %Z")); iomanip_test_impl(quoted(str.c_str()), quoted(str)); From 0f297153c35988323a115fcca9a411d0c5344c82 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 31 May 2023 07:47:55 +0800 Subject: [PATCH 05/11] ``: Diagnose the precondition added by LWG-3597 (#3731) Co-authored-by: Stephan T. Lavavej --- stl/inc/ranges | 9 ++- tests/std/test.lst | 1 + .../tests/P0896R4_views_iota_death/env.lst | 4 + .../tests/P0896R4_views_iota_death/test.cpp | 81 +++++++++++++++++++ 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 tests/std/tests/P0896R4_views_iota_death/env.lst create mode 100644 tests/std/tests/P0896R4_views_iota_death/test.cpp diff --git a/stl/inc/ranges b/stl/inc/ranges index c2013431f35..6a5238a58fb 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -1333,13 +1333,18 @@ namespace ranges { constexpr explicit iota_view(_Wi _Value_) noexcept( is_nothrow_move_constructible_v<_Wi>&& is_nothrow_default_constructible_v<_Bo>) // strengthened - : _Value(_STD move(_Value_)) {} + : _Value(_STD move(_Value_)) { + if constexpr (totally_ordered_with<_Wi, _Bo>) { + _STL_ASSERT(_Value_ <= _Bound, "Per N4950 [range.iota.view]/6, the first argument must not exceed the " + "value-initialized bound when their types are totally ordered."); + } + } constexpr explicit iota_view(type_identity_t<_Wi> _Value_, type_identity_t<_Bo> _Bound_) noexcept( is_nothrow_move_constructible_v<_Wi>&& is_nothrow_move_constructible_v<_Bo>) // strengthened : _Value(_STD move(_Value_)), _Bound(_STD move(_Bound_)) { if constexpr (totally_ordered_with<_Wi, _Bo>) { - _STL_ASSERT(_Value_ <= _Bound_, "Per N4950 [range.iota.view]/8, the first argument must precede the " + _STL_ASSERT(_Value_ <= _Bound_, "Per N4950 [range.iota.view]/8, the first argument must not exceed the " "second when their types are totally ordered."); } } diff --git a/tests/std/test.lst b/tests/std/test.lst index 9ec3885fdd8..d0707da3e0f 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -455,6 +455,7 @@ tests\P0896R4_views_filter tests\P0896R4_views_filter_death tests\P0896R4_views_filter_iterator tests\P0896R4_views_iota +tests\P0896R4_views_iota_death tests\P0896R4_views_join tests\P0896R4_views_lazy_split tests\P0896R4_views_reverse diff --git a/tests/std/tests/P0896R4_views_iota_death/env.lst b/tests/std/tests/P0896R4_views_iota_death/env.lst new file mode 100644 index 00000000000..d6d824b5879 --- /dev/null +++ b/tests/std/tests/P0896R4_views_iota_death/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_20_matrix.lst diff --git a/tests/std/tests/P0896R4_views_iota_death/test.cpp b/tests/std/tests/P0896R4_views_iota_death/test.cpp new file mode 100644 index 00000000000..fc606cb372e --- /dev/null +++ b/tests/std/tests/P0896R4_views_iota_death/test.cpp @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +#include +using namespace std; + +template +void test_misordered_start_bound_int() { + ranges::iota_view{I{42}, I{1}}; +} + +template +void test_misordered_start_bound_uint_value_init() { + ranges::iota_view{UI{42}}; +} + +template +void test_misordered_start_bound_ptr() { + T arr[1]{}; + ranges::iota_view{arr + 1, arr + 0}; +} + +template +void test_misordered_start_bound_vector_iter() { + vector vec(1); + ranges::iota_view{vec.end(), vec.begin()}; +} + +int main(int argc, char* argv[]) { + std_testing::death_test_executive exec; + +#ifdef _DEBUG + struct S {}; + + exec.add_death_tests({ + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + + test_misordered_start_bound_int, +#ifdef __cpp_char8_t + test_misordered_start_bound_int, +#endif // __cpp_char8_t + test_misordered_start_bound_int, + test_misordered_start_bound_int, + test_misordered_start_bound_int, + + test_misordered_start_bound_uint_value_init, + test_misordered_start_bound_uint_value_init, + test_misordered_start_bound_uint_value_init, + test_misordered_start_bound_uint_value_init, + test_misordered_start_bound_uint_value_init, +#ifdef __cpp_char8_t + test_misordered_start_bound_uint_value_init, +#endif // __cpp_char8_t + test_misordered_start_bound_uint_value_init, + test_misordered_start_bound_uint_value_init, + test_misordered_start_bound_uint_value_init, + + test_misordered_start_bound_ptr, + test_misordered_start_bound_ptr, + test_misordered_start_bound_ptr, + + test_misordered_start_bound_vector_iter, + test_misordered_start_bound_vector_iter, + test_misordered_start_bound_vector_iter, + }); +#endif // _DEBUG + + return exec.run(argc, argv); +} From d08d14c1811ccb018fa6737c95fd0e29a2b54fef Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 30 May 2023 16:55:31 -0700 Subject: [PATCH 06/11] Support x64-only symbols on ARM64EC (#3732) --- CMakeLists.txt | 9 +++ stl/CMakeLists.txt | 8 ++- stl/src/vector_algorithms.cpp | 105 ++++++++++++++++++++++++---------- stl/src/xonce2.cpp | 5 +- 4 files changed, 91 insertions(+), 36 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ad971dad468..47f6022e0fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,8 @@ set(VCLIBS_SUFFIX "_oss" CACHE STRING "suffix for built DLL names to avoid confl option(STL_USE_ANALYZE "Pass the /analyze flag to MSVC" OFF) +set(VCLIBS_EXPLICIT_MACHINE "") + if("${VCLIBS_TARGET_ARCHITECTURE}" MATCHES "^x86$") set(VCLIBS_TARGET_ARCHITECTURE "x86") set(VCLIBS_I386_OR_AMD64 "i386") @@ -71,6 +73,13 @@ elseif(VCLIBS_TARGET_ARCHITECTURE MATCHES "^arm64$") set(VCLIBS_I386_OR_AMD64 "arm64") set(VCLIBS_X86_OR_X64 "arm64") add_compile_definitions(_ARM64_ _VCRT_WIN32_WINNT=0x0A00 _STL_WIN32_WINNT=0x0A00) +elseif(VCLIBS_TARGET_ARCHITECTURE MATCHES "^arm64ec$") + set(VCLIBS_TARGET_ARCHITECTURE "arm64ec") + set(VCLIBS_I386_OR_AMD64 "arm64ec") + set(VCLIBS_X86_OR_X64 "arm64") # Yes, really: `%VCToolsInstallDir%lib\arm64ec` only contains the Link Options + add_compile_definitions(_AMD64_ _ARM64EC_ _VCRT_WIN32_WINNT=0x0501 _STL_WIN32_WINNT=0x0501) + add_compile_options($<$:/arm64EC>) + set(VCLIBS_EXPLICIT_MACHINE "/machine:arm64ec") else() message(FATAL_ERROR "Could not determine target architecture: VCLIBS_TARGET_ARCHITECTURE: ${VCLIBS_TARGET_ARCHITECTURE}") endif() diff --git a/stl/CMakeLists.txt b/stl/CMakeLists.txt index 6c2e456eedf..8cc4f64b719 100644 --- a/stl/CMakeLists.txt +++ b/stl/CMakeLists.txt @@ -552,8 +552,8 @@ function(generate_satellite_def SATELLITE_NAME D_SUFFIX) endfunction() function(add_stl_dlls D_SUFFIX REL_OR_DBG) - set(link_options_Release "/LTCG;/opt:ref,icf") - set(link_options_Debug "/opt:ref,noicf") + set(link_options_Release "/LTCG;/opt:ref,icf;${VCLIBS_EXPLICIT_MACHINE}") + set(link_options_Debug "/opt:ref,noicf;${VCLIBS_EXPLICIT_MACHINE}") set(gl_flag_Release "/GL") set(gl_flag_Debug "") @@ -652,7 +652,7 @@ function(add_stl_dlls D_SUFFIX REL_OR_DBG) add_library(msvcp${D_SUFFIX}_implib STATIC ${HEADERS}) target_link_libraries(msvcp${D_SUFFIX}_implib stl_alias_objects msvcp${D_SUFFIX}_implib_objects) add_dependencies(msvcp${D_SUFFIX}_implib msvcp${D_SUFFIX} msvcp_1${D_SUFFIX} msvcp_2${D_SUFFIX} msvcp${D_SUFFIX}_atomic_wait msvcp${D_SUFFIX}_codecvt_ids) - set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$;$") + set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES STATIC_LIBRARY_OPTIONS "/NOLOGO;/NODEFAULTLIB;/IGNORE:4006;$;$;$;$;$;${VCLIBS_EXPLICIT_MACHINE}") set_target_properties(msvcp${D_SUFFIX}_implib PROPERTIES ARCHIVE_OUTPUT_NAME "msvcprt${D_SUFFIX}") endfunction() @@ -670,6 +670,7 @@ function(add_stl_statics FLAVOR_SUFFIX REL_OR_DBG IDL_VALUE) target_compile_options(libcpmt${FLAVOR_SUFFIX} PRIVATE "$<$:/EHsc>") target_link_libraries(libcpmt${FLAVOR_SUFFIX} PRIVATE Boost::math stl_alias_objects libcpmt${FLAVOR_SUFFIX}_eha) target_stl_compile_options(libcpmt${FLAVOR_SUFFIX} ${REL_OR_DBG}) + set_target_properties(libcpmt${FLAVOR_SUFFIX} PROPERTIES STATIC_LIBRARY_OPTIONS "${VCLIBS_EXPLICIT_MACHINE}") endfunction() add_stl_statics("" Release 0) @@ -679,6 +680,7 @@ add_stl_statics("d1" Debug 1) add_stl_statics("d0" Debug 0) add_library(stl_asan STATIC ${ASAN_SOURCES}) +set_target_properties(stl_asan PROPERTIES STATIC_LIBRARY_OPTIONS "${VCLIBS_EXPLICIT_MACHINE}") configure_file(set_environment.bat.in "${PROJECT_BINARY_DIR}/set_environment.bat" @ONLY) configure_file(set_environment.ps1.in "${PROJECT_BINARY_DIR}/set_environment.ps1" @ONLY) diff --git a/stl/src/vector_algorithms.cpp b/stl/src/vector_algorithms.cpp index a33e059209d..7c1d0eb7143 100644 --- a/stl/src/vector_algorithms.cpp +++ b/stl/src/vector_algorithms.cpp @@ -5,9 +5,9 @@ #error _M_CEE_PURE should not be defined when compiling vector_algorithms.cpp. #endif -#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_ARM64EC) - +#if defined(_M_IX86) || defined(_M_X64) // NB: includes _M_ARM64EC #include +#ifndef _M_ARM64EC #include #include @@ -34,6 +34,20 @@ namespace { #endif // _M_IX86 } + struct [[nodiscard]] _Zeroupper_on_exit { // TRANSITION, DevCom-10331414 + _Zeroupper_on_exit() = default; + + _Zeroupper_on_exit(const _Zeroupper_on_exit&) = delete; + _Zeroupper_on_exit& operator=(const _Zeroupper_on_exit&) = delete; + + ~_Zeroupper_on_exit() { + _mm256_zeroupper(); + } + }; +} // namespace +#endif // !defined(_M_ARM64EC) + +namespace { template void _Reverse_tail(_BidIt _First, _BidIt _Last) noexcept { for (; _First != _Last && _First != --_Last; ++_First) { @@ -61,19 +75,6 @@ namespace { void _Advance_bytes(const void*& _Target, ptrdiff_t _Offset) noexcept { _Target = static_cast(_Target) + _Offset; } - - // TRANSITION, DevCom-10331414 - struct [[nodiscard]] _Zeroupper_on_exit { - _Zeroupper_on_exit() = default; - - _Zeroupper_on_exit(const _Zeroupper_on_exit&) = delete; - _Zeroupper_on_exit& operator=(const _Zeroupper_on_exit&) = delete; - - ~_Zeroupper_on_exit() { - _mm256_zeroupper(); - } - }; - } // unnamed namespace extern "C" { @@ -85,6 +86,7 @@ struct _Min_max_element_t { __declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias( void* _First1, void* _Last1, void* _First2) noexcept { +#ifndef _M_ARM64EC constexpr size_t _Mask_32 = ~((static_cast(1) << 5) - 1); if (_Byte_length(_First1, _Last1) >= 32 && _Use_avx2()) { const void* _Stop_at = _First1; @@ -146,6 +148,7 @@ __declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias( #else #error Unsupported architecture #endif +#endif // !_M_ARM64EC auto _First1c = static_cast(_First1); auto _Last1c = static_cast(_Last1); @@ -164,6 +167,7 @@ void* __cdecl __std_swap_ranges_trivially_swappable(void* _First1, void* _Last1, } __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_1(void* _First, void* _Last) noexcept { +#ifndef _M_ARM64EC if (_Byte_length(_First, _Last) >= 64 && _Use_avx2()) { const __m256i _Reverse_char_lanes_avx = _mm256_set_epi8( // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // @@ -203,11 +207,13 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_1(void* _Firs _Advance_bytes(_First, 16); } while (_First != _Stop_at); } +#endif // !_M_ARM64EC _Reverse_tail(static_cast(_First), static_cast(_Last)); } __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_2(void* _First, void* _Last) noexcept { +#ifndef _M_ARM64EC if (_Byte_length(_First, _Last) >= 64 && _Use_avx2()) { const __m256i _Reverse_short_lanes_avx = _mm256_set_epi8( // 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, // @@ -245,11 +251,13 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_2(void* _Firs _Advance_bytes(_First, 16); } while (_First != _Stop_at); } +#endif // !_M_ARM64EC _Reverse_tail(static_cast(_First), static_cast(_Last)); } __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_4(void* _First, void* _Last) noexcept { +#ifndef _M_ARM64EC if (_Byte_length(_First, _Last) >= 64 && _Use_avx2()) { const void* _Stop_at = _First; _Advance_bytes(_Stop_at, (_Byte_length(_First, _Last) >> 1) & ~size_t{0x1F}); @@ -282,11 +290,13 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_4(void* _Firs _Advance_bytes(_First, 16); } while (_First != _Stop_at); } +#endif // !_M_ARM64EC _Reverse_tail(static_cast(_First), static_cast(_Last)); } __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_8(void* _First, void* _Last) noexcept { +#ifndef _M_ARM64EC if (_Byte_length(_First, _Last) >= 64 && _Use_avx2()) { const void* _Stop_at = _First; _Advance_bytes(_Stop_at, (_Byte_length(_First, _Last) >> 1) & ~size_t{0x1F}); @@ -318,12 +328,14 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_8(void* _Firs _Advance_bytes(_First, 16); } while (_First != _Stop_at); } +#endif // !_M_ARM64EC _Reverse_tail(static_cast(_First), static_cast(_Last)); } __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_1( const void* _First, const void* _Last, void* _Dest) noexcept { +#ifndef _M_ARM64EC if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { const __m256i _Reverse_char_lanes_avx = _mm256_set_epi8( // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // @@ -354,6 +366,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_1( _Advance_bytes(_Dest, 16); } while (_Dest != _Stop_at); } +#endif // !_M_ARM64EC _Reverse_copy_tail(static_cast(_First), static_cast(_Last), static_cast(_Dest)); @@ -361,6 +374,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_1( __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_2( const void* _First, const void* _Last, void* _Dest) noexcept { +#ifndef _M_ARM64EC if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { const __m256i _Reverse_short_lanes_avx = _mm256_set_epi8( // 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, // @@ -391,6 +405,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_2( _Advance_bytes(_Dest, 16); } while (_Dest != _Stop_at); } +#endif // !_M_ARM64EC _Reverse_copy_tail(static_cast(_First), static_cast(_Last), static_cast(_Dest)); @@ -398,6 +413,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_2( __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_4( const void* _First, const void* _Last, void* _Dest) noexcept { +#ifndef _M_ARM64EC if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { const void* _Stop_at = _Dest; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) & ~size_t{0x1F}); @@ -424,6 +440,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_4( _Advance_bytes(_Dest, 16); } while (_Dest != _Stop_at); } +#endif // !_M_ARM64EC _Reverse_copy_tail(static_cast(_First), static_cast(_Last), static_cast(_Dest)); @@ -431,6 +448,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_4( __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_8( const void* _First, const void* _Last, void* _Dest) noexcept { +#ifndef _M_ARM64EC if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { const void* _Stop_at = _Dest; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) & ~size_t{0x1F}); @@ -456,6 +474,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_8( _Advance_bytes(_Dest, 16); } while (_Dest != _Stop_at); } +#endif // !_M_ARM64EC _Reverse_copy_tail(static_cast(_First), static_cast(_Last), static_cast(_Dest)); @@ -464,7 +483,6 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_8( } // extern "C" namespace { - template const void* _Min_tail(const void* const _First, const void* const _Last, const void* _Res, _Ty _Cur) noexcept { for (auto _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) { @@ -546,12 +564,13 @@ namespace { using _Signed_t = int8_t; using _Unsigned_t = uint8_t; - static constexpr bool _Has_portion_max = true; - static constexpr size_t _Portion_max = 256; - static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7F); static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x80); +#ifndef _M_ARM64EC + static constexpr bool _Has_portion_max = true; + static constexpr size_t _Portion_max = 256; + static __m128i _Sign_correction(const __m128i _Val, const bool _Sign) noexcept { alignas(16) static constexpr _Unsigned_t _Sign_corrections[2][16] = { {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}, {}}; @@ -614,18 +633,20 @@ namespace { static __m128i _Max(const __m128i _First, const __m128i _Second, __m128i) noexcept { return _mm_max_epi8(_First, _Second); } +#endif // !_M_ARM64EC }; struct _Minmax_traits_2 { using _Signed_t = int16_t; using _Unsigned_t = uint16_t; - static constexpr bool _Has_portion_max = true; - static constexpr size_t _Portion_max = 65536; - static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7FFF); static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x8000); +#ifndef _M_ARM64EC + static constexpr bool _Has_portion_max = true; + static constexpr size_t _Portion_max = 65536; + static __m128i _Sign_correction(const __m128i _Val, const bool _Sign) noexcept { alignas(16) static constexpr _Unsigned_t _Sign_corrections[2][8] = { 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, {}}; @@ -689,12 +710,17 @@ namespace { static __m128i _Max(const __m128i _First, const __m128i _Second, __m128i) noexcept { return _mm_max_epi16(_First, _Second); } +#endif // !_M_ARM64EC }; struct _Minmax_traits_4 { using _Signed_t = int32_t; using _Unsigned_t = uint32_t; + static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7FFF'FFFFUL); + static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x8000'0000UL); + +#ifndef _M_ARM64EC #ifdef _M_IX86 static constexpr bool _Has_portion_max = false; #else // ^^^ 32-bit / 64-bit vvv @@ -702,9 +728,6 @@ namespace { static constexpr size_t _Portion_max = 0x1'0000'0000ULL; #endif // ^^^ 64-bit ^^^ - static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7FFF'FFFFUL); - static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x8000'0000UL); - static __m128i _Sign_correction(const __m128i _Val, const bool _Sign) noexcept { alignas(16) static constexpr _Unsigned_t _Sign_corrections[2][4] = { 0x8000'0000UL, 0x8000'0000UL, 0x8000'0000UL, 0x8000'0000UL, {}}; @@ -764,17 +787,19 @@ namespace { static __m128i _Max(const __m128i _First, const __m128i _Second, __m128i) noexcept { return _mm_max_epi32(_First, _Second); } +#endif // !_M_ARM64EC }; struct _Minmax_traits_8 { using _Signed_t = int64_t; using _Unsigned_t = uint64_t; - static constexpr bool _Has_portion_max = false; - static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7FFF'FFFF'FFFF'FFFFULL); static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x8000'0000'0000'0000ULL); +#ifndef _M_ARM64EC + static constexpr bool _Has_portion_max = false; + static __m128i _Sign_correction(const __m128i _Val, const bool _Sign) { alignas(16) static constexpr _Unsigned_t _Sign_corrections[2][2] = { 0x8000'0000'0000'0000ULL, 0x8000'0000'0000'0000ULL, {}}; @@ -842,6 +867,7 @@ namespace { static __m128i _Max(const __m128i _First, const __m128i _Second, const __m128i _Mask) noexcept { return _mm_blendv_epi8(_First, _Second, _Mask); } +#endif // !_M_ARM64EC }; // _Minmax_element has exactly the same signature as the extern "C" functions @@ -851,10 +877,12 @@ namespace { template <_Min_max_mode _Mode, class _Traits> auto __stdcall _Minmax_element(const void* _First, const void* const _Last, const bool _Sign) noexcept { _Min_max_element_t _Res = {_First, _First}; - auto _Base = static_cast(_First); auto _Cur_min_val = _Traits::_Init_min_val; auto _Cur_max_val = _Traits::_Init_max_val; +#ifndef _M_ARM64EC + auto _Base = static_cast(_First); + if (_Byte_length(_First, _Last) >= 16 && _Use_sse42()) { size_t _Portion_byte_size = _Byte_length(_First, _Last) & ~size_t{0xF}; @@ -1024,6 +1052,7 @@ namespace { } } } +#endif // !_M_ARM64EC return _Minmax_tail<_Mode, typename _Traits::_Signed_t, typename _Traits::_Unsigned_t>( _First, _Last, _Res, _Sign, _Cur_min_val, _Cur_max_val); @@ -1128,6 +1157,7 @@ namespace { struct _Find_traits_1 { static constexpr size_t _Shift = 0; +#ifndef _M_ARM64EC static __m256i _Set_avx(const uint8_t _Val) noexcept { return _mm256_set1_epi8(_Val); } @@ -1147,11 +1177,13 @@ namespace { static bool _Sse_available() noexcept { return _Use_sse2(); } +#endif // !_M_ARM64EC }; struct _Find_traits_2 { static constexpr size_t _Shift = 1; +#ifndef _M_ARM64EC static __m256i _Set_avx(const uint16_t _Val) noexcept { return _mm256_set1_epi16(_Val); } @@ -1171,11 +1203,13 @@ namespace { static bool _Sse_available() noexcept { return _Use_sse2(); } +#endif // !_M_ARM64EC }; struct _Find_traits_4 { static constexpr size_t _Shift = 2; +#ifndef _M_ARM64EC static __m256i _Set_avx(const uint32_t _Val) noexcept { return _mm256_set1_epi32(_Val); } @@ -1195,11 +1229,13 @@ namespace { static bool _Sse_available() noexcept { return _Use_sse2(); } +#endif // !_M_ARM64EC }; struct _Find_traits_8 { static constexpr size_t _Shift = 3; +#ifndef _M_ARM64EC static __m256i _Set_avx(const uint64_t _Val) noexcept { return _mm256_set1_epi64x(_Val); } @@ -1219,6 +1255,7 @@ namespace { static bool _Sse_available() noexcept { return _Use_sse42(); // for pcmpeqq on _Cmp_sse } +#endif // !_M_ARM64EC }; // The below functions have exactly the same signature as the extern "C" functions, up to calling convention. @@ -1227,6 +1264,7 @@ namespace { template const void* __stdcall __std_find_trivial_unsized(const void* _First, const _Ty _Val) noexcept { +#ifndef _M_ARM64EC if (_Use_avx2()) { _Zeroupper_on_exit _Guard; // TRANSITION, DevCom-10331414 @@ -1302,12 +1340,14 @@ namespace { _Advance_bytes(_First, 16); } } +#endif // !_M_ARM64EC return _Find_trivial_unsized_fallback(_First, _Val); } template const void* __stdcall __std_find_trivial(const void* _First, const void* _Last, _Ty _Val) noexcept { +#ifndef _M_ARM64EC size_t _Size_bytes = _Byte_length(_First, _Last); const size_t _Avx_size = _Size_bytes & ~size_t{0x1F}; @@ -1351,6 +1391,7 @@ namespace { _Advance_bytes(_First, 16); } while (_First != _Stop_at); } +#endif // !_M_ARM64EC return _Find_trivial_tail(_First, _Last, _Val); } @@ -1358,8 +1399,10 @@ namespace { template __declspec(noalias) size_t __stdcall __std_count_trivial(const void* _First, const void* const _Last, const _Ty _Val) noexcept { + size_t _Result = 0; + +#ifndef _M_ARM64EC size_t _Size_bytes = _Byte_length(_First, _Last); - size_t _Result = 0; const size_t _Avx_size = _Size_bytes & ~size_t{0x1F}; if (_Avx_size != 0 && _Use_avx2()) { @@ -1389,6 +1432,7 @@ namespace { _Advance_bytes(_First, 16); } while (_First != _Stop_at); } +#endif // !_M_ARM64EC return _Count_trivial_tail(_First, _Last, _Result >> _Traits::_Shift, _Val); } @@ -1453,5 +1497,4 @@ __declspec(noalias) size_t } } // extern "C" - -#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_ARM64EC) +#endif // defined(_M_IX86) || defined(_M_X64) diff --git a/stl/src/xonce2.cpp b/stl/src/xonce2.cpp index e90c6236025..bbc77ca852f 100644 --- a/stl/src/xonce2.cpp +++ b/stl/src/xonce2.cpp @@ -25,12 +25,13 @@ int __stdcall __std_init_once_complete_clr(void** _LpInitOnce, unsigned long _Dw _CSTD abort(); } -#if defined(_M_ARM64EC) || defined(_M_HYBRID) +#if defined(_M_HYBRID) // uses the forwarder fallbacks for ARM64EC and CHPE. +// Note that ARM64EC nevertheless needs the ALTERNATENAMEs to support x64 object files. #elif defined(_M_IX86) #pragma comment(linker, "/ALTERNATENAME:__imp____std_init_once_begin_initialize@16=__imp__InitOnceBeginInitialize@16") #pragma comment(linker, "/ALTERNATENAME:__imp____std_init_once_complete@12=__imp__InitOnceComplete@12") -#elif defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64) +#elif defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64) // Note: includes _M_ARM64EC #pragma comment(linker, "/ALTERNATENAME:__imp___std_init_once_begin_initialize=__imp_InitOnceBeginInitialize") #pragma comment(linker, "/ALTERNATENAME:__imp___std_init_once_complete=__imp_InitOnceComplete") #else // ^^^ known architecture / unknown architecture vvv From 0d47d98f95d2bc3247ebb9f45e292c3f2343727d Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 31 May 2023 02:00:01 +0200 Subject: [PATCH 07/11] ``: Fix `cartesian_product_view::size` in debug mode (#3733) --- stl/inc/ranges | 22 ++++++++++++------- .../P2374R4_views_cartesian_product/test.cpp | 13 +++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 6a5238a58fb..0a89c81f9cd 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -9991,11 +9991,14 @@ namespace ranges { { return [&](index_sequence<_Indices...>) { #if _CONTAINER_DEBUG_LEVEL > 0 + const array _Sizes = {static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases)))...}; + const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...); + if (_Any_zero) { + return _Size_type{0}; + } + _Size_type _Product{1}; - const bool _Overflow = - (_Mul_overflow( - _Product, static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases))), _Product) - || ...); + const bool _Overflow = (_Mul_overflow(_Product, _Sizes[_Indices], _Product) || ...); _STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 " "[range.cartesian.view]/10)."); return _Product; @@ -10010,11 +10013,14 @@ namespace ranges { { return [&](index_sequence<_Indices...>) { #if _CONTAINER_DEBUG_LEVEL > 0 + const array _Sizes = {static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases)))...}; + const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...); + if (_Any_zero) { + return _Size_type{0}; + } + _Size_type _Product{1}; - const bool _Overflow = - (_Mul_overflow( - _Product, static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases))), _Product) - || ...); + const bool _Overflow = (_Mul_overflow(_Product, _Sizes[_Indices], _Product) || ...); _STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 " "[range.cartesian.view]/10)."); return _Product; diff --git a/tests/std/tests/P2374R4_views_cartesian_product/test.cpp b/tests/std/tests/P2374R4_views_cartesian_product/test.cpp index d9e657cdeb7..7a3daa44fad 100644 --- a/tests/std/tests/P2374R4_views_cartesian_product/test.cpp +++ b/tests/std/tests/P2374R4_views_cartesian_product/test.cpp @@ -973,6 +973,16 @@ namespace check_recommended_practice_implementation { // MSVC STL specific behav STATIC_ASSERT(sizeof(range_difference_t, all_t>>) > sizeof(ptrdiff_t)); } // namespace check_recommended_practice_implementation +// GH-3733: cartesian_product_view would incorrectly reject a call to size() claiming that big*big*big*0 is not +// representable as range_size_t because big*big*big is not. +constexpr void test_gh_3733() { + const auto r1 = views::repeat(0, (numeric_limits::max)()); + const auto r2 = views::repeat(1, 0); + const auto cart = views::cartesian_product(r1, r1, r1, r2); + assert(cart.size() == 0); + assert(as_const(cart).size() == 0); +} + int main() { // Check views { // ... copyable @@ -1029,4 +1039,7 @@ int main() { STATIC_ASSERT((instantiation_test(), true)); #endif // TRANSITION, GH-1030 instantiation_test(); + + STATIC_ASSERT((test_gh_3733(), true)); + test_gh_3733(); } From c8594d859619b0879da72bb464ced3e1605135a3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 30 May 2023 17:05:39 -0700 Subject: [PATCH 08/11] Fix static analysis warnings (#3734) Co-authored-by: Dmitry Kobets <89153909+dmitrykobets-msft@users.noreply.github.com> --- stl/inc/charconv | 7 +++++++ stl/inc/exception | 4 ++-- stl/inc/format | 4 ++-- stl/inc/future | 4 ++-- stl/inc/ios | 6 +++--- stl/inc/istream | 7 ++++--- stl/inc/list | 6 +++--- stl/inc/ostream | 2 +- stl/inc/regex | 2 +- stl/inc/streambuf | 28 ++++++++++++++-------------- stl/inc/xiosbase | 10 +++++----- stl/src/atomic.cpp | 1 + stl/src/excptptr.cpp | 2 +- stl/src/ppltasks.cpp | 5 +++-- stl/src/primitives.hpp | 1 + stl/src/sharedmutex.cpp | 1 + stl/src/winapisupp.cpp | 1 + stl/src/xstol.cpp | 3 +-- stl/src/xstoll.cpp | 3 +-- 19 files changed, 54 insertions(+), 43 deletions(-) diff --git a/stl/inc/charconv b/stl/inc/charconv index f2a94a630a9..2614acb2ee8 100644 --- a/stl/inc/charconv +++ b/stl/inc/charconv @@ -395,7 +395,11 @@ _EXPORT_STD _CONSTEXPR23 from_chars_result from_chars(const char* const _First, // - Otherwise, no initialization is performed." // Therefore, _Mydata's elements are not initialized. struct _Big_integer_flt { +#pragma warning(push) +#pragma warning(disable : 26495) // Variable 'std::_Big_integer_flt::_Mydata' is uninitialized. + // Always initialize a member variable (type.6). _Big_integer_flt() noexcept : _Myused(0) {} +#pragma warning(pop) _Big_integer_flt(const _Big_integer_flt& _Other) noexcept : _Myused(_Other._Myused) { _CSTD memcpy(_Mydata, _Other._Mydata, _Other._Myused * sizeof(uint32_t)); @@ -1020,7 +1024,10 @@ _NODISCARD inline uint64_t _Right_shift_with_rounding( constexpr uint32_t _Total_number_of_bits = 64; if (_Shift >= _Total_number_of_bits) { if (_Shift == _Total_number_of_bits) { +#pragma warning(push) +#pragma warning(disable : 26454) // TRANSITION, VSO-1826196 constexpr uint64_t _Extra_bits_mask = (1ULL << (_Total_number_of_bits - 1)) - 1; +#pragma warning(pop) constexpr uint64_t _Round_bit_mask = (1ULL << (_Total_number_of_bits - 1)); const bool _Round_bit = (_Value & _Round_bit_mask) != 0; diff --git a/stl/inc/exception b/stl/inc/exception index 4d3e300521a..e812966eb3f 100644 --- a/stl/inc/exception +++ b/stl/inc/exception @@ -305,8 +305,8 @@ private: #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-private-field" #endif // __clang__ - void* _Data1; - void* _Data2; + void* _Data1{}; + void* _Data2{}; #ifdef __clang__ #pragma clang diagnostic pop #endif // __clang__ diff --git a/stl/inc/format b/stl/inc/format index f8a736a74ab..d3c695d593e 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -1892,8 +1892,8 @@ struct _Format_arg_index { _Type_ = static_cast(_Val); } - size_t _Index : (sizeof(size_t) * 8 - 4); - size_t _Type_ : 4; + size_t _Index : (sizeof(size_t) * 8 - 4){}; + size_t _Type_ : 4 {}; }; _EXPORT_STD template diff --git a/stl/inc/future b/stl/inc/future index 915348ef5b7..e1686479959 100644 --- a/stl/inc/future +++ b/stl/inc/future @@ -205,8 +205,8 @@ public: // TRANSITION, incorrectly default constructs _Result when _Ty is default constructible _Associated_state(_Mydel* _Dp = nullptr) : _Refs(1), // non-atomic initialization - _Exception(), _Retrieved(false), _Ready(false), _Ready_at_thread_exit(false), _Has_stored_result(false), - _Running(false), _Deleter(_Dp) {} + _Result(), _Exception(), _Retrieved(false), _Ready(false), _Ready_at_thread_exit(false), + _Has_stored_result(false), _Running(false), _Deleter(_Dp) {} virtual ~_Associated_state() noexcept { if (_Already_has_stored_result() && !_Ready) { // registered for release at thread exit diff --git a/stl/inc/ios b/stl/inc/ios index e4096ec0612..486b0c89914 100644 --- a/stl/inc/ios +++ b/stl/inc/ios @@ -161,9 +161,9 @@ protected: __CLR_OR_THIS_CALL basic_ios() {} private: - _Mysb* _Mystrbuf; // pointer to stream buffer - _Myos* _Tiestr; // pointer to tied output stream - _Elem _Fillch; // the fill character + _Mysb* _Mystrbuf{}; // pointer to stream buffer + _Myos* _Tiestr{}; // pointer to tied output stream + _Elem _Fillch{}; // the fill character public: __CLR_OR_THIS_CALL basic_ios(const basic_ios&) = delete; diff --git a/stl/inc/istream b/stl/inc/istream index c335d3501a9..ad814f15549 100644 --- a/stl/inc/istream +++ b/stl/inc/istream @@ -48,7 +48,7 @@ public: } protected: - __CLR_OR_THIS_CALL basic_istream(basic_istream&& _Right) : _Chcount(_Right._Chcount) { + __CLR_OR_THIS_CALL basic_istream(basic_istream&& _Right) noexcept(false) : _Chcount(_Right._Chcount) { _Myios::init(); _Myios::move(_STD move(_Right)); _Right._Chcount = 0; @@ -686,7 +686,7 @@ public: } private: - streamsize _Chcount; // the character count + streamsize _Chcount{}; // the character count }; #pragma vtordisp(pop) // compiler bug workaround @@ -739,7 +739,8 @@ public: : _Myis(_Strbuf, false), _Myos(_Noinit, false) {} protected: - __CLR_OR_THIS_CALL basic_iostream(basic_iostream&& _Right) : _Myis(_Right.rdbuf(), false), _Myos(_Noinit, false) { + __CLR_OR_THIS_CALL basic_iostream(basic_iostream&& _Right) noexcept(false) + : _Myis(_Right.rdbuf(), false), _Myos(_Noinit, false) { _Myios::init(); _Myios::move(_STD move(_Right)); } diff --git a/stl/inc/list b/stl/inc/list index de5c25248ca..8eae947c0b5 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -745,8 +745,8 @@ struct _List_node_insert_op2 { private: _Alnode& _Al; size_type _Added; // if 0, the values of _Head and _Tail are indeterminate - pointer _Tail; // points to the most recently appended element; it doesn't have _Next constructed - pointer _Head; // points to the first appended element; it doesn't have _Prev constructed + pointer _Tail{}; // points to the most recently appended element; it doesn't have _Next constructed + pointer _Head{}; // points to the first appended element; it doesn't have _Prev constructed }; template @@ -896,7 +896,7 @@ public: } #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) - list(list&& _Right) : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { + list(list&& _Right) noexcept(false) : _Mypair(_One_then_variadic_args_t{}, _STD move(_Right._Getal())) { _Alloc_sentinel_and_proxy(); _Swap_val(_Right); } diff --git a/stl/inc/ostream b/stl/inc/ostream index bc57dae978f..6658a75d81e 100644 --- a/stl/inc/ostream +++ b/stl/inc/ostream @@ -45,7 +45,7 @@ public: } protected: - __CLR_OR_THIS_CALL basic_ostream(basic_ostream&& _Right) { + __CLR_OR_THIS_CALL basic_ostream(basic_ostream&& _Right) noexcept(false) { _Myios::init(); _Myios::move(_STD move(_Right)); } diff --git a/stl/inc/regex b/stl/inc/regex index cd2ea570493..bb831fa32c2 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1367,7 +1367,7 @@ public: static_assert(sizeof(_Refs) == sizeof(_Atomic_counter_t), "invalid _Refs size"); } - regex_constants::syntax_option_type _Fl; + regex_constants::syntax_option_type _Fl{}; unsigned int _Loops; unsigned int _Marks; unsigned int _Refs; diff --git a/stl/inc/streambuf b/stl/inc/streambuf index 9a9802eb0af..76cc33db524 100644 --- a/stl/inc/streambuf +++ b/stl/inc/streambuf @@ -381,22 +381,22 @@ protected: virtual void __CLR_OR_THIS_CALL imbue(const locale&) {} // set locale to argument (do nothing) private: - _Elem* _Gfirst; // beginning of read buffer - _Elem* _Pfirst; // beginning of write buffer - _Elem** _IGfirst; // pointer to beginning of read buffer - _Elem** _IPfirst; // pointer to beginning of write buffer - _Elem* _Gnext; // current position in read buffer - _Elem* _Pnext; // current position in write buffer - _Elem** _IGnext; // pointer to current position in read buffer - _Elem** _IPnext; // pointer to current position in write buffer - - int _Gcount; // length of read buffer - int _Pcount; // length of write buffer - int* _IGcount; // pointer to length of read buffer - int* _IPcount; // pointer to length of write buffer + _Elem* _Gfirst{}; // beginning of read buffer + _Elem* _Pfirst{}; // beginning of write buffer + _Elem** _IGfirst{}; // pointer to beginning of read buffer + _Elem** _IPfirst{}; // pointer to beginning of write buffer + _Elem* _Gnext{}; // current position in read buffer + _Elem* _Pnext{}; // current position in write buffer + _Elem** _IGnext{}; // pointer to current position in read buffer + _Elem** _IPnext{}; // pointer to current position in write buffer + + int _Gcount{}; // length of read buffer + int _Pcount{}; // length of write buffer + int* _IGcount{}; // pointer to length of read buffer + int* _IPcount{}; // pointer to length of write buffer protected: - locale* _Plocale; // pointer to imbued locale object + locale* _Plocale{}; // pointer to imbued locale object }; #if defined(_DLL_CPPLIB) diff --git a/stl/inc/xiosbase b/stl/inc/xiosbase index 338f5f1adf0..aaa05048725 100644 --- a/stl/inc/xiosbase +++ b/stl/inc/xiosbase @@ -468,11 +468,11 @@ private: _Calls = nullptr; } - iostate _Mystate; // stream state - iostate _Except; // exception mask - fmtflags _Fmtfl; // format flags - streamsize _Prec; // field precision - streamsize _Wide; // field width + iostate _Mystate{}; // stream state + iostate _Except{}; // exception mask + fmtflags _Fmtfl{}; // format flags + streamsize _Prec{}; // field precision + streamsize _Wide{}; // field width _Iosarray* _Arr{nullptr}; // pointer to first node of long/pointer array _Fnarray* _Calls{nullptr}; // pointer to first node of call list locale* _Ploc{nullptr}; // pointer to locale diff --git a/stl/src/atomic.cpp b/stl/src/atomic.cpp index b6016bd9357..3bdbf725407 100644 --- a/stl/src/atomic.cpp +++ b/stl/src/atomic.cpp @@ -18,6 +18,7 @@ _CRTIMP2_PURE void __cdecl _Lock_shared_ptr_spin_lock() { // TRANSITION, ABI: "s } _CRTIMP2_PURE void __cdecl _Unlock_shared_ptr_spin_lock() { // release previously obtained lock + _Analysis_assume_lock_held_(_Shared_ptr_lock); ReleaseSRWLockExclusive(&_Shared_ptr_lock); } diff --git a/stl/src/excptptr.cpp b/stl/src/excptptr.cpp index 22e059eaffe..75aeac65891 100644 --- a/stl/src/excptptr.cpp +++ b/stl/src/excptptr.cpp @@ -300,7 +300,7 @@ namespace { } _EXCEPTION_RECORD _ExRecord; - void* _Unused_alignment_padding; + void* _Unused_alignment_padding{}; }; // We aren't using alignas because this file might be compiled with _M_CEE_PURE diff --git a/stl/src/ppltasks.cpp b/stl/src/ppltasks.cpp index 721a2ea2941..1108413976a 100644 --- a/stl/src/ppltasks.cpp +++ b/stl/src/ppltasks.cpp @@ -27,8 +27,9 @@ static GUID const Local_IID_ICallbackWithNoReentrancyToApplicationSTA = { // Introduce stacktrace API for Debug CRT_APP #if defined(_CRT_APP) && defined(_DEBUG) -extern "C" NTSYSAPI WORD NTAPI RtlCaptureStackBackTrace(_In_ DWORD FramesToSkip, _In_ DWORD FramesToCapture, - _Out_writes_to_(FramesToCapture, return) PVOID* BackTrace, _Out_opt_ PDWORD BackTraceHash); +extern "C" NTSYSAPI _Success_(return != 0) WORD NTAPI + RtlCaptureStackBackTrace(_In_ DWORD FramesToSkip, _In_ DWORD FramesToCapture, + _Out_writes_to_(FramesToCapture, return) PVOID* BackTrace, _Out_opt_ PDWORD BackTraceHash); #endif namespace Concurrency { diff --git a/stl/src/primitives.hpp b/stl/src/primitives.hpp index 7e835f1d3c3..f3e2d99920b 100644 --- a/stl/src/primitives.hpp +++ b/stl/src/primitives.hpp @@ -52,6 +52,7 @@ namespace Concurrency { } void unlock() override { + _Analysis_assume_lock_held_(m_srw_lock); ReleaseSRWLockExclusive(&m_srw_lock); } diff --git a/stl/src/sharedmutex.cpp b/stl/src/sharedmutex.cpp index b678cf8c724..6cfcc63cf45 100644 --- a/stl/src/sharedmutex.cpp +++ b/stl/src/sharedmutex.cpp @@ -29,6 +29,7 @@ int __cdecl _Smtx_try_lock_shared(_Smtx_t* smtx) { // try to lock shared mutex n } void __cdecl _Smtx_unlock_exclusive(_Smtx_t* smtx) { // unlock exclusive shared mutex + _Analysis_assume_lock_held_(*reinterpret_cast(smtx)); ReleaseSRWLockExclusive(reinterpret_cast(smtx)); } diff --git a/stl/src/winapisupp.cpp b/stl/src/winapisupp.cpp index a54eed524f0..5ac59987fe5 100644 --- a/stl/src/winapisupp.cpp +++ b/stl/src/winapisupp.cpp @@ -325,6 +325,7 @@ extern "C" VOID __cdecl __crtAcquireSRWLockExclusive(_Inout_ PSRWLOCK const pLoc // TRANSITION, ABI: preserved for binary compatibility extern "C" VOID __cdecl __crtReleaseSRWLockExclusive(_Inout_ PSRWLOCK const pLock) { + _Analysis_assume_lock_held_(*pLock); ReleaseSRWLockExclusive(pLock); } diff --git a/stl/src/xstol.cpp b/stl/src/xstol.cpp index 0e5f94ba008..5971a54ef6d 100644 --- a/stl/src/xstol.cpp +++ b/stl/src/xstol.cpp @@ -36,8 +36,7 @@ _CRTIMP2_PURE long __CLRCALL_PURE_OR_CDECL _Stolx( *endptr = const_cast(s); } - if (s == *endptr && x != 0 || sign == '+' && LONG_MAX < x - || sign == '-' && 0 - static_cast(LONG_MIN) < x) { // overflow + if (s == *endptr && x != 0 || sign == '+' && LONG_MAX < x || sign == '-' && (1ul << 31) < x) { // overflow errno = ERANGE; if (perr != nullptr) { *perr = 1; diff --git a/stl/src/xstoll.cpp b/stl/src/xstoll.cpp index 4bddd4e19c9..a952bb9760a 100644 --- a/stl/src/xstoll.cpp +++ b/stl/src/xstoll.cpp @@ -36,8 +36,7 @@ _CRTIMP2_PURE long long __CLRCALL_PURE_OR_CDECL _Stollx( *endptr = const_cast(s); } - if (s == *endptr && x != 0 || sign == '+' && LLONG_MAX < x - || sign == '-' && 0 - static_cast(LLONG_MIN) < x) { // overflow + if (s == *endptr && x != 0 || sign == '+' && LLONG_MAX < x || sign == '-' && (1ull << 63) < x) { // overflow errno = ERANGE; if (perr != nullptr) { *perr = 1; From a8c47373bec114bfa0bdfe8b47f4d1083a573bf8 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Wed, 31 May 2023 08:09:32 +0800 Subject: [PATCH 09/11] ``: Restore the indent after adding `inline namespace __p2286` (#3726) --- .clang-format | 2 + stl/inc/format | 2303 ++++++++++++++++++++++++------------------------ 2 files changed, 1148 insertions(+), 1157 deletions(-) diff --git a/.clang-format b/.clang-format index 6c2d849e5b4..e4e65166947 100644 --- a/.clang-format +++ b/.clang-format @@ -269,6 +269,8 @@ StatementMacros: - _STD_END - _STDEXT_BEGIN - _STDEXT_END + - _FMT_P2286_BEGIN + - _FMT_P2286_END - _EXTERN_C - _END_EXTERN_C - _EXTERN_C_UNLESS_PURE diff --git a/stl/inc/format b/stl/inc/format index d3c695d593e..b6c788828f1 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -69,6 +69,14 @@ extern "C" _NODISCARD __std_win_error __stdcall __std_get_cvt(__std_code_page _C _STD_BEGIN +#if _HAS_CXX23 +#define _FMT_P2286_BEGIN inline namespace __p2286 { +#define _FMT_P2286_END } +#else // ^^^ C++23 / C++20 vvv +#define _FMT_P2286_BEGIN +#define _FMT_P2286_END +#endif // ^^^ C++20 ^^^ + template _NODISCARD constexpr const _CharT* _Choose_literal(const char* const _Str, const wchar_t* const _WStr) noexcept { if constexpr (is_same_v<_CharT, char>) { @@ -2347,1172 +2355,1162 @@ using _Fmt_wit = back_insert_iterator<_Fmt_buffer>; _EXPORT_STD using format_context = basic_format_context<_Fmt_it, char>; _EXPORT_STD using wformat_context = basic_format_context<_Fmt_wit, wchar_t>; -#if _HAS_CXX23 -inline namespace __p2286 { -#endif // _HAS_CXX23 - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate) { - _STL_INTERNAL_CHECK(false); - return _Out; - } - - // This size is derived from the maximum length of an arithmetic type. The contenders for widest are: - // (a) long long has a max length of 20 characters: LLONG_MIN is "-9223372036854775807". - // (b) unsigned long long has a max length of 20 characters: ULLONG_MAX is "18446744073709551615". - // (c) double has a max length of 24 characters: -DBL_MAX is "-1.7976931348623158e+308". - // That's 17 characters for numeric_limits::max_digits10, - // plus 1 character for the sign, - // plus 1 character for the decimal point, - // plus 1 character for 'e', - // plus 1 character for the exponent's sign, - // plus 3 characters for the max exponent. - inline constexpr size_t _Format_min_buffer_length = 24; +_FMT_P2286_BEGIN +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate) { + _STL_INTERNAL_CHECK(false); + return _Out; +} - template - requires (is_arithmetic_v<_Arithmetic> && !_CharT_or_bool<_Arithmetic, _CharT>) - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, _Arithmetic _Value); +// This size is derived from the maximum length of an arithmetic type. The contenders for widest are: +// (a) long long has a max length of 20 characters: LLONG_MIN is "-9223372036854775807". +// (b) unsigned long long has a max length of 20 characters: ULLONG_MAX is "18446744073709551615". +// (c) double has a max length of 24 characters: -DBL_MAX is "-1.7976931348623158e+308". +// That's 17 characters for numeric_limits::max_digits10, +// plus 1 character for the sign, +// plus 1 character for the decimal point, +// plus 1 character for 'e', +// plus 1 character for the exponent's sign, +// plus 3 characters for the max exponent. +inline constexpr size_t _Format_min_buffer_length = 24; - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, bool _Value); +template + requires (is_arithmetic_v<_Arithmetic> && !_CharT_or_bool<_Arithmetic, _CharT>) +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, _Arithmetic _Value); - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, _CharT _Value); +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, bool _Value); - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const void* _Value); +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, _CharT _Value); - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT* _Value); +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const void* _Value); - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, basic_string_view<_CharT> _Value); +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT* _Value); - template - _NODISCARD _OutputIt _Widen_and_copy(const char* _First, const char* const _Last, _OutputIt _Out) { - for (; _First != _Last; ++_First, (void) ++_Out) { - *_Out = static_cast<_CharT>(*_First); - } +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, basic_string_view<_CharT> _Value); - return _Out; +template +_NODISCARD _OutputIt _Widen_and_copy(const char* _First, const char* const _Last, _OutputIt _Out) { + for (; _First != _Last; ++_First, (void) ++_Out) { + *_Out = static_cast<_CharT>(*_First); } - template - requires (is_arithmetic_v<_Arithmetic> && !_CharT_or_bool<_Arithmetic, _CharT>) - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _Arithmetic _Value) { - // TRANSITION, Reusable buffer - char _Buffer[_Format_min_buffer_length]; - char* _End = _Buffer; + return _Out; +} - if constexpr (is_floating_point_v<_Arithmetic>) { - if ((_STD isnan)(_Value)) { - if ((_STD signbit)(_Value)) { - *_End++ = '-'; - } +template + requires (is_arithmetic_v<_Arithmetic> && !_CharT_or_bool<_Arithmetic, _CharT>) +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _Arithmetic _Value) { + // TRANSITION, Reusable buffer + char _Buffer[_Format_min_buffer_length]; + char* _End = _Buffer; - _CSTD memcpy(_End, "nan", 3); - _End += 3; + if constexpr (is_floating_point_v<_Arithmetic>) { + if ((_STD isnan)(_Value)) { + if ((_STD signbit)(_Value)) { + *_End++ = '-'; } - } - if (_End == _Buffer) { - const to_chars_result _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value); - _STL_INTERNAL_CHECK(_Result.ec == errc{}); - _End = _Result.ptr; + _CSTD memcpy(_End, "nan", 3); + _End += 3; } - - return _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); } - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const bool _Value) { - if constexpr (is_same_v<_CharT, wchar_t>) { - return _Fmt_write(_STD move(_Out), _Value ? L"true" : L"false"); - } else { - return _Fmt_write(_STD move(_Out), _Value ? "true" : "false"); - } + if (_End == _Buffer) { + const to_chars_result _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value); + _STL_INTERNAL_CHECK(_Result.ec == errc{}); + _End = _Result.ptr; } - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT _Value) { - *_Out++ = _Value; - return _Out; - } + return _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); +} - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const void* const _Value) { - // TRANSITION, Reusable buffer - char _Buffer[_Format_min_buffer_length]; - const auto [_End, _Ec] = _STD to_chars(_Buffer, _STD end(_Buffer), reinterpret_cast(_Value), 16); - _STL_INTERNAL_CHECK(_Ec == errc{}); - *_Out++ = '0'; - *_Out++ = 'x'; - return _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const bool _Value) { + if constexpr (is_same_v<_CharT, wchar_t>) { + return _Fmt_write(_STD move(_Out), _Value ? L"true" : L"false"); + } else { + return _Fmt_write(_STD move(_Out), _Value ? "true" : "false"); } +} - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT* _Value) { - if (!_Value) { - _Throw_format_error("String pointer is null."); - } +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT _Value) { + *_Out++ = _Value; + return _Out; +} - while (*_Value) { - *_Out++ = *_Value++; - } +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const void* const _Value) { + // TRANSITION, Reusable buffer + char _Buffer[_Format_min_buffer_length]; + const auto [_End, _Ec] = _STD to_chars(_Buffer, _STD end(_Buffer), reinterpret_cast(_Value), 16); + _STL_INTERNAL_CHECK(_Ec == errc{}); + *_Out++ = '0'; + *_Out++ = 'x'; + return _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); +} - return _Out; +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT* _Value) { + if (!_Value) { + _Throw_format_error("String pointer is null."); } - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const basic_string_view<_CharT> _Value) { - return _RANGES copy(_Value, _STD move(_Out)).out; - } - - template - _NODISCARD _OutputIt _Write_aligned( - _OutputIt _Out, const int _Width, const _Specs_type& _Specs, const _Fmt_align _Default_align, _Func&& _Fn) { - int _Fill_left = 0; - int _Fill_right = 0; - auto _Alignment = _Specs._Alignment; - - if (_Alignment == _Fmt_align::_None) { - _Alignment = _Default_align; - } - - if (_Width < _Specs._Width) { - switch (_Alignment) { - case _Fmt_align::_Left: - _Fill_right = _Specs._Width - _Width; - break; - case _Fmt_align::_Right: - _Fill_left = _Specs._Width - _Width; - break; - case _Fmt_align::_Center: - _Fill_left = (_Specs._Width - _Width) / 2; - _Fill_right = _Specs._Width - _Width - _Fill_left; - break; - case _Fmt_align::_None: - _STL_ASSERT(false, "Invalid alignment"); - break; - } - } + while (*_Value) { + *_Out++ = *_Value++; + } - const basic_string_view _Fill_char{_Specs._Fill, _Specs._Fill_length}; - for (; _Fill_left > 0; --_Fill_left) { - _Out = _RANGES copy(_Fill_char, _STD move(_Out)).out; - } + return _Out; +} - _Out = _Fn(_STD move(_Out)); +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const basic_string_view<_CharT> _Value) { + return _RANGES copy(_Value, _STD move(_Out)).out; +} - for (; _Fill_right > 0; --_Fill_right) { - _Out = _RANGES copy(_Fill_char, _STD move(_Out)).out; - } +template +_NODISCARD _OutputIt _Write_aligned( + _OutputIt _Out, const int _Width, const _Specs_type& _Specs, const _Fmt_align _Default_align, _Func&& _Fn) { + int _Fill_left = 0; + int _Fill_right = 0; + auto _Alignment = _Specs._Alignment; - return _Out; + if (_Alignment == _Fmt_align::_None) { + _Alignment = _Default_align; } - template - _NODISCARD constexpr string_view _Get_integral_prefix(const char _Type, const _Integral _Value) noexcept { - switch (_Type) { - case 'b': - return "0b"sv; - case 'B': - return "0B"sv; - case 'x': - return "0x"sv; - case 'X': - return "0X"sv; - case 'o': - if (_Value != _Integral{0}) { - return "0"sv; - } - return {}; - default: - return {}; + if (_Width < _Specs._Width) { + switch (_Alignment) { + case _Fmt_align::_Left: + _Fill_right = _Specs._Width - _Width; + break; + case _Fmt_align::_Right: + _Fill_left = _Specs._Width - _Width; + break; + case _Fmt_align::_Center: + _Fill_left = (_Specs._Width - _Width) / 2; + _Fill_right = _Specs._Width - _Width - _Fill_left; + break; + case _Fmt_align::_None: + _STL_ASSERT(false, "Invalid alignment"); + break; } } - template - _NODISCARD _OutputIt _Write_sign(_OutputIt _Out, const _Fmt_sign _Sgn, const bool _Is_negative) { - if (_Is_negative) { - *_Out++ = '-'; - } else { - switch (_Sgn) { - case _Fmt_sign::_Plus: - *_Out++ = '+'; - break; - case _Fmt_sign::_Space: - *_Out++ = ' '; - break; - case _Fmt_sign::_None: - case _Fmt_sign::_Minus: - break; - } - } - return _Out; + const basic_string_view _Fill_char{_Specs._Fill, _Specs._Fill_length}; + for (; _Fill_left > 0; --_Fill_left) { + _Out = _RANGES copy(_Fill_char, _STD move(_Out)).out; } - inline void _Buffer_to_uppercase(char* _First, const char* _Last) { - for (; _First != _Last; ++_First) { - *_First = static_cast(_CSTD toupper(*_First)); - } + _Out = _Fn(_STD move(_Out)); + + for (; _Fill_right > 0; --_Fill_right) { + _Out = _RANGES copy(_Fill_char, _STD move(_Out)).out; } - template - using _Make_standard_integer = conditional_t, make_signed_t<_Ty>, make_unsigned_t<_Ty>>; + return _Out; +} - template - _NODISCARD constexpr bool _In_bounds(const _Ty _Value) { - return _STD in_range<_Make_standard_integer<_CharT>>(static_cast<_Make_standard_integer<_Ty>>(_Value)); +template +_NODISCARD constexpr string_view _Get_integral_prefix(const char _Type, const _Integral _Value) noexcept { + switch (_Type) { + case 'b': + return "0b"sv; + case 'B': + return "0B"sv; + case 'x': + return "0x"sv; + case 'X': + return "0X"sv; + case 'o': + if (_Value != _Integral{0}) { + return "0"sv; + } + return {}; + default: + return {}; } +} - _NODISCARD inline int _Count_separators(size_t _Digits, const string_view _Groups) { - if (_Groups.empty()) { - return 0; - } - - // Calculate the amount of separators that are going to be inserted based on the groupings of the locale. - int _Separators = 0; - auto _Group_it = _Groups.begin(); - while (_Digits > static_cast(*_Group_it)) { - _Digits -= static_cast(*_Group_it); - ++_Separators; - if (_Group_it + 1 != _Groups.end()) { - ++_Group_it; - } +template +_NODISCARD _OutputIt _Write_sign(_OutputIt _Out, const _Fmt_sign _Sgn, const bool _Is_negative) { + if (_Is_negative) { + *_Out++ = '-'; + } else { + switch (_Sgn) { + case _Fmt_sign::_Plus: + *_Out++ = '+'; + break; + case _Fmt_sign::_Space: + *_Out++ = ' '; + break; + case _Fmt_sign::_None: + case _Fmt_sign::_Minus: + break; } + } + return _Out; +} - return _Separators; +inline void _Buffer_to_uppercase(char* _First, const char* _Last) { + for (; _First != _Last; ++_First) { + *_First = static_cast(_CSTD toupper(*_First)); } +} - template - _NODISCARD _OutputIt _Write_separated_integer(const char* _First, const char* const _Last, - const string_view _Groups, const _CharT _Separator, int _Separators, _OutputIt _Out) { - auto _Group_it = _Groups.begin(); - auto _Repeats = 0; - auto _Grouped = 0; +template +using _Make_standard_integer = conditional_t, make_signed_t<_Ty>, make_unsigned_t<_Ty>>; - for (int _Section = 0; _Section < _Separators; ++_Section) { - _Grouped += *_Group_it; - if (_Group_it + 1 != _Groups.end()) { - ++_Group_it; - } else { - ++_Repeats; - } +template +_NODISCARD constexpr bool _In_bounds(const _Ty _Value) { + return _STD in_range<_Make_standard_integer<_CharT>>(static_cast<_Make_standard_integer<_Ty>>(_Value)); +} + +_NODISCARD inline int _Count_separators(size_t _Digits, const string_view _Groups) { + if (_Groups.empty()) { + return 0; + } + + // Calculate the amount of separators that are going to be inserted based on the groupings of the locale. + int _Separators = 0; + auto _Group_it = _Groups.begin(); + while (_Digits > static_cast(*_Group_it)) { + _Digits -= static_cast(*_Group_it); + ++_Separators; + if (_Group_it + 1 != _Groups.end()) { + ++_Group_it; } - _Out = _Widen_and_copy<_CharT>(_First, _Last - _Grouped, _STD move(_Out)); - _First = _Last - _Grouped; + } - for (; _Separators > 0; --_Separators) { - if (_Repeats > 0) { - --_Repeats; - } else { - --_Group_it; - } + return _Separators; +} - *_Out++ = _Separator; - _Out = _Widen_and_copy<_CharT>(_First, _First + *_Group_it, _STD move(_Out)); - _First += *_Group_it; +template +_NODISCARD _OutputIt _Write_separated_integer(const char* _First, const char* const _Last, const string_view _Groups, + const _CharT _Separator, int _Separators, _OutputIt _Out) { + auto _Group_it = _Groups.begin(); + auto _Repeats = 0; + auto _Grouped = 0; + + for (int _Section = 0; _Section < _Separators; ++_Section) { + _Grouped += *_Group_it; + if (_Group_it + 1 != _Groups.end()) { + ++_Group_it; + } else { + ++_Repeats; } - _STL_INTERNAL_CHECK(_First == _Last); - return _Out; } + _Out = _Widen_and_copy<_CharT>(_First, _Last - _Grouped, _STD move(_Out)); + _First = _Last - _Grouped; - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate, const _Basic_format_specs<_CharT>&, _Lazy_locale) { - _STL_INTERNAL_CHECK(false); - return _Out; + for (; _Separators > 0; --_Separators) { + if (_Repeats > 0) { + --_Repeats; + } else { + --_Group_it; + } + + *_Out++ = _Separator; + _Out = _Widen_and_copy<_CharT>(_First, _First + *_Group_it, _STD move(_Out)); + _First += *_Group_it; } + _STL_INTERNAL_CHECK(_First == _Last); + return _Out; +} - template - _NODISCARD _OutputIt _Write_integral( - _OutputIt _Out, _Integral _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate, const _Basic_format_specs<_CharT>&, _Lazy_locale) { + _STL_INTERNAL_CHECK(false); + return _Out; +} + +template +_NODISCARD _OutputIt _Write_integral( + _OutputIt _Out, _Integral _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); #if _HAS_CXX23 - template - _NODISCARD _OutputIt _Write_escaped( - _OutputIt _Out, basic_string_view<_CharT> _Value, _Basic_format_specs<_CharT> _Specs, char _Delim); +template +_NODISCARD _OutputIt _Write_escaped( + _OutputIt _Out, basic_string_view<_CharT> _Value, _Basic_format_specs<_CharT> _Specs, char _Delim); #endif // _HAS_CXX23 - template - requires (!_CharT_or_bool<_Integral, _CharT>) - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, _Integral _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); +template + requires (!_CharT_or_bool<_Integral, _CharT>) +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, _Integral _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, bool _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); +template +_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, bool _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, _CharT _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, _CharT _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, _Float _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, _Float _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const void* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale); +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const void* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale); - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _CharT* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _CharT* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, basic_string_view<_CharT> _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale); +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, basic_string_view<_CharT> _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale); #pragma warning(push) #pragma warning(disable : 4296) // '<': expression is always false - template - _NODISCARD _OutputIt _Write_integral( - _OutputIt _Out, const _Integral _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { - if (_Specs._Type == 'c') { - if (!_In_bounds<_CharT>(_Value)) { - if constexpr (is_same_v<_CharT, char>) { - _Throw_format_error("integral cannot be stored in char"); - } else { - _Throw_format_error("integral cannot be stored in wchar_t"); - } +template +_NODISCARD _OutputIt _Write_integral( + _OutputIt _Out, const _Integral _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { + if (_Specs._Type == 'c') { + if (!_In_bounds<_CharT>(_Value)) { + if constexpr (is_same_v<_CharT, char>) { + _Throw_format_error("integral cannot be stored in char"); + } else { + _Throw_format_error("integral cannot be stored in wchar_t"); } - _Specs._Alt = false; - return _Fmt_write(_STD move(_Out), static_cast<_CharT>(_Value), _Specs, _Locale); } + _Specs._Alt = false; + return _Fmt_write(_STD move(_Out), static_cast<_CharT>(_Value), _Specs, _Locale); + } - _STL_INTERNAL_CHECK(_Specs._Precision == -1); + _STL_INTERNAL_CHECK(_Specs._Precision == -1); - if (_Specs._Sgn == _Fmt_sign::_None) { - _Specs._Sgn = _Fmt_sign::_Minus; - } + if (_Specs._Sgn == _Fmt_sign::_None) { + _Specs._Sgn = _Fmt_sign::_Minus; + } - int _Base = 10; - bool _To_upper = false; + int _Base = 10; + bool _To_upper = false; - switch (_Specs._Type) { - case 'B': - _To_upper = true; - [[fallthrough]]; - case 'b': - _Base = 2; - break; - case 'X': - _To_upper = true; - [[fallthrough]]; - case 'x': - _Base = 16; - break; - case 'o': - _Base = 8; - break; - } + switch (_Specs._Type) { + case 'B': + _To_upper = true; + [[fallthrough]]; + case 'b': + _Base = 2; + break; + case 'X': + _To_upper = true; + [[fallthrough]]; + case 'x': + _Base = 16; + break; + case 'o': + _Base = 8; + break; + } - // long long -1 representation in binary is 64 bits + sign - char _Buffer[65]; - const auto [_End, _Ec] = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Base); - _STL_INTERNAL_CHECK(_Ec == errc{}); + // long long -1 representation in binary is 64 bits + sign + char _Buffer[65]; + const auto [_End, _Ec] = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Base); + _STL_INTERNAL_CHECK(_Ec == errc{}); - auto _Buffer_start = _Buffer; - auto _Width = static_cast(_End - _Buffer_start); + auto _Buffer_start = _Buffer; + auto _Width = static_cast(_End - _Buffer_start); - if (_Value >= _Integral{0}) { - if (_Specs._Sgn != _Fmt_sign::_Minus) { - _Width += 1; - } - } else { - // Remove the '-', it will be dealt with directly - _Buffer_start += 1; + if (_Value >= _Integral{0}) { + if (_Specs._Sgn != _Fmt_sign::_Minus) { + _Width += 1; } + } else { + // Remove the '-', it will be dealt with directly + _Buffer_start += 1; + } - if (_To_upper) { - _Buffer_to_uppercase(_Buffer_start, _End); - } + if (_To_upper) { + _Buffer_to_uppercase(_Buffer_start, _End); + } - string_view _Prefix; - if (_Specs._Alt) { - _Prefix = _Get_integral_prefix(_Specs._Type, _Value); - _Width += static_cast(_Prefix.size()); - } + string_view _Prefix; + if (_Specs._Alt) { + _Prefix = _Get_integral_prefix(_Specs._Type, _Value); + _Width += static_cast(_Prefix.size()); + } - auto _Separators = 0; - string _Groups; - if (_Specs._Localized) { - _Groups = _STD use_facet>(_Locale._Get()).grouping(); - _Separators = _Count_separators(static_cast(_End - _Buffer_start), _Groups); - // TRANSITION, separators may be wider for wide chars - _Width += _Separators; - } - - const bool _Write_leading_zeroes = _Specs._Leading_zero && _Specs._Alignment == _Fmt_align::_None; - auto _Writer = [&, _End = _End](_OutputIt _Out) { - _Out = _Write_sign(_STD move(_Out), _Specs._Sgn, _Value < _Integral{0}); - _Out = _Widen_and_copy<_CharT>(_Prefix.data(), _Prefix.data() + _Prefix.size(), _STD move(_Out)); - if (_Write_leading_zeroes && _Width < _Specs._Width) { - _Out = _RANGES fill_n(_STD move(_Out), _Specs._Width - _Width, _CharT{'0'}); - } + auto _Separators = 0; + string _Groups; + if (_Specs._Localized) { + _Groups = _STD use_facet>(_Locale._Get()).grouping(); + _Separators = _Count_separators(static_cast(_End - _Buffer_start), _Groups); + // TRANSITION, separators may be wider for wide chars + _Width += _Separators; + } - if (_Separators > 0) { - return _Write_separated_integer(_Buffer_start, _End, _Groups, - _STD use_facet>(_Locale._Get()).thousands_sep(), // - _Separators, _STD move(_Out)); - } - return _Widen_and_copy<_CharT>(_Buffer_start, _End, _STD move(_Out)); - }; + const bool _Write_leading_zeroes = _Specs._Leading_zero && _Specs._Alignment == _Fmt_align::_None; + auto _Writer = [&, _End = _End](_OutputIt _Out) { + _Out = _Write_sign(_STD move(_Out), _Specs._Sgn, _Value < _Integral{0}); + _Out = _Widen_and_copy<_CharT>(_Prefix.data(), _Prefix.data() + _Prefix.size(), _STD move(_Out)); + if (_Write_leading_zeroes && _Width < _Specs._Width) { + _Out = _RANGES fill_n(_STD move(_Out), _Specs._Width - _Width, _CharT{'0'}); + } - if (_Write_leading_zeroes) { - return _Writer(_STD move(_Out)); + if (_Separators > 0) { + return _Write_separated_integer(_Buffer_start, _End, _Groups, + _STD use_facet>(_Locale._Get()).thousands_sep(), // + _Separators, _STD move(_Out)); } + return _Widen_and_copy<_CharT>(_Buffer_start, _End, _STD move(_Out)); + }; - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, _Writer); + if (_Write_leading_zeroes) { + return _Writer(_STD move(_Out)); } + + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, _Writer); +} #pragma warning(pop) - template - requires (!_CharT_or_bool<_Integral, _CharT>) - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _Integral _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { - return _Write_integral(_STD move(_Out), _Value, _Specs, _Locale); - } +template + requires (!_CharT_or_bool<_Integral, _CharT>) +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _Integral _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { + return _Write_integral(_STD move(_Out), _Value, _Specs, _Locale); +} - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const bool _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { - if (_Specs._Type != '\0' && _Specs._Type != 's') { - return _Write_integral(_STD move(_Out), static_cast(_Value), _Specs, _Locale); - } +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const bool _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { + if (_Specs._Type != '\0' && _Specs._Type != 's') { + return _Write_integral(_STD move(_Out), static_cast(_Value), _Specs, _Locale); + } - _STL_INTERNAL_CHECK(_Specs._Precision == -1); + _STL_INTERNAL_CHECK(_Specs._Precision == -1); - if (_Specs._Localized) { - _Specs._Localized = false; - const auto& _Facet = _STD use_facet>(_Locale._Get()); - return _Fmt_write(_STD move(_Out), - _Value ? static_cast>(_Facet.truename()) - : static_cast>(_Facet.falsename()), - _Specs, _Locale); - } + if (_Specs._Localized) { + _Specs._Localized = false; + const auto& _Facet = _STD use_facet>(_Locale._Get()); + return _Fmt_write(_STD move(_Out), + _Value ? static_cast>(_Facet.truename()) + : static_cast>(_Facet.falsename()), + _Specs, _Locale); + } - if constexpr (is_same_v<_CharT, wchar_t>) { - return _Fmt_write(_STD move(_Out), _Value ? L"true" : L"false", _Specs, _Locale); - } else { - return _Fmt_write(_STD move(_Out), _Value ? "true" : "false", _Specs, _Locale); - } + if constexpr (is_same_v<_CharT, wchar_t>) { + return _Fmt_write(_STD move(_Out), _Value ? L"true" : L"false", _Specs, _Locale); + } else { + return _Fmt_write(_STD move(_Out), _Value ? "true" : "false", _Specs, _Locale); } +} - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _CharT _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { - if (_Specs._Type != '\0' && _Specs._Type != 'c' +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _CharT _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { + if (_Specs._Type != '\0' && _Specs._Type != 'c' #if _HAS_CXX23 - && _Specs._Type != '?' + && _Specs._Type != '?' #endif // _HAS_CXX23 - ) { - return _Write_integral(_STD move(_Out), _Value, _Specs, _Locale); - } + ) { + return _Write_integral(_STD move(_Out), _Value, _Specs, _Locale); + } - _STL_INTERNAL_CHECK(_Specs._Precision == -1); + _STL_INTERNAL_CHECK(_Specs._Precision == -1); #if _HAS_CXX23 - if (_Specs._Type == '?') { - return _Write_escaped(_STD move(_Out), basic_string_view<_CharT>{&_Value, 1}, _Specs, '\''); - } -#endif // _HAS_CXX23 - - return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{&_Value, 1}, _Specs, _Locale); + if (_Specs._Type == '?') { + return _Write_escaped(_STD move(_Out), basic_string_view<_CharT>{&_Value, 1}, _Specs, '\''); } +#endif // _HAS_CXX23 - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _Float _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { - auto _Sgn = _Specs._Sgn; - if (_Sgn == _Fmt_sign::_None) { - _Sgn = _Fmt_sign::_Minus; - } + return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{&_Value, 1}, _Specs, _Locale); +} - auto _To_upper = false; - auto _Format = chars_format::general; - auto _Exponent = '\0'; - auto _Precision = _Specs._Precision; +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _Float _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { + auto _Sgn = _Specs._Sgn; + if (_Sgn == _Fmt_sign::_None) { + _Sgn = _Fmt_sign::_Minus; + } + + auto _To_upper = false; + auto _Format = chars_format::general; + auto _Exponent = '\0'; + auto _Precision = _Specs._Precision; + + switch (_Specs._Type) { + case 'A': + _To_upper = true; + [[fallthrough]]; + case 'a': + _Format = chars_format::hex; + _Exponent = 'p'; + break; + case 'E': + _To_upper = true; + [[fallthrough]]; + case 'e': + if (_Precision == -1) { + _Precision = 6; + } + _Format = chars_format::scientific; + _Exponent = 'e'; + break; + case 'F': + _To_upper = true; + [[fallthrough]]; + case 'f': + if (_Precision == -1) { + _Precision = 6; + } + _Format = chars_format::fixed; + break; + case 'G': + _To_upper = true; + [[fallthrough]]; + case 'g': + if (_Precision == -1) { + _Precision = 6; + } + _Format = chars_format::general; + _Exponent = 'e'; + break; + } - switch (_Specs._Type) { - case 'A': - _To_upper = true; - [[fallthrough]]; - case 'a': - _Format = chars_format::hex; - _Exponent = 'p'; - break; - case 'E': - _To_upper = true; - [[fallthrough]]; - case 'e': - if (_Precision == -1) { - _Precision = 6; - } - _Format = chars_format::scientific; - _Exponent = 'e'; - break; - case 'F': - _To_upper = true; - [[fallthrough]]; - case 'f': - if (_Precision == -1) { - _Precision = 6; - } - _Format = chars_format::fixed; - break; - case 'G': - _To_upper = true; - [[fallthrough]]; - case 'g': - if (_Precision == -1) { - _Precision = 6; - } - _Format = chars_format::general; - _Exponent = 'e'; - break; + // Consider the powers of 2 in decimal: + // 2^-1 = 0.5 + // 2^-2 = 0.25 + // 2^-3 = 0.125 + // 2^-4 = 0.0625 + // Each power of 2 consumes one more decimal digit. This is because: + // 2^-N * 5^-N = 10^-N + // 2^-N = 10^-N * 5^N + // Example: 2^-4 = 10^-4 * 5^4 = 0.0001 * 625 + // Therefore, the min subnormal 2^-1074 consumes 1074 digits of precision (digits after the decimal point). + // We need 3 more characters for a potential negative sign, the zero integer part, and the decimal point. + // Therefore, the precision can be clamped to 1074. + // The largest number consumes 309 digits before the decimal point. With a precision of 1074, and it being + // negative, it would use a buffer of size 1074+309+2. We need to add an additional number to the max + // exponent to accommodate the ones place. + constexpr auto _Max_precision = 1074; + constexpr auto _Buffer_size = _Max_precision + DBL_MAX_10_EXP + 3; + char _Buffer[_Buffer_size]; + to_chars_result _Result; + + auto _Extra_precision = 0; + if (_Precision > _Max_precision) { + _Extra_precision = _Precision - _Max_precision; + _Precision = _Max_precision; + } + + const auto _Is_negative = (_STD signbit)(_Value); + + if ((_STD isnan)(_Value)) { + _Result.ptr = _Buffer; + if (_Is_negative) { + ++_Result.ptr; // pretend to skip over a '-' that to_chars would put in _Buffer[0] } - // Consider the powers of 2 in decimal: - // 2^-1 = 0.5 - // 2^-2 = 0.25 - // 2^-3 = 0.125 - // 2^-4 = 0.0625 - // Each power of 2 consumes one more decimal digit. This is because: - // 2^-N * 5^-N = 10^-N - // 2^-N = 10^-N * 5^N - // Example: 2^-4 = 10^-4 * 5^4 = 0.0001 * 625 - // Therefore, the min subnormal 2^-1074 consumes 1074 digits of precision (digits after the decimal point). - // We need 3 more characters for a potential negative sign, the zero integer part, and the decimal point. - // Therefore, the precision can be clamped to 1074. - // The largest number consumes 309 digits before the decimal point. With a precision of 1074, and it being - // negative, it would use a buffer of size 1074+309+2. We need to add an additional number to the max - // exponent to accommodate the ones place. - constexpr auto _Max_precision = 1074; - constexpr auto _Buffer_size = _Max_precision + DBL_MAX_10_EXP + 3; - char _Buffer[_Buffer_size]; - to_chars_result _Result; - - auto _Extra_precision = 0; - if (_Precision > _Max_precision) { - _Extra_precision = _Precision - _Max_precision; - _Precision = _Max_precision; - } - - const auto _Is_negative = (_STD signbit)(_Value); - - if ((_STD isnan)(_Value)) { - _Result.ptr = _Buffer; - if (_Is_negative) { - ++_Result.ptr; // pretend to skip over a '-' that to_chars would put in _Buffer[0] - } - - _CSTD memcpy(_Result.ptr, "nan", 3); - _Result.ptr += 3; + _CSTD memcpy(_Result.ptr, "nan", 3); + _Result.ptr += 3; + } else { + if (_Precision == -1) { + _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Format); } else { - if (_Precision == -1) { - _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Format); - } else { - _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Format, _Precision); - } - - _STL_INTERNAL_CHECK(_Result.ec == errc{}); + _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Format, _Precision); } - auto _Buffer_start = _Buffer; - auto _Width = static_cast(_Result.ptr - _Buffer_start); + _STL_INTERNAL_CHECK(_Result.ec == errc{}); + } - if (_Is_negative) { - // Remove the '-', it will be dealt with directly - _Buffer_start += 1; - } else { - if (_Sgn != _Fmt_sign::_Minus) { - _Width += 1; - } - } + auto _Buffer_start = _Buffer; + auto _Width = static_cast(_Result.ptr - _Buffer_start); - if (_To_upper) { - _Buffer_to_uppercase(_Buffer_start, _Result.ptr); - _Exponent = static_cast(_CSTD toupper(_Exponent)); + if (_Is_negative) { + // Remove the '-', it will be dealt with directly + _Buffer_start += 1; + } else { + if (_Sgn != _Fmt_sign::_Minus) { + _Width += 1; } + } + + if (_To_upper) { + _Buffer_to_uppercase(_Buffer_start, _Result.ptr); + _Exponent = static_cast(_CSTD toupper(_Exponent)); + } - const auto _Is_finite = (_STD isfinite)(_Value); + const auto _Is_finite = (_STD isfinite)(_Value); - auto _Append_decimal = false; - auto _Exponent_start = _Result.ptr; - auto _Radix_point = _Result.ptr; - auto _Integral_end = _Result.ptr; - auto _Zeroes_to_append = 0; - auto _Separators = 0; - string _Groups; + auto _Append_decimal = false; + auto _Exponent_start = _Result.ptr; + auto _Radix_point = _Result.ptr; + auto _Integral_end = _Result.ptr; + auto _Zeroes_to_append = 0; + auto _Separators = 0; + string _Groups; - if (_Is_finite) { - if (_Specs._Alt || _Specs._Localized) { - for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) { - if (*_It == '.') { - _Radix_point = _It; - } else if (*_It == _Exponent) { - _Exponent_start = _It; - } + if (_Is_finite) { + if (_Specs._Alt || _Specs._Localized) { + for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) { + if (*_It == '.') { + _Radix_point = _It; + } else if (*_It == _Exponent) { + _Exponent_start = _It; } - _Integral_end = (_STD min)(_Radix_point, _Exponent_start); + } + _Integral_end = (_STD min)(_Radix_point, _Exponent_start); - if (_Specs._Alt && _Radix_point == _Result.ptr) { - // TRANSITION, decimal point may be wider - ++_Width; - _Append_decimal = true; - } + if (_Specs._Alt && _Radix_point == _Result.ptr) { + // TRANSITION, decimal point may be wider + ++_Width; + _Append_decimal = true; + } + + if (_Specs._Localized) { + _Groups = _STD use_facet>(_Locale._Get()).grouping(); + _Separators = _Count_separators(static_cast(_Integral_end - _Buffer_start), _Groups); + } + } - if (_Specs._Localized) { - _Groups = _STD use_facet>(_Locale._Get()).grouping(); - _Separators = _Count_separators(static_cast(_Integral_end - _Buffer_start), _Groups); + switch (_Format) { + case chars_format::hex: + case chars_format::scientific: + if (_Extra_precision != 0) { + // Trailing zeroes are in front of the exponent + while (*--_Exponent_start != _Exponent) { } } + [[fallthrough]]; + case chars_format::fixed: + _Zeroes_to_append = _Extra_precision; + break; + case chars_format::general: + if (_Specs._Alt) { + auto _Digits = static_cast(_Exponent_start - _Buffer_start); - switch (_Format) { - case chars_format::hex: - case chars_format::scientific: - if (_Extra_precision != 0) { - // Trailing zeroes are in front of the exponent - while (*--_Exponent_start != _Exponent) { - } + if (!_Append_decimal) { + --_Digits; } - [[fallthrough]]; - case chars_format::fixed: - _Zeroes_to_append = _Extra_precision; - break; - case chars_format::general: - if (_Specs._Alt) { - auto _Digits = static_cast(_Exponent_start - _Buffer_start); - - if (!_Append_decimal) { - --_Digits; - } - _Zeroes_to_append = _Extra_precision + _Precision - _Digits; + _Zeroes_to_append = _Extra_precision + _Precision - _Digits; - // Leading zeroes are not significant if we used fixed point notation. - if (_Exponent_start == _Result.ptr && _STD abs(_Value) < 1.0 && _Value != 0.0) { - for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) { - if (*_It == '0') { - ++_Zeroes_to_append; - } else if (*_It != '.') { - break; - } + // Leading zeroes are not significant if we used fixed point notation. + if (_Exponent_start == _Result.ptr && _STD abs(_Value) < 1.0 && _Value != 0.0) { + for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) { + if (*_It == '0') { + ++_Zeroes_to_append; + } else if (*_It != '.') { + break; } } } - break; - default: - _STL_UNREACHABLE; } + break; + default: + _STL_UNREACHABLE; } + } - _Width += _Zeroes_to_append; + _Width += _Zeroes_to_append; - const bool _Write_leading_zeroes = _Specs._Leading_zero && _Specs._Alignment == _Fmt_align::_None && _Is_finite; + const bool _Write_leading_zeroes = _Specs._Leading_zero && _Specs._Alignment == _Fmt_align::_None && _Is_finite; - auto _Writer = [&](_OutputIt _Out) { - _Out = _Write_sign(_STD move(_Out), _Sgn, _Is_negative); + auto _Writer = [&](_OutputIt _Out) { + _Out = _Write_sign(_STD move(_Out), _Sgn, _Is_negative); - if (_Write_leading_zeroes && _Width < _Specs._Width) { - _Out = _RANGES fill_n(_STD move(_Out), _Specs._Width - _Width, _CharT{'0'}); - } + if (_Write_leading_zeroes && _Width < _Specs._Width) { + _Out = _RANGES fill_n(_STD move(_Out), _Specs._Width - _Width, _CharT{'0'}); + } - if (_Specs._Localized) { - const auto& _Facet = _STD use_facet>(_Locale._Get()); + if (_Specs._Localized) { + const auto& _Facet = _STD use_facet>(_Locale._Get()); - _Out = _Write_separated_integer( - _Buffer_start, _Integral_end, _Groups, _Facet.thousands_sep(), _Separators, _STD move(_Out)); - if (_Radix_point != _Result.ptr || _Append_decimal) { - *_Out++ = _Facet.decimal_point(); - _Append_decimal = false; - } - _Buffer_start = _Integral_end; - if (_Radix_point != _Result.ptr) { - ++_Buffer_start; - } + _Out = _Write_separated_integer( + _Buffer_start, _Integral_end, _Groups, _Facet.thousands_sep(), _Separators, _STD move(_Out)); + if (_Radix_point != _Result.ptr || _Append_decimal) { + *_Out++ = _Facet.decimal_point(); + _Append_decimal = false; } - - _Out = _Widen_and_copy<_CharT>(_Buffer_start, _Exponent_start, _STD move(_Out)); - if (_Specs._Alt && _Append_decimal) { - *_Out++ = '.'; + _Buffer_start = _Integral_end; + if (_Radix_point != _Result.ptr) { + ++_Buffer_start; } - - for (; _Zeroes_to_append > 0; --_Zeroes_to_append) { - *_Out++ = '0'; - } - - return _Widen_and_copy<_CharT>(_Exponent_start, _Result.ptr, _STD move(_Out)); - }; - - if (_Write_leading_zeroes) { - return _Writer(_STD move(_Out)); } - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, _Writer); - } - - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const void* const _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale) { - _STL_INTERNAL_CHECK(_Specs._Type == '\0' || _Specs._Type == 'p'); - _STL_INTERNAL_CHECK(_Specs._Sgn == _Fmt_sign::_None); - _STL_INTERNAL_CHECK(!_Specs._Alt); - _STL_INTERNAL_CHECK(_Specs._Precision == -1); - _STL_INTERNAL_CHECK(!_Specs._Leading_zero); - _STL_INTERNAL_CHECK(!_Specs._Localized); + _Out = _Widen_and_copy<_CharT>(_Buffer_start, _Exponent_start, _STD move(_Out)); + if (_Specs._Alt && _Append_decimal) { + *_Out++ = '.'; + } - // Since the bit width of 0 is 0x0, special-case it instead of complicating the math even more. - int _Width = 3; - if (_Value != nullptr) { - // Compute the bit width of the pointer (i.e. how many bits it takes to be represented). - // Add 3 to the bit width so we always round up on the division. - // Divide that by the amount of bits a hexit represents (log2(16) = log2(2^4) = 4). - // Add 2 for the 0x prefix. - _Width = 2 + (_STD bit_width(reinterpret_cast(_Value)) + 3) / 4; + for (; _Zeroes_to_append > 0; --_Zeroes_to_append) { + *_Out++ = '0'; } - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, - [=](_OutputIt _Out) { return _Fmt_write<_CharT>(_STD move(_Out), _Value); }); - } + return _Widen_and_copy<_CharT>(_Exponent_start, _Result.ptr, _STD move(_Out)); + }; - template - _NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _CharT* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { - return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Value}, _Specs, _Locale); + if (_Write_leading_zeroes) { + return _Writer(_STD move(_Out)); } - // width iterator for UTF-8 and UTF-16 - template - class _Measure_string_prefix_iterator_utf { - private: - _Grapheme_break_property_iterator<_CharT> _WrappedIter; + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, _Writer); +} - public: - _NODISCARD constexpr bool operator==(const _Measure_string_prefix_iterator_utf&) const noexcept = default; +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const void* const _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale) { + _STL_INTERNAL_CHECK(_Specs._Type == '\0' || _Specs._Type == 'p'); + _STL_INTERNAL_CHECK(_Specs._Sgn == _Fmt_sign::_None); + _STL_INTERNAL_CHECK(!_Specs._Alt); + _STL_INTERNAL_CHECK(_Specs._Precision == -1); + _STL_INTERNAL_CHECK(!_Specs._Leading_zero); + _STL_INTERNAL_CHECK(!_Specs._Localized); + + // Since the bit width of 0 is 0x0, special-case it instead of complicating the math even more. + int _Width = 3; + if (_Value != nullptr) { + // Compute the bit width of the pointer (i.e. how many bits it takes to be represented). + // Add 3 to the bit width so we always round up on the division. + // Divide that by the amount of bits a hexit represents (log2(16) = log2(2^4) = 4). + // Add 2 for the 0x prefix. + _Width = 2 + (_STD bit_width(reinterpret_cast(_Value)) + 3) / 4; + } + + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, + [=](_OutputIt _Out) { return _Fmt_write<_CharT>(_STD move(_Out), _Value); }); +} - _NODISCARD constexpr bool operator==(default_sentinel_t) const noexcept { - return _WrappedIter == default_sentinel; - } +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _CharT* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { + return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Value}, _Specs, _Locale); +} - using difference_type = ptrdiff_t; - using value_type = int; +// width iterator for UTF-8 and UTF-16 +template +class _Measure_string_prefix_iterator_utf { +private: + _Grapheme_break_property_iterator<_CharT> _WrappedIter; - constexpr _Measure_string_prefix_iterator_utf(const _CharT* _First, const _CharT* _Last) - : _WrappedIter(_First, _Last) {} +public: + _NODISCARD constexpr bool operator==(const _Measure_string_prefix_iterator_utf&) const noexcept = default; - constexpr _Measure_string_prefix_iterator_utf() = default; + _NODISCARD constexpr bool operator==(default_sentinel_t) const noexcept { + return _WrappedIter == default_sentinel; + } - _NODISCARD constexpr value_type operator*() const { - return _Unicode_width_estimate(*_WrappedIter); - } + using difference_type = ptrdiff_t; + using value_type = int; - constexpr _Measure_string_prefix_iterator_utf& operator++() noexcept { - ++_WrappedIter; - return *this; - } + constexpr _Measure_string_prefix_iterator_utf(const _CharT* _First, const _CharT* _Last) + : _WrappedIter(_First, _Last) {} - constexpr _Measure_string_prefix_iterator_utf operator++(int) noexcept { - auto _Old = *this; - ++*this; - return _Old; - } + constexpr _Measure_string_prefix_iterator_utf() = default; - _NODISCARD constexpr const _CharT* _Position() const { - return _WrappedIter._Position(); - } - }; + _NODISCARD constexpr value_type operator*() const { + return _Unicode_width_estimate(*_WrappedIter); + } - class _Measure_string_prefix_iterator_legacy { - private: - _Fmt_codec _Codec = _Get_fmt_codec(); - const char* _First = nullptr; - const char* _Last = nullptr; - int _Units = 0; - - void _Update_units() { - if (_First < _Last) { - _Units = _Codec._Units_in_next_character(_First, _Last); - } else { - _Units = -1; - } - } + constexpr _Measure_string_prefix_iterator_utf& operator++() noexcept { + ++_WrappedIter; + return *this; + } - public: - _NODISCARD bool operator==(default_sentinel_t) const noexcept { - return _First == _Last; - } - _NODISCARD bool operator==(const _Measure_string_prefix_iterator_legacy& _Rhs) const noexcept { - return _First == _Rhs._First && _Last == _Rhs._Last; - } + constexpr _Measure_string_prefix_iterator_utf operator++(int) noexcept { + auto _Old = *this; + ++*this; + return _Old; + } - using difference_type = ptrdiff_t; - using value_type = int; + _NODISCARD constexpr const _CharT* _Position() const { + return _WrappedIter._Position(); + } +}; - _Measure_string_prefix_iterator_legacy(const char* _First_val, const char* _Last_val) - : _First(_First_val), _Last(_Last_val) { - _Update_units(); +class _Measure_string_prefix_iterator_legacy { +private: + _Fmt_codec _Codec = _Get_fmt_codec(); + const char* _First = nullptr; + const char* _Last = nullptr; + int _Units = 0; + + void _Update_units() { + if (_First < _Last) { + _Units = _Codec._Units_in_next_character(_First, _Last); + } else { + _Units = -1; } + } - _Measure_string_prefix_iterator_legacy() = default; +public: + _NODISCARD bool operator==(default_sentinel_t) const noexcept { + return _First == _Last; + } + _NODISCARD bool operator==(const _Measure_string_prefix_iterator_legacy& _Rhs) const noexcept { + return _First == _Rhs._First && _Last == _Rhs._Last; + } - _Measure_string_prefix_iterator_legacy& operator++() noexcept { - _First += _Units; - _Update_units(); - return *this; - } - _Measure_string_prefix_iterator_legacy operator++(int) noexcept { - auto _Old = *this; - ++*this; - return _Old; - } - _NODISCARD value_type operator*() const noexcept { - return _Units; - } + using difference_type = ptrdiff_t; + using value_type = int; - _NODISCARD const char* _Position() const noexcept { - return _First; - } - }; + _Measure_string_prefix_iterator_legacy(const char* _First_val, const char* _Last_val) + : _First(_First_val), _Last(_Last_val) { + _Update_units(); + } - template - using _Measure_string_prefix_iterator = - conditional_t && !_Is_execution_charset_self_synchronizing(), - _Measure_string_prefix_iterator_legacy, _Measure_string_prefix_iterator_utf<_CharT>>; + _Measure_string_prefix_iterator_legacy() = default; - template - _NODISCARD const _CharT* _Measure_string_prefix(const basic_string_view<_CharT> _Value, int& _Width) { - // Returns a pointer past-the-end of the largest prefix of _Value that fits in _Width, or all - // of _Value if _Width is negative. Updates _Width to the estimated width of that prefix. - const int _Max_width = _Width; - const auto _First = _Value.data(); - const auto _Last = _First + _Value.size(); - _Measure_string_prefix_iterator<_CharT> _Pfx_iter(_First, _Last); - int _Estimated_width = 0; // the estimated width of [_First, _Pfx_iter) - - constexpr auto _Max_int = (numeric_limits::max)(); - - while (_Pfx_iter != default_sentinel) { - if (_Estimated_width == _Max_width && _Max_width >= 0) { - // We're at our maximum length - break; - } + _Measure_string_prefix_iterator_legacy& operator++() noexcept { + _First += _Units; + _Update_units(); + return *this; + } + _Measure_string_prefix_iterator_legacy operator++(int) noexcept { + auto _Old = *this; + ++*this; + return _Old; + } + _NODISCARD value_type operator*() const noexcept { + return _Units; + } - const int _Character_width = *_Pfx_iter; + _NODISCARD const char* _Position() const noexcept { + return _First; + } +}; - if (_Max_int - _Character_width < _Estimated_width) { // avoid overflow - // Either _Max_width isn't set, or adding this character will exceed it. - if (_Max_width < 0) { // unset; saturate width estimate and take all characters - _Width = _Max_int; - return _Last; - } - break; - } +template +using _Measure_string_prefix_iterator = + conditional_t && !_Is_execution_charset_self_synchronizing(), + _Measure_string_prefix_iterator_legacy, _Measure_string_prefix_iterator_utf<_CharT>>; + +template +_NODISCARD const _CharT* _Measure_string_prefix(const basic_string_view<_CharT> _Value, int& _Width) { + // Returns a pointer past-the-end of the largest prefix of _Value that fits in _Width, or all + // of _Value if _Width is negative. Updates _Width to the estimated width of that prefix. + const int _Max_width = _Width; + const auto _First = _Value.data(); + const auto _Last = _First + _Value.size(); + _Measure_string_prefix_iterator<_CharT> _Pfx_iter(_First, _Last); + int _Estimated_width = 0; // the estimated width of [_First, _Pfx_iter) + + constexpr auto _Max_int = (numeric_limits::max)(); + + while (_Pfx_iter != default_sentinel) { + if (_Estimated_width == _Max_width && _Max_width >= 0) { + // We're at our maximum length + break; + } - _Estimated_width += _Character_width; - if (_Estimated_width > _Max_width && _Max_width >= 0) { - // with this character, we exceed the maximum length - _Estimated_width -= _Character_width; - break; + const int _Character_width = *_Pfx_iter; + + if (_Max_int - _Character_width < _Estimated_width) { // avoid overflow + // Either _Max_width isn't set, or adding this character will exceed it. + if (_Max_width < 0) { // unset; saturate width estimate and take all characters + _Width = _Max_int; + return _Last; } - ++_Pfx_iter; + break; } - _Width = _Estimated_width; - return _Pfx_iter._Position(); + _Estimated_width += _Character_width; + if (_Estimated_width > _Max_width && _Max_width >= 0) { + // with this character, we exceed the maximum length + _Estimated_width -= _Character_width; + break; + } + ++_Pfx_iter; } -#if _HAS_CXX23 - _NODISCARD constexpr bool _Is_printable(char32_t _Val) { - return __printable_property_data._Get_property_for_codepoint(_Val) == __printable_property_values::_Yes_value; - } + _Width = _Estimated_width; + return _Pfx_iter._Position(); +} - _NODISCARD constexpr bool _Is_grapheme_extend(char32_t _Val) { - // TRANSITION, should reuse _Grapheme_Break_property_data to save space. - // (Grapheme_Extend=Yes is Grapheme_Cluster_Break=Extend minus Emoji_Modifier=Yes.) - return _Grapheme_Extend_property_data._Get_property_for_codepoint(_Val) - == _Grapheme_Extend_property_values::_Grapheme_Extend_value; - } +#if _HAS_CXX23 +_NODISCARD constexpr bool _Is_printable(char32_t _Val) { + return __printable_property_data._Get_property_for_codepoint(_Val) == __printable_property_values::_Yes_value; +} - template - _NODISCARD _OutputIt _Write_escaped(_OutputIt _Out, basic_string_view<_CharT> _Value, char _Delim) { - auto _First = _Value.data(); - const auto _Last = _First + _Value.size(); - const auto& _Codec = _Get_fmt_codec<_CharT>(); +_NODISCARD constexpr bool _Is_grapheme_extend(char32_t _Val) { + // TRANSITION, should reuse _Grapheme_Break_property_data to save space. + // (Grapheme_Extend=Yes is Grapheme_Cluster_Break=Extend minus Emoji_Modifier=Yes.) + return _Grapheme_Extend_property_data._Get_property_for_codepoint(_Val) + == _Grapheme_Extend_property_values::_Grapheme_Extend_value; +} - _STL_INTERNAL_CHECK(_Delim == '"' || _Delim == '\''); - *_Out++ = static_cast<_CharT>(_Delim); +template +_NODISCARD _OutputIt _Write_escaped(_OutputIt _Out, basic_string_view<_CharT> _Value, char _Delim) { + auto _First = _Value.data(); + const auto _Last = _First + _Value.size(); + const auto& _Codec = _Get_fmt_codec<_CharT>(); - bool _Escape_grapheme_extend = true; + _STL_INTERNAL_CHECK(_Delim == '"' || _Delim == '\''); + *_Out++ = static_cast<_CharT>(_Delim); - char _Buffer[8]; + bool _Escape_grapheme_extend = true; - while (_First != _Last) { - const auto _Ch = *_First; + char _Buffer[8]; - if (_Ch == static_cast<_CharT>('\t')) { - _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\t)")); - _Escape_grapheme_extend = true; - ++_First; - } else if (_Ch == static_cast<_CharT>('\n')) { - _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\n)")); - _Escape_grapheme_extend = true; - ++_First; - } else if (_Ch == static_cast<_CharT>('\r')) { - _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\r)")); - _Escape_grapheme_extend = true; - ++_First; - } else if (_Ch == static_cast<_CharT>(_Delim)) { - *_Out++ = static_cast<_CharT>('\\'); - *_Out++ = static_cast<_CharT>(_Delim); - _Escape_grapheme_extend = true; - ++_First; - } else if (_Ch == static_cast<_CharT>('\\')) { - _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\\)")); - _Escape_grapheme_extend = true; - ++_First; - } else { - char32_t _Decoded_ch; - const auto [_Next, _Is_usv] = _Codec._Decode(_First, _Last, _Decoded_ch); + while (_First != _Last) { + const auto _Ch = *_First; - if (_Is_usv) { - const bool _Needs_escape = - !_Is_printable(_Decoded_ch) || (_Escape_grapheme_extend && _Is_grapheme_extend(_Decoded_ch)); + if (_Ch == static_cast<_CharT>('\t')) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\t)")); + _Escape_grapheme_extend = true; + ++_First; + } else if (_Ch == static_cast<_CharT>('\n')) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\n)")); + _Escape_grapheme_extend = true; + ++_First; + } else if (_Ch == static_cast<_CharT>('\r')) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\r)")); + _Escape_grapheme_extend = true; + ++_First; + } else if (_Ch == static_cast<_CharT>(_Delim)) { + *_Out++ = static_cast<_CharT>('\\'); + *_Out++ = static_cast<_CharT>(_Delim); + _Escape_grapheme_extend = true; + ++_First; + } else if (_Ch == static_cast<_CharT>('\\')) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\\)")); + _Escape_grapheme_extend = true; + ++_First; + } else { + char32_t _Decoded_ch; + const auto [_Next, _Is_usv] = _Codec._Decode(_First, _Last, _Decoded_ch); - if (_Needs_escape) { - _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\u{)")); + if (_Is_usv) { + const bool _Needs_escape = + !_Is_printable(_Decoded_ch) || (_Escape_grapheme_extend && _Is_grapheme_extend(_Decoded_ch)); - const auto [_End, _Ec] = - _STD to_chars(_Buffer, _STD end(_Buffer), static_cast(_Decoded_ch), 16); - _STL_INTERNAL_CHECK(_Ec == errc{}); + if (_Needs_escape) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\u{)")); - _Out = _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); + const auto [_End, _Ec] = + _STD to_chars(_Buffer, _STD end(_Buffer), static_cast(_Decoded_ch), 16); + _STL_INTERNAL_CHECK(_Ec == errc{}); - *_Out++ = static_cast<_CharT>('}'); - _Escape_grapheme_extend = true; - } else { - _Out = _STD _Copy_unchecked(_First, _Next, _STD move(_Out)); - _Escape_grapheme_extend = false; - } + _Out = _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); - _First = _Next; + *_Out++ = static_cast<_CharT>('}'); + _Escape_grapheme_extend = true; } else { - for (; _First != _Next; ++_First) { - _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\x{)")); + _Out = _STD _Copy_unchecked(_First, _Next, _STD move(_Out)); + _Escape_grapheme_extend = false; + } - const auto [_End, _Ec] = _STD to_chars( - _Buffer, _STD end(_Buffer), static_cast>(*_First), 16); - _STL_INTERNAL_CHECK(_Ec == errc{}); + _First = _Next; + } else { + for (; _First != _Next; ++_First) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\x{)")); - _Out = _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); + const auto [_End, _Ec] = + _STD to_chars(_Buffer, _STD end(_Buffer), static_cast>(*_First), 16); + _STL_INTERNAL_CHECK(_Ec == errc{}); - *_Out++ = static_cast<_CharT>('}'); - } - _Escape_grapheme_extend = true; + _Out = _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); + + *_Out++ = static_cast<_CharT>('}'); } + _Escape_grapheme_extend = true; } } - - *_Out++ = static_cast<_CharT>(_Delim); - - return _STD move(_Out); } - template - _NODISCARD _OutputIt _Write_escaped( - _OutputIt _Out, basic_string_view<_CharT> _Value, _Basic_format_specs<_CharT> _Specs, char _Delim) { - if (_Specs._Precision < 0 && _Specs._Width <= 0) { - return _Write_escaped(_STD move(_Out), _Value, _Delim); - } + *_Out++ = static_cast<_CharT>(_Delim); - basic_string<_CharT> _Temp; - { - _Fmt_iterator_buffer>, _CharT> _Buf(back_insert_iterator{_Temp}); - (void) _Write_escaped(back_insert_iterator<_Fmt_buffer<_CharT>>{_Buf}, _Value, _Delim); - } + return _STD move(_Out); +} - int _Width = _Specs._Precision; - const _CharT* _Last = _Measure_string_prefix<_CharT>(_Temp, _Width); +template +_NODISCARD _OutputIt _Write_escaped( + _OutputIt _Out, basic_string_view<_CharT> _Value, _Basic_format_specs<_CharT> _Specs, char _Delim) { + if (_Specs._Precision < 0 && _Specs._Width <= 0) { + return _Write_escaped(_STD move(_Out), _Value, _Delim); + } - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Left, [&_Temp, _Last](_OutputIt _Out) { - return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Temp.data(), _Last}); - }); + basic_string<_CharT> _Temp; + { + _Fmt_iterator_buffer>, _CharT> _Buf(back_insert_iterator{_Temp}); + (void) _Write_escaped(back_insert_iterator<_Fmt_buffer<_CharT>>{_Buf}, _Value, _Delim); } + + int _Width = _Specs._Precision; + const _CharT* _Last = _Measure_string_prefix<_CharT>(_Temp, _Width); + + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Left, [&_Temp, _Last](_OutputIt _Out) { + return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Temp.data(), _Last}); + }); +} #endif // _HAS_CXX23 - template - _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const basic_string_view<_CharT> _Value, - const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale) { - _STL_INTERNAL_CHECK(_Specs._Type == '\0' || _Specs._Type == 'c' || _Specs._Type == 's' || _Specs._Type == '?'); - _STL_INTERNAL_CHECK(_Specs._Sgn == _Fmt_sign::_None); - _STL_INTERNAL_CHECK(!_Specs._Alt); - _STL_INTERNAL_CHECK(!_Specs._Leading_zero); +template +_NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const basic_string_view<_CharT> _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale) { + _STL_INTERNAL_CHECK(_Specs._Type == '\0' || _Specs._Type == 'c' || _Specs._Type == 's' || _Specs._Type == '?'); + _STL_INTERNAL_CHECK(_Specs._Sgn == _Fmt_sign::_None); + _STL_INTERNAL_CHECK(!_Specs._Alt); + _STL_INTERNAL_CHECK(!_Specs._Leading_zero); #if _HAS_CXX23 - if (_Specs._Type == '?') { - return _Write_escaped(_STD move(_Out), _Value, _Specs, '"'); - } + if (_Specs._Type == '?') { + return _Write_escaped(_STD move(_Out), _Value, _Specs, '"'); + } #endif // _HAS_CXX23 - if (_Specs._Precision < 0 && _Specs._Width <= 0) { - return _Fmt_write(_STD move(_Out), _Value); - } + if (_Specs._Precision < 0 && _Specs._Width <= 0) { + return _Fmt_write(_STD move(_Out), _Value); + } - int _Width = _Specs._Precision; - const _CharT* _Last = _Measure_string_prefix(_Value, _Width); + int _Width = _Specs._Precision; + const _CharT* _Last = _Measure_string_prefix(_Value, _Width); - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Left, [=](_OutputIt _Out) { - return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Value.data(), _Last}); - }); + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Left, [=](_OutputIt _Out) { + return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Value.data(), _Last}); + }); +} + +// This is the visitor that's used for "simple" replacement fields. +// It could be a generic lambda, but that's bad for throughput. +// A simple replacement field is a replacement field that's just "{}", +// without any format specs. +template +struct _Default_arg_formatter { + using _Context = basic_format_context<_OutputIt, _CharT>; + + _OutputIt _Out; + basic_format_args<_Context> _Args; + _Lazy_locale _Loc; + + template + _OutputIt operator()(_Ty _Val) && { + return _Fmt_write<_CharT>(_STD move(_Out), _Val); } - // This is the visitor that's used for "simple" replacement fields. - // It could be a generic lambda, but that's bad for throughput. - // A simple replacement field is a replacement field that's just "{}", - // without any format specs. - template - struct _Default_arg_formatter { - using _Context = basic_format_context<_OutputIt, _CharT>; + _OutputIt operator()(typename basic_format_arg<_Context>::handle _Handle) && { + basic_format_parse_context<_CharT> _Parse_ctx({}); + basic_format_context<_OutputIt, _CharT> _Format_ctx(_STD move(_Out), _Args, _Loc); + _Handle.format(_Parse_ctx, _Format_ctx); + return _Format_ctx.out(); + } +}; - _OutputIt _Out; - basic_format_args<_Context> _Args; - _Lazy_locale _Loc; +// Visitor used for replacement fields that contain specs +template +struct _Arg_formatter { + using _Context = basic_format_context<_OutputIt, _CharT>; - template - _OutputIt operator()(_Ty _Val) && { - return _Fmt_write<_CharT>(_STD move(_Out), _Val); - } + _Context* _Ctx = nullptr; + _Basic_format_specs<_CharT>* _Specs = nullptr; - _OutputIt operator()(typename basic_format_arg<_Context>::handle _Handle) && { - basic_format_parse_context<_CharT> _Parse_ctx({}); - basic_format_context<_OutputIt, _CharT> _Format_ctx(_STD move(_Out), _Args, _Loc); - _Handle.format(_Parse_ctx, _Format_ctx); - return _Format_ctx.out(); - } - }; + _OutputIt operator()(typename basic_format_arg<_Context>::handle) { + _STL_VERIFY(false, "The custom handler should be structurally unreachable for _Arg_formatter"); + _STL_INTERNAL_CHECK(_Ctx); + return _Ctx->out(); + } - // Visitor used for replacement fields that contain specs - template - struct _Arg_formatter { - using _Context = basic_format_context<_OutputIt, _CharT>; + template + _OutputIt operator()(_Ty _Val) { + _STL_INTERNAL_CHECK(_Specs); + _STL_INTERNAL_CHECK(_Ctx); + return _Fmt_write(_Ctx->out(), _Val, *_Specs, _Ctx->_Get_lazy_locale()); + } +}; - _Context* _Ctx = nullptr; - _Basic_format_specs<_CharT>* _Specs = nullptr; +// Special compile time version of _Parse_format_specs. This version is parameterized on +// the type of the argument associated with the format specifier, since we don't really +// care about avoiding code bloat for code that never runs at runtime, and we can't form +// the erased basic_format_args structure at compile time. +template +consteval typename _ParseContext::iterator _Compile_time_parse_format_specs(_ParseContext& _Pc) { + using _CharT = typename _ParseContext::char_type; + using _Context = basic_format_context>, _CharT>; + using _ArgTraits = _Format_arg_traits<_Context>; + using _FormattedTypeMapping = typename _ArgTraits::template _Storage_type<_Ty>; + // If the type is going to use a custom formatter we should just use that, + // instead of trying to instantiate a custom formatter for its erased handle + // type + using _FormattedType = conditional_t::handle>, + _Ty, _FormattedTypeMapping>; + formatter<_FormattedType, _CharT> _Formatter{}; + return _Formatter.parse(_Pc); +} - _OutputIt operator()(typename basic_format_arg<_Context>::handle) { - _STL_VERIFY(false, "The custom handler should be structurally unreachable for _Arg_formatter"); - _STL_INTERNAL_CHECK(_Ctx); - return _Ctx->out(); +// set of format parsing actions that only checks for validity +template +struct _Format_checker { + using _ParseContext = basic_format_parse_context<_CharT>; + using _ParseFunc = typename _ParseContext::iterator (*)(_ParseContext&); + + static constexpr size_t _Num_args = sizeof...(_Args); + _ParseContext _Parse_context; + _ParseFunc _Parse_funcs[_Num_args > 0 ? _Num_args : 1]; + + consteval explicit _Format_checker(basic_string_view<_CharT> _Fmt) noexcept + : _Parse_context(_Fmt, _Num_args), _Parse_funcs{&_Compile_time_parse_format_specs<_Args, _ParseContext>...} {} + constexpr void _On_text(const _CharT*, const _CharT*) const noexcept {} + constexpr void _On_replacement_field(size_t, const _CharT*) const noexcept {} + constexpr const _CharT* _On_format_specs(const size_t _Id, const _CharT* _First, const _CharT*) { + _Parse_context.advance_to(_Parse_context.begin() + (_First - _Parse_context.begin()._Unwrapped())); + if (_Id < _Num_args) { + auto _Iter = _Parse_funcs[_Id](_Parse_context); // TRANSITION, VSO-1451773 (workaround: named variable) + return _Iter._Unwrapped(); + } else { + return _First; } + } +}; - template - _OutputIt operator()(_Ty _Val) { - _STL_INTERNAL_CHECK(_Specs); - _STL_INTERNAL_CHECK(_Ctx); - return _Fmt_write(_Ctx->out(), _Val, *_Specs, _Ctx->_Get_lazy_locale()); - } - }; +// The top level set of parsing "actions". +template +struct _Format_handler { + using _OutputIt = back_insert_iterator<_Fmt_buffer<_CharT>>; + using _Context = basic_format_context<_OutputIt, _CharT>; - // Special compile time version of _Parse_format_specs. This version is parameterized on - // the type of the argument associated with the format specifier, since we don't really - // care about avoiding code bloat for code that never runs at runtime, and we can't form - // the erased basic_format_args structure at compile time. - template - consteval typename _ParseContext::iterator _Compile_time_parse_format_specs(_ParseContext& _Pc) { - using _CharT = typename _ParseContext::char_type; - using _Context = basic_format_context>, _CharT>; - using _ArgTraits = _Format_arg_traits<_Context>; - using _FormattedTypeMapping = typename _ArgTraits::template _Storage_type<_Ty>; - // If the type is going to use a custom formatter we should just use that, - // instead of trying to instantiate a custom formatter for its erased handle - // type - using _FormattedType = - conditional_t::handle>, _Ty, - _FormattedTypeMapping>; - formatter<_FormattedType, _CharT> _Formatter{}; - return _Formatter.parse(_Pc); - } - - // set of format parsing actions that only checks for validity - template - struct _Format_checker { - using _ParseContext = basic_format_parse_context<_CharT>; - using _ParseFunc = typename _ParseContext::iterator (*)(_ParseContext&); - - static constexpr size_t _Num_args = sizeof...(_Args); - _ParseContext _Parse_context; - _ParseFunc _Parse_funcs[_Num_args > 0 ? _Num_args : 1]; - - consteval explicit _Format_checker(basic_string_view<_CharT> _Fmt) noexcept - : _Parse_context(_Fmt, _Num_args), - _Parse_funcs{&_Compile_time_parse_format_specs<_Args, _ParseContext>...} {} - constexpr void _On_text(const _CharT*, const _CharT*) const noexcept {} - constexpr void _On_replacement_field(size_t, const _CharT*) const noexcept {} - constexpr const _CharT* _On_format_specs(const size_t _Id, const _CharT* _First, const _CharT*) { - _Parse_context.advance_to(_Parse_context.begin() + (_First - _Parse_context.begin()._Unwrapped())); - if (_Id < _Num_args) { - auto _Iter = _Parse_funcs[_Id](_Parse_context); // TRANSITION, VSO-1451773 (workaround: named variable) - return _Iter._Unwrapped(); - } else { - return _First; - } - } - }; + basic_format_parse_context<_CharT> _Parse_context; + _Context _Ctx; - // The top level set of parsing "actions". - template - struct _Format_handler { - using _OutputIt = back_insert_iterator<_Fmt_buffer<_CharT>>; - using _Context = basic_format_context<_OutputIt, _CharT>; + explicit _Format_handler(_OutputIt _Out, basic_string_view<_CharT> _Str, basic_format_args<_Context> _Format_args) + : _Parse_context(_Str), _Ctx(_STD move(_Out), _Format_args) {} - basic_format_parse_context<_CharT> _Parse_context; - _Context _Ctx; + explicit _Format_handler(_OutputIt _Out, basic_string_view<_CharT> _Str, basic_format_args<_Context> _Format_args, + const _Lazy_locale& _Loc) + : _Parse_context(_Str), _Ctx(_STD move(_Out), _Format_args, _Loc) {} - explicit _Format_handler( - _OutputIt _Out, basic_string_view<_CharT> _Str, basic_format_args<_Context> _Format_args) - : _Parse_context(_Str), _Ctx(_STD move(_Out), _Format_args) {} + void _On_text(const _CharT* _First, const _CharT* _Last) { + _Ctx.advance_to(_RANGES _Copy_unchecked(_First, _Last, _Ctx.out()).out); + } - explicit _Format_handler(_OutputIt _Out, basic_string_view<_CharT> _Str, - basic_format_args<_Context> _Format_args, const _Lazy_locale& _Loc) - : _Parse_context(_Str), _Ctx(_STD move(_Out), _Format_args, _Loc) {} + void _On_replacement_field(const size_t _Id, const _CharT*) { + auto _Arg = _Get_arg(_Ctx, _Id); + _Ctx.advance_to(_STD visit_format_arg( + _Default_arg_formatter<_OutputIt, _CharT>{_Ctx.out(), _Ctx._Get_args(), _Ctx._Get_lazy_locale()}, _Arg)); + } - void _On_text(const _CharT* _First, const _CharT* _Last) { - _Ctx.advance_to(_RANGES _Copy_unchecked(_First, _Last, _Ctx.out()).out); + const _CharT* _On_format_specs(const size_t _Id, const _CharT* _First, const _CharT* _Last) { + _Parse_context.advance_to(_Parse_context.begin() + (_First - &*_Parse_context.begin())); + auto _Arg = _Get_arg(_Ctx, _Id); + if (_Arg._Active_state == _Basic_format_arg_type::_Custom_type) { + _Arg._Custom_state.format(_Parse_context, _Ctx); + return _Parse_context.begin()._Unwrapped(); } - void _On_replacement_field(const size_t _Id, const _CharT*) { - auto _Arg = _Get_arg(_Ctx, _Id); - _Ctx.advance_to(_STD visit_format_arg( - _Default_arg_formatter<_OutputIt, _CharT>{_Ctx.out(), _Ctx._Get_args(), _Ctx._Get_lazy_locale()}, - _Arg)); + _Basic_format_specs<_CharT> _Specs; + _Specs_checker<_Specs_handler, _Context>> _Handler( + _Specs_handler, _Context>{_Specs, _Parse_context, _Ctx}, + _Arg._Active_state); + _First = _Parse_format_specs(_First, _Last, _Handler); + if (_First == _Last || *_First != '}') { + _Throw_format_error("Missing '}' in format string."); } - const _CharT* _On_format_specs(const size_t _Id, const _CharT* _First, const _CharT* _Last) { - _Parse_context.advance_to(_Parse_context.begin() + (_First - &*_Parse_context.begin())); - auto _Arg = _Get_arg(_Ctx, _Id); - if (_Arg._Active_state == _Basic_format_arg_type::_Custom_type) { - _Arg._Custom_state.format(_Parse_context, _Ctx); - return _Parse_context.begin()._Unwrapped(); - } - - _Basic_format_specs<_CharT> _Specs; - _Specs_checker<_Specs_handler, _Context>> _Handler( - _Specs_handler, _Context>{_Specs, _Parse_context, _Ctx}, - _Arg._Active_state); - _First = _Parse_format_specs(_First, _Last, _Handler); - if (_First == _Last || *_First != '}') { - _Throw_format_error("Missing '}' in format string."); - } - - _Ctx.advance_to(_STD visit_format_arg( - _Arg_formatter<_OutputIt, _CharT>{._Ctx = _STD addressof(_Ctx), ._Specs = _STD addressof(_Specs)}, - _Arg)); - return _First; - } - }; -#if _HAS_CXX23 -} // inline namespace __p2286 -#endif // _HAS_CXX23 + _Ctx.advance_to(_STD visit_format_arg( + _Arg_formatter<_OutputIt, _CharT>{._Ctx = _STD addressof(_Ctx), ._Specs = _STD addressof(_Specs)}, _Arg)); + return _First; + } +}; +_FMT_P2286_END // Generic formatter definition, the deleted default constructor // makes it "disabled" as per N4950 [format.formatter.spec]/5 @@ -3523,48 +3521,43 @@ struct formatter { formatter operator=(const formatter&) = delete; }; -#if _HAS_CXX23 -inline namespace __p2286 { -#endif // _HAS_CXX23 - template - struct _Formatter_base { - using _Pc = basic_format_parse_context<_CharT>; - - constexpr typename _Pc::iterator parse(_Pc& _ParseCtx) { - _Specs_checker<_Dynamic_specs_handler<_Pc>> _Handler( - _Dynamic_specs_handler<_Pc>{_Specs, _ParseCtx}, _ArgType); - const auto _It = _Parse_format_specs(_ParseCtx._Unchecked_begin(), _ParseCtx._Unchecked_end(), _Handler); - if (_It != _ParseCtx._Unchecked_end() && *_It != '}') { - _Throw_format_error("Missing '}' in format string."); - } - return _ParseCtx.begin() + (_It - _ParseCtx._Unchecked_begin()); - } +_FMT_P2286_BEGIN +template +struct _Formatter_base { + using _Pc = basic_format_parse_context<_CharT>; - template - typename _FormatContext::iterator format(const _Ty& _Val, _FormatContext& _FormatCtx) const { - _Dynamic_format_specs<_CharT> _Format_specs = _Specs; - if (_Specs._Dynamic_width_index >= 0) { - _Format_specs._Width = _Get_dynamic_specs<_Width_checker>( - _FormatCtx.arg(static_cast(_Specs._Dynamic_width_index))); - } + constexpr typename _Pc::iterator parse(_Pc& _ParseCtx) { + _Specs_checker<_Dynamic_specs_handler<_Pc>> _Handler(_Dynamic_specs_handler<_Pc>{_Specs, _ParseCtx}, _ArgType); + const auto _It = _Parse_format_specs(_ParseCtx._Unchecked_begin(), _ParseCtx._Unchecked_end(), _Handler); + if (_It != _ParseCtx._Unchecked_end() && *_It != '}') { + _Throw_format_error("Missing '}' in format string."); + } + return _ParseCtx.begin() + (_It - _ParseCtx._Unchecked_begin()); + } - if (_Specs._Dynamic_precision_index >= 0) { - _Format_specs._Precision = _Get_dynamic_specs<_Precision_checker>( - _FormatCtx.arg(static_cast(_Specs._Dynamic_precision_index))); - } + template + typename _FormatContext::iterator format(const _Ty& _Val, _FormatContext& _FormatCtx) const { + _Dynamic_format_specs<_CharT> _Format_specs = _Specs; + if (_Specs._Dynamic_width_index >= 0) { + _Format_specs._Width = + _Get_dynamic_specs<_Width_checker>(_FormatCtx.arg(static_cast(_Specs._Dynamic_width_index))); + } - return _STD visit_format_arg( - _Arg_formatter{ - ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, - basic_format_arg<_FormatContext>{_Val}); + if (_Specs._Dynamic_precision_index >= 0) { + _Format_specs._Precision = _Get_dynamic_specs<_Precision_checker>( + _FormatCtx.arg(static_cast(_Specs._Dynamic_precision_index))); } - private: - _Dynamic_format_specs<_CharT> _Specs; - }; -#if _HAS_CXX23 -} // inline namespace __p2286 -#endif // _HAS_CXX23 + return _STD visit_format_arg( + _Arg_formatter{ + ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, + basic_format_arg<_FormatContext>{_Val}); + } + +private: + _Dynamic_format_specs<_CharT> _Specs; +}; +_FMT_P2286_END #define _FORMAT_SPECIALIZE_FOR(_Type, _ArgType) \ template <_Format_supported_charT _CharT> \ @@ -3659,147 +3652,143 @@ _NODISCARD auto make_wformat_args(_Args&&... _Vals) { return _Format_arg_store{_Vals...}; } -#if _HAS_CXX23 -inline namespace __p2286 { -#endif // _HAS_CXX23 - _EXPORT_STD template _OutputIt> - _OutputIt vformat_to(_OutputIt _Out, const string_view _Fmt, const format_args _Args) { - // Make `_Parse_format_string` type-dependent to defer instantiation: - using _Dependent_char = decltype((void) _Out, char{}); - if constexpr (is_same_v<_OutputIt, _Fmt_it>) { - _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args); - _Parse_format_string(_Fmt, _Handler); - return _Out; - } else { - _Fmt_iterator_buffer<_OutputIt, char> _Buf(_STD move(_Out)); - _Format_handler<_Dependent_char> _Handler(_Fmt_it{_Buf}, _Fmt, _Args); - _Parse_format_string(_Fmt, _Handler); - return _Buf._Out(); - } +_FMT_P2286_BEGIN +_EXPORT_STD template _OutputIt> +_OutputIt vformat_to(_OutputIt _Out, const string_view _Fmt, const format_args _Args) { + // Make `_Parse_format_string` type-dependent to defer instantiation: + using _Dependent_char = decltype((void) _Out, char{}); + if constexpr (is_same_v<_OutputIt, _Fmt_it>) { + _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args); + _Parse_format_string(_Fmt, _Handler); + return _Out; + } else { + _Fmt_iterator_buffer<_OutputIt, char> _Buf(_STD move(_Out)); + _Format_handler<_Dependent_char> _Handler(_Fmt_it{_Buf}, _Fmt, _Args); + _Parse_format_string(_Fmt, _Handler); + return _Buf._Out(); } +} - _EXPORT_STD template _OutputIt> - _OutputIt vformat_to(_OutputIt _Out, const wstring_view _Fmt, const wformat_args _Args) { - // Make `_Parse_format_string` type-dependent to defer instantiation: - using _Dependent_char = decltype((void) _Out, wchar_t{}); - if constexpr (is_same_v<_OutputIt, _Fmt_wit>) { - _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args); - _Parse_format_string(_Fmt, _Handler); - return _Out; - } else { - _Fmt_iterator_buffer<_OutputIt, wchar_t> _Buf(_STD move(_Out)); - _Format_handler<_Dependent_char> _Handler(_Fmt_wit{_Buf}, _Fmt, _Args); - _Parse_format_string(_Fmt, _Handler); - return _Buf._Out(); - } +_EXPORT_STD template _OutputIt> +_OutputIt vformat_to(_OutputIt _Out, const wstring_view _Fmt, const wformat_args _Args) { + // Make `_Parse_format_string` type-dependent to defer instantiation: + using _Dependent_char = decltype((void) _Out, wchar_t{}); + if constexpr (is_same_v<_OutputIt, _Fmt_wit>) { + _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args); + _Parse_format_string(_Fmt, _Handler); + return _Out; + } else { + _Fmt_iterator_buffer<_OutputIt, wchar_t> _Buf(_STD move(_Out)); + _Format_handler<_Dependent_char> _Handler(_Fmt_wit{_Buf}, _Fmt, _Args); + _Parse_format_string(_Fmt, _Handler); + return _Buf._Out(); } +} - _EXPORT_STD template _OutputIt> - _OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const string_view _Fmt, const format_args _Args) { - // Make `_Parse_format_string` type-dependent to defer instantiation: - using _Dependent_char = decltype((void) _Out, char{}); - if constexpr (is_same_v<_OutputIt, _Fmt_it>) { - _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args, _Lazy_locale{_Loc}); - _Parse_format_string(_Fmt, _Handler); - return _Out; - } else { - _Fmt_iterator_buffer<_OutputIt, char> _Buf(_STD move(_Out)); - _Format_handler<_Dependent_char> _Handler(_Fmt_it{_Buf}, _Fmt, _Args, _Lazy_locale{_Loc}); - _Parse_format_string(_Fmt, _Handler); - return _Buf._Out(); - } +_EXPORT_STD template _OutputIt> +_OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const string_view _Fmt, const format_args _Args) { + // Make `_Parse_format_string` type-dependent to defer instantiation: + using _Dependent_char = decltype((void) _Out, char{}); + if constexpr (is_same_v<_OutputIt, _Fmt_it>) { + _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args, _Lazy_locale{_Loc}); + _Parse_format_string(_Fmt, _Handler); + return _Out; + } else { + _Fmt_iterator_buffer<_OutputIt, char> _Buf(_STD move(_Out)); + _Format_handler<_Dependent_char> _Handler(_Fmt_it{_Buf}, _Fmt, _Args, _Lazy_locale{_Loc}); + _Parse_format_string(_Fmt, _Handler); + return _Buf._Out(); } +} - _EXPORT_STD template _OutputIt> - _OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const wstring_view _Fmt, const wformat_args _Args) { - // Make `_Parse_format_string` type-dependent to defer instantiation: - using _Dependent_char = decltype((void) _Out, wchar_t{}); - if constexpr (is_same_v<_OutputIt, _Fmt_wit>) { - _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args, _Lazy_locale{_Loc}); - _Parse_format_string(_Fmt, _Handler); - return _Out; - } else { - _Fmt_iterator_buffer<_OutputIt, wchar_t> _Buf(_STD move(_Out)); - _Format_handler<_Dependent_char> _Handler(_Fmt_wit{_Buf}, _Fmt, _Args, _Lazy_locale{_Loc}); - _Parse_format_string(_Fmt, _Handler); - return _Buf._Out(); - } +_EXPORT_STD template _OutputIt> +_OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const wstring_view _Fmt, const wformat_args _Args) { + // Make `_Parse_format_string` type-dependent to defer instantiation: + using _Dependent_char = decltype((void) _Out, wchar_t{}); + if constexpr (is_same_v<_OutputIt, _Fmt_wit>) { + _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args, _Lazy_locale{_Loc}); + _Parse_format_string(_Fmt, _Handler); + return _Out; + } else { + _Fmt_iterator_buffer<_OutputIt, wchar_t> _Buf(_STD move(_Out)); + _Format_handler<_Dependent_char> _Handler(_Fmt_wit{_Buf}, _Fmt, _Args, _Lazy_locale{_Loc}); + _Parse_format_string(_Fmt, _Handler); + return _Buf._Out(); } +} - _EXPORT_STD template _OutputIt, class... _Types> - _OutputIt format_to(_OutputIt _Out, const format_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat_to(_STD move(_Out), _Fmt.get(), _STD make_format_args(_Args...)); - } +_EXPORT_STD template _OutputIt, class... _Types> +_OutputIt format_to(_OutputIt _Out, const format_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat_to(_STD move(_Out), _Fmt.get(), _STD make_format_args(_Args...)); +} - _EXPORT_STD template _OutputIt, class... _Types> - _OutputIt format_to(_OutputIt _Out, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat_to(_STD move(_Out), _Fmt.get(), _STD make_wformat_args(_Args...)); - } +_EXPORT_STD template _OutputIt, class... _Types> +_OutputIt format_to(_OutputIt _Out, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat_to(_STD move(_Out), _Fmt.get(), _STD make_wformat_args(_Args...)); +} - _EXPORT_STD template _OutputIt, class... _Types> - _OutputIt format_to(_OutputIt _Out, const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat_to(_STD move(_Out), _Loc, _Fmt.get(), _STD make_format_args(_Args...)); - } +_EXPORT_STD template _OutputIt, class... _Types> +_OutputIt format_to(_OutputIt _Out, const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat_to(_STD move(_Out), _Loc, _Fmt.get(), _STD make_format_args(_Args...)); +} - _EXPORT_STD template _OutputIt, class... _Types> - _OutputIt format_to(_OutputIt _Out, const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat_to(_STD move(_Out), _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); - } +_EXPORT_STD template _OutputIt, class... _Types> +_OutputIt format_to(_OutputIt _Out, const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat_to(_STD move(_Out), _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); +} - _EXPORT_STD template // improves throughput, see GH-2329 - _NODISCARD string vformat(const string_view _Fmt, const format_args _Args) { - string _Str; - _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); - _STD vformat_to(back_insert_iterator{_Str}, _Fmt, _Args); - return _Str; - } +_EXPORT_STD template // improves throughput, see GH-2329 +_NODISCARD string vformat(const string_view _Fmt, const format_args _Args) { + string _Str; + _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); + _STD vformat_to(back_insert_iterator{_Str}, _Fmt, _Args); + return _Str; +} - _EXPORT_STD template // improves throughput, see GH-2329 - _NODISCARD wstring vformat(const wstring_view _Fmt, const wformat_args _Args) { - wstring _Str; - _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); - _STD vformat_to(back_insert_iterator{_Str}, _Fmt, _Args); - return _Str; - } +_EXPORT_STD template // improves throughput, see GH-2329 +_NODISCARD wstring vformat(const wstring_view _Fmt, const wformat_args _Args) { + wstring _Str; + _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); + _STD vformat_to(back_insert_iterator{_Str}, _Fmt, _Args); + return _Str; +} - _EXPORT_STD template // improves throughput, see GH-2329 - _NODISCARD string vformat(const locale& _Loc, const string_view _Fmt, const format_args _Args) { - string _Str; - _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); - _STD vformat_to(back_insert_iterator{_Str}, _Loc, _Fmt, _Args); - return _Str; - } +_EXPORT_STD template // improves throughput, see GH-2329 +_NODISCARD string vformat(const locale& _Loc, const string_view _Fmt, const format_args _Args) { + string _Str; + _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); + _STD vformat_to(back_insert_iterator{_Str}, _Loc, _Fmt, _Args); + return _Str; +} - _EXPORT_STD template // improves throughput, see GH-2329 - _NODISCARD wstring vformat(const locale& _Loc, const wstring_view _Fmt, const wformat_args _Args) { - wstring _Str; - _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); - _STD vformat_to(back_insert_iterator{_Str}, _Loc, _Fmt, _Args); - return _Str; - } +_EXPORT_STD template // improves throughput, see GH-2329 +_NODISCARD wstring vformat(const locale& _Loc, const wstring_view _Fmt, const wformat_args _Args) { + wstring _Str; + _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); + _STD vformat_to(back_insert_iterator{_Str}, _Loc, _Fmt, _Args); + return _Str; +} - _EXPORT_STD template - _NODISCARD string format(const format_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat(_Fmt.get(), _STD make_format_args(_Args...)); - } +_EXPORT_STD template +_NODISCARD string format(const format_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat(_Fmt.get(), _STD make_format_args(_Args...)); +} - _EXPORT_STD template - _NODISCARD wstring format(const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat(_Fmt.get(), _STD make_wformat_args(_Args...)); - } +_EXPORT_STD template +_NODISCARD wstring format(const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat(_Fmt.get(), _STD make_wformat_args(_Args...)); +} - _EXPORT_STD template - _NODISCARD string format(const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat(_Loc, _Fmt.get(), _STD make_format_args(_Args...)); - } +_EXPORT_STD template +_NODISCARD string format(const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat(_Loc, _Fmt.get(), _STD make_format_args(_Args...)); +} - _EXPORT_STD template - _NODISCARD wstring format(const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat(_Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); - } -#if _HAS_CXX23 -} // inline namespace __p2286 -#endif // _HAS_CXX23 +_EXPORT_STD template +_NODISCARD wstring format(const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat(_Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); +} +_FMT_P2286_END _EXPORT_STD template struct format_to_n_result { @@ -3807,72 +3796,69 @@ struct format_to_n_result { iter_difference_t<_OutputIt> size; }; -#if _HAS_CXX23 -inline namespace __p2286 { -#endif // _HAS_CXX23 - _EXPORT_STD template _OutputIt, class... _Types> - format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, - const format_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); - _STD vformat_to(_Fmt_it{_Buf}, _Fmt.get(), _STD make_format_args(_Args...)); - return {.out = _Buf._Out(), .size = _Buf._Count()}; - } +_FMT_P2286_BEGIN +_EXPORT_STD template _OutputIt, class... _Types> +format_to_n_result<_OutputIt> format_to_n( + _OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const format_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); + _STD vformat_to(_Fmt_it{_Buf}, _Fmt.get(), _STD make_format_args(_Args...)); + return {.out = _Buf._Out(), .size = _Buf._Count()}; +} - _EXPORT_STD template _OutputIt, class... _Types> - format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, - const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); - _STD vformat_to(_Fmt_wit{_Buf}, _Fmt.get(), _STD make_wformat_args(_Args...)); - return {.out = _Buf._Out(), .size = _Buf._Count()}; - } +_EXPORT_STD template _OutputIt, class... _Types> +format_to_n_result<_OutputIt> format_to_n( + _OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); + _STD vformat_to(_Fmt_wit{_Buf}, _Fmt.get(), _STD make_wformat_args(_Args...)); + return {.out = _Buf._Out(), .size = _Buf._Count()}; +} - _EXPORT_STD template _OutputIt, class... _Types> - format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, - const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); - _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt.get(), _STD make_format_args(_Args...)); - return {.out = _Buf._Out(), .size = _Buf._Count()}; - } +_EXPORT_STD template _OutputIt, class... _Types> +format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const locale& _Loc, + const format_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); + _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt.get(), _STD make_format_args(_Args...)); + return {.out = _Buf._Out(), .size = _Buf._Count()}; +} - _EXPORT_STD template _OutputIt, class... _Types> - format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, - const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); - _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); - return {.out = _Buf._Out(), .size = _Buf._Count()}; - } +_EXPORT_STD template _OutputIt, class... _Types> +format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const locale& _Loc, + const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); + _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); + return {.out = _Buf._Out(), .size = _Buf._Count()}; +} - _EXPORT_STD template - _NODISCARD size_t formatted_size(const format_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_counting_buffer _Buf; - _STD vformat_to(_Fmt_it{_Buf}, _Fmt.get(), _STD make_format_args(_Args...)); - return _Buf._Count(); - } +_EXPORT_STD template +_NODISCARD size_t formatted_size(const format_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_counting_buffer _Buf; + _STD vformat_to(_Fmt_it{_Buf}, _Fmt.get(), _STD make_format_args(_Args...)); + return _Buf._Count(); +} - _EXPORT_STD template - _NODISCARD size_t formatted_size(const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_counting_buffer _Buf; - _STD vformat_to(_Fmt_wit{_Buf}, _Fmt.get(), _STD make_wformat_args(_Args...)); - return _Buf._Count(); - } +_EXPORT_STD template +_NODISCARD size_t formatted_size(const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_counting_buffer _Buf; + _STD vformat_to(_Fmt_wit{_Buf}, _Fmt.get(), _STD make_wformat_args(_Args...)); + return _Buf._Count(); +} - _EXPORT_STD template - _NODISCARD size_t formatted_size(const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_counting_buffer _Buf; - _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt.get(), _STD make_format_args(_Args...)); - return _Buf._Count(); - } +_EXPORT_STD template +_NODISCARD size_t formatted_size(const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_counting_buffer _Buf; + _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt.get(), _STD make_format_args(_Args...)); + return _Buf._Count(); +} - _EXPORT_STD template - _NODISCARD size_t formatted_size(const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_counting_buffer _Buf; - _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); - return _Buf._Count(); - } +_EXPORT_STD template +_NODISCARD size_t formatted_size(const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_counting_buffer _Buf; + _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); + return _Buf._Count(); +} +_FMT_P2286_END #if _HAS_CXX23 -} // inline namespace __p2286 - enum class _Add_newline : bool { _Nope, _Yes }; _NODISCARD inline string _Unescape_braces(const _Add_newline _Add_nl, const string_view _Old_str) { @@ -3920,6 +3906,9 @@ _NODISCARD inline string _Unescape_braces(const _Add_newline _Add_nl, const stri } #endif // _HAS_CXX23 +#undef _FMT_P2286_END +#undef _FMT_P2286_BEGIN + _STD_END #pragma pop_macro("new") From 6a9845652ae9692d33fba07a4c431a082f7c2399 Mon Sep 17 00:00:00 2001 From: "S. B. Tam" Date: Wed, 31 May 2023 10:08:22 +0800 Subject: [PATCH 10/11] ``: Make `formatter` cast the argument to the correct type before constructing `basic_format_arg` (#3723) Co-authored-by: Stephan T. Lavavej --- stl/inc/format | 21 +++++++----- .../test.cpp | 32 ++++++++++++++++++- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index b6c788828f1..438300f2d79 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -695,10 +695,6 @@ public: : _Active_state(_Basic_format_arg_type::_Int_type), _Int_state(_Val) {} explicit basic_format_arg(const unsigned int _Val) noexcept : _Active_state(_Basic_format_arg_type::_UInt_type), _UInt_state(_Val) {} - explicit basic_format_arg(const long _Val) noexcept - : _Active_state(_Basic_format_arg_type::_Int_type), _Int_state(_Val) {} - explicit basic_format_arg(const unsigned long _Val) noexcept - : _Active_state(_Basic_format_arg_type::_UInt_type), _UInt_state(_Val) {} explicit basic_format_arg(const long long _Val) noexcept : _Active_state(_Basic_format_arg_type::_Long_long_type), _Long_long_state(_Val) {} explicit basic_format_arg(const unsigned long long _Val) noexcept @@ -3548,10 +3544,19 @@ struct _Formatter_base { _FormatCtx.arg(static_cast(_Specs._Dynamic_precision_index))); } - return _STD visit_format_arg( - _Arg_formatter{ - ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, - basic_format_arg<_FormatContext>{_Val}); + using _Erased_type = _Format_arg_traits<_FormatContext>::template _Storage_type<_Ty>; + + _Arg_formatter _Visitor{ + ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}; +#if !_HAS_CXX23 + if constexpr (is_same_v<_Erased_type, basic_string_view<_CharT>>) { + return _STD visit_format_arg( + _Visitor, basic_format_arg<_FormatContext>{_Erased_type{_Val.data(), _Val.size()}}); + } else +#endif // !_HAS_CXX23 + { + return _STD visit_format_arg(_Visitor, basic_format_arg<_FormatContext>{static_cast<_Erased_type>(_Val)}); + } } private: diff --git a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp index e1bf232b065..c285fcdbaf3 100644 --- a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp @@ -96,7 +96,7 @@ struct std::formatter, charT> : std::formatter; static_assert(!is_default_constructible_v); @@ -184,6 +184,21 @@ void test_custom_formattable_type() { test_numeric_custom_formattable_type(); test_numeric_custom_formattable_type(); test_numeric_custom_formattable_type(); + + test_custom_equiv_with_format(STR("{}"), charT(' ')); + test_custom_equiv_with_format(STR("{}"), ' '); + + charT test_str[] = {charT(' '), charT()}; + test_custom_equiv_with_format(STR("{}"), test_str); + test_custom_equiv_with_format(STR("{}"), test_str); + + struct traits : char_traits {}; + test_custom_equiv_with_format, charT>(STR("{}"), test_str); + test_custom_equiv_with_format, charT>(STR("{}"), test_str); + + test_custom_equiv_with_format(STR("{}"), nullptr); + test_custom_equiv_with_format(STR("{}"), nullptr); + test_custom_equiv_with_format(STR("{}"), nullptr); } template @@ -201,6 +216,21 @@ void test_mixed_custom_formattable_type() { test_numeric_mixed_args_custom_formattable_type(); test_numeric_mixed_args_custom_formattable_type(); test_numeric_mixed_args_custom_formattable_type(); + + test_custom_equiv_with_format_mixed(STR("{}{}"), charT(' ')); + test_custom_equiv_with_format_mixed(STR("{}{}"), ' '); + + charT test_str[] = {charT(' '), charT()}; + test_custom_equiv_with_format_mixed(STR("{}{}"), test_str); + test_custom_equiv_with_format_mixed(STR("{}{}"), test_str); + + struct traits : char_traits {}; + test_custom_equiv_with_format_mixed, charT>(STR("{}{}"), test_str); + test_custom_equiv_with_format_mixed, charT>(STR("{}{}"), test_str); + + test_custom_equiv_with_format_mixed(STR("{}{}"), nullptr); + test_custom_equiv_with_format_mixed(STR("{}{}"), nullptr); + test_custom_equiv_with_format_mixed(STR("{}{}"), nullptr); } int main() { From c8d1efb6d504f6392acf8f6d01fd703f7c8826c0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 31 May 2023 16:38:11 -0700 Subject: [PATCH 11/11] Silence 3 static analysis warnings (#3743) Co-authored-by: Casey Carter --- stl/inc/charconv | 3 +++ stl/inc/memory_resource | 3 +++ stl/inc/xlocale | 11 +++++++++++ 3 files changed, 17 insertions(+) diff --git a/stl/inc/charconv b/stl/inc/charconv index 2614acb2ee8..428567c1317 100644 --- a/stl/inc/charconv +++ b/stl/inc/charconv @@ -253,7 +253,10 @@ _NODISCARD _CONSTEXPR23 from_chars_result _Integer_from_chars( constexpr _Unsigned _Uint_max = static_cast<_Unsigned>(-1); constexpr _Unsigned _Int_max = static_cast<_Unsigned>(_Uint_max >> 1); +#pragma warning(push) +#pragma warning(disable : 26450) // TRANSITION, VSO-1828677 constexpr _Unsigned _Abs_int_min = static_cast<_Unsigned>(_Int_max + 1); +#pragma warning(pop) _Unsigned _Risky_val; _Unsigned _Max_digit; diff --git a/stl/inc/memory_resource b/stl/inc/memory_resource index 9d996bdb859..eee7f03236b 100644 --- a/stl/inc/memory_resource +++ b/stl/inc/memory_resource @@ -704,7 +704,10 @@ namespace pmr { static constexpr size_t _Scale(const size_t _Size) noexcept { // scale _Size by 1.5, rounding up to a multiple of alignof(_Header), saturating to _Max_allocation // (keep synchronized with monotonic_buffer_resource::release) +#pragma warning(push) +#pragma warning(disable : 26450) // TRANSITION, VSO-1828677 constexpr auto _Max_size = (_Max_allocation - alignof(_Header) + 1) / 3 * 2; +#pragma warning(pop) if (_Size >= _Max_size) { return _Max_allocation; } diff --git a/stl/inc/xlocale b/stl/inc/xlocale index 9a1c54b228b..5a70bb2cb44 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -257,7 +257,18 @@ public: } } +#pragma warning(push) +#pragma warning(disable : 26495) // Variable 'std::locale::_Ptr' is uninitialized. + // Always initialize a member variable (type.6). + + // We must not explicitly initialize _Ptr here; we rely on it maintaining the value + // previously created in its storage. To be precise: + // In locale0.cpp, locale::_Init() uses True Placement New at classic_locale's address, + // and classic_locale is constructed from the _Noinit enumerator of type _Uninitialized. + // The sequencing is highly unusual; the True Placement New happens before the _Uninitialized construction, + // so while _Ptr here formally has indeterminate value, we expect it to actually keep the previous value. locale(_Uninitialized) {} // defer construction +#pragma warning(pop) locale(const locale& _Right) noexcept : _Ptr(_Right._Ptr) { _Ptr->_Incref();