From 645cac9cad15a32c530c2eb6197c91c0a7a84477 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 8 Nov 2024 09:03:59 -0800 Subject: [PATCH 01/16] Refactor `_Copy_memmove` and `_Copy_memmove_n` (#5046) Co-authored-by: Stephan T. Lavavej --- stl/inc/algorithm | 32 +++--- stl/inc/xutility | 67 ++++++----- .../tests/GH_000431_copy_move_family/test.cpp | 108 ++++++++++++++++++ 3 files changed, 162 insertions(+), 45 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 1b66037563..23d74b52f6 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1557,24 +1557,26 @@ namespace ranges { requires indirectly_copyable<_It, _Out> _STATIC_CALL_OPERATOR constexpr copy_n_result<_It, _Out> operator()( _It _First, iter_difference_t<_It> _Count, _Out _Output) _CONST_CALL_OPERATOR { - auto _UFirst = _STD _Get_unwrapped_n(_STD move(_First), _Count); - auto _UOutput = _STD _Get_unwrapped_n(_STD move(_Output), _Count); - if constexpr (_Iter_copy_cat::_Bitcopy_assignable) { - if (!_STD is_constant_evaluated()) { - _UOutput = _STD _Copy_memmove_n(_UFirst, static_cast(_Count), _STD move(_UOutput)); - _UFirst += _Count; - _STD _Seek_wrapped(_First, _STD move(_UFirst)); - _STD _Seek_wrapped(_Output, _STD move(_UOutput)); - return {_STD move(_First), _STD move(_Output)}; + if (_Count > 0) { + auto _UFirst = _STD _Get_unwrapped_n(_STD move(_First), _Count); + auto _UOutput = _STD _Get_unwrapped_n(_STD move(_Output), _Count); + if constexpr (_Iter_copy_cat::_Bitcopy_assignable) { + if (!_STD is_constant_evaluated()) { + _UOutput = _STD _Copy_memmove_n(_UFirst, static_cast(_Count), _STD move(_UOutput)); + _UFirst += _Count; + _STD _Seek_wrapped(_First, _STD move(_UFirst)); + _STD _Seek_wrapped(_Output, _STD move(_UOutput)); + return {_STD move(_First), _STD move(_Output)}; + } } - } - for (; _Count > 0; ++_UFirst, (void) ++_UOutput, --_Count) { - *_UOutput = *_UFirst; - } + for (; _Count > 0; ++_UFirst, (void) ++_UOutput, --_Count) { + *_UOutput = *_UFirst; + } - _STD _Seek_wrapped(_First, _STD move(_UFirst)); - _STD _Seek_wrapped(_Output, _STD move(_UOutput)); + _STD _Seek_wrapped(_First, _STD move(_UFirst)); + _STD _Seek_wrapped(_Output, _STD move(_UOutput)); + } return {_STD move(_First), _STD move(_Output)}; } }; diff --git a/stl/inc/xutility b/stl/inc/xutility index e67be17a51..f9793535d6 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4708,32 +4708,40 @@ _CONSTEXPR20 void _Verify_ranges_do_not_overlap(const _Iter1& _First1, const _Se #endif // _ITERATOR_DEBUG_LEVEL != 2 ^^^ } -template -_OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { - auto _FirstPtr = _STD _To_address(_First); - auto _LastPtr = _STD _To_address(_Last); - auto _DestPtr = _STD _To_address(_Dest); - const char* const _First_ch = const_cast(reinterpret_cast(_FirstPtr)); - const char* const _Last_ch = const_cast(reinterpret_cast(_LastPtr)); - char* const _Dest_ch = const_cast(reinterpret_cast(_DestPtr)); - const auto _Count = static_cast(_Last_ch - _First_ch); - _CSTD memmove(_Dest_ch, _First_ch, _Count); +template +_OutCtgIt _Copy_memmove_tail( + const char* const _First_ch, const _OutCtgIt _Dest, const size_t _Byte_count, const size_t _Object_count) { + _STL_INTERNAL_CHECK(_Byte_count == _Object_count * sizeof(*_Dest)); + const auto _Dest_ptr = _STD _To_address(_Dest); + const auto _Dest_ch = const_cast(reinterpret_cast(_Dest_ptr)); + _CSTD memmove(_Dest_ch, _First_ch, _Byte_count); if constexpr (is_pointer_v<_OutCtgIt>) { + (void) _Object_count; // CodeQL [SM02986] This cast is correct: we're bypassing pointer arithmetic for performance. - return reinterpret_cast<_OutCtgIt>(_Dest_ch + _Count); + return reinterpret_cast<_OutCtgIt>(_Dest_ch + _Byte_count); } else { - return _Dest + static_cast<_Iter_diff_t<_OutCtgIt>>(_LastPtr - _FirstPtr); + return _Dest + static_cast<_Iter_diff_t<_OutCtgIt>>(_Object_count); } } template -_OutCtgIt _Copy_memmove_n(_CtgIt _First, const size_t _Count, _OutCtgIt _Dest) { - const auto _Result = _STD _Copy_memmove(_First, _First + _Count, _Dest); - if constexpr (is_pointer_v<_OutCtgIt>) { - return _Result; - } else { // _Result is unused so the compiler can optimize it away - return _Dest + static_cast<_Iter_diff_t<_OutCtgIt>>(_Count); - } +_OutCtgIt _Copy_memmove(_CtgIt _First, _CtgIt _Last, _OutCtgIt _Dest) { + _STL_INTERNAL_CHECK(_First <= _Last); + const auto _First_ptr = _STD _To_address(_First); + const auto _Last_ptr = _STD _To_address(_Last); + const auto _Object_count = static_cast(_Last_ptr - _First_ptr); + const auto _First_ch = const_cast(reinterpret_cast(_First_ptr)); + const auto _Last_ch = const_cast(reinterpret_cast(_Last_ptr)); + const auto _Byte_count = static_cast(_Last_ch - _First_ch); + return _STD _Copy_memmove_tail(_First_ch, _STD move(_Dest), _Byte_count, _Object_count); +} + +template +_OutCtgIt _Copy_memmove_n(_CtgIt _First, const size_t _Object_count, _OutCtgIt _Dest) { + const auto _First_ptr = _STD _To_address(_First); + const auto _First_ch = const_cast(reinterpret_cast(_First_ptr)); + const auto _Byte_count = _Object_count * sizeof(*_First_ptr); + return _STD _Copy_memmove_tail(_First_ch, _STD move(_Dest), _Byte_count, _Object_count); } template @@ -4755,9 +4763,8 @@ template _CONSTEXPR20 _OutIt _Copy_n_unchecked4(_InIt _First, _SizeTy _Count, _OutIt _Dest) { // copy _First + [0, _Count) to _Dest + [0, _Count), returning _Dest + _Count // note: has callers outside the copy family -#if _HAS_CXX20 _STL_INTERNAL_STATIC_ASSERT(_Integer_like<_SizeTy>); -#endif // _HAS_CXX20 + _STL_INTERNAL_CHECK(_Count >= 0); if constexpr (_Iter_copy_cat<_InIt, _OutIt>::_Bitcopy_assignable) { #if _HAS_CXX20 @@ -5041,18 +5048,18 @@ _FwdIt2 copy_n(_ExPo&&, _FwdIt1 _First, _Diff _Count_raw, _FwdIt2 _Dest) noexcep template _CtgIt2 _Copy_backward_memmove(_CtgIt1 _First, _CtgIt1 _Last, _CtgIt2 _Dest) { // implement copy_backward-like function as memmove - auto _FirstPtr = _STD _To_address(_First); - auto _LastPtr = _STD _To_address(_Last); - auto _DestPtr = _STD _To_address(_Dest); - const char* const _First_ch = const_cast(reinterpret_cast(_FirstPtr)); - const char* const _Last_ch = const_cast(reinterpret_cast(_LastPtr)); - char* const _Dest_ch = const_cast(reinterpret_cast(_DestPtr)); - const auto _Count = static_cast(_Last_ch - _First_ch); - auto _Result = _CSTD memmove(_Dest_ch - _Count, _First_ch, _Count); + const auto _First_ptr = _STD _To_address(_First); + const auto _Last_ptr = _STD _To_address(_Last); + const auto _Dest_ptr = _STD _To_address(_Dest); + const auto _First_ch = const_cast(reinterpret_cast(_First_ptr)); + const auto _Last_ch = const_cast(reinterpret_cast(_Last_ptr)); + const auto _Dest_ch = const_cast(reinterpret_cast(_Dest_ptr)); + const auto _Count = static_cast(_Last_ch - _First_ch); + const auto _Result = _CSTD memmove(_Dest_ch - _Count, _First_ch, _Count); if constexpr (is_pointer_v<_CtgIt2>) { return static_cast<_CtgIt2>(_Result); } else { - return _Dest - static_cast<_Iter_diff_t<_CtgIt2>>(_LastPtr - _FirstPtr); + return _Dest - static_cast<_Iter_diff_t<_CtgIt2>>(_Last_ptr - _First_ptr); } } diff --git a/tests/std/tests/GH_000431_copy_move_family/test.cpp b/tests/std/tests/GH_000431_copy_move_family/test.cpp index fe0b36682a..125792ea6e 100644 --- a/tests/std/tests/GH_000431_copy_move_family/test.cpp +++ b/tests/std/tests/GH_000431_copy_move_family/test.cpp @@ -17,6 +17,7 @@ #endif // _HAS_CXX17 #if _HAS_CXX20 +#include #include #endif // _HAS_CXX20 @@ -641,6 +642,111 @@ void test_algorithms(CopyFn copy_fn) { } } +#if _HAS_CXX20 +template +struct MyIterator { // A contiguous iterator with a weirdly narrow difference type + using iterator_concept = contiguous_iterator_tag; + using value_type = T; + using difference_type = short; + + value_type* ptr = nullptr; + + MyIterator() = default; + explicit MyIterator(value_type* p) : ptr{p} {} + + value_type& operator*() const { + return *ptr; + } + value_type* operator->() const { + return ptr; + } + + MyIterator& operator++() { + ++ptr; + return *this; + } + MyIterator operator++(int) { + auto tmp = *this; + ++ptr; + return tmp; + } + + MyIterator& operator--() { + --ptr; + return *this; + } + MyIterator operator--(int) { + auto tmp = *this; + --ptr; + return tmp; + } + + auto operator<=>(const MyIterator&) const = default; + + value_type& operator[](difference_type n) const { + return ptr[n]; + } + + MyIterator& operator+=(difference_type n) { + ptr += n; + return *this; + } + MyIterator& operator-=(difference_type n) { + ptr -= n; + return *this; + } + difference_type operator-(const MyIterator& that) const { + return ptr - that.ptr; + } + MyIterator operator+(difference_type n) const { + return MyIterator{ptr + n}; + } + MyIterator operator-(difference_type n) const { + return MyIterator{ptr - n}; + } + friend MyIterator operator+(difference_type n, const MyIterator& i) { + return i + n; + } +}; +static_assert(contiguous_iterator>); + +void test_copy_n_regressions() { + const int src = 1729; + int x = 100; + + // _Copy_memmove_n was adding a size_t to an iterator without converting to its difference_type: + // warning C4267: 'argument': conversion from 'size_t' to 'MyIterator::difference_type', possible loss of data + copy_n(MyIterator{}, -42, MyIterator{}); + copy_n(MyIterator{}, 0, MyIterator{}); + copy_n(MyIterator{&src}, 1, MyIterator{&x}); + assert(x == 1729); + x = 100; + + copy_n(&src, -42, &x); + assert(x == 100); + copy_n(&src, 0, &x); + assert(x == 100); + copy_n(&src, 1, &x); + assert(x == 1729); + x = 100; + + // ranges::copy_n wasn't guarding against negative n when calling the memmove optimization + ranges::copy_n(MyIterator{}, -42, MyIterator{}); + ranges::copy_n(MyIterator{}, 0, MyIterator{}); + ranges::copy_n(MyIterator{&src}, 1, MyIterator{&x}); + assert(x == 1729); + x = 100; + + ranges::copy_n(&src, -42, &x); + assert(x == 100); + ranges::copy_n(&src, 0, &x); + assert(x == 100); + ranges::copy_n(&src, 1, &x); + assert(x == 1729); + x = 100; +} +#endif // _HAS_CXX20 + int main() { test_algorithms([](auto begin, auto end, auto out) { copy(begin, end, out); }); test_algorithms([](auto begin, auto end, auto out) { copy_n(begin, distance(begin, end), out); }); @@ -710,5 +816,7 @@ int main() { test_algorithms([](auto begin, auto end, auto out) { ranges::uninitialized_move_n(begin, distance(begin, end), out, unreachable_sentinel); }); + + test_copy_n_regressions(); #endif // _HAS_CXX20 } From f70b8859c25551e242d7f51621062de53aafcf5a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 8 Nov 2024 09:15:53 -0800 Subject: [PATCH 02/16] Fix internal Perl script for Standard Library Header Units test coverage (#5056) --- .../custombuild.pl | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl b/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl index 8ffb446266..458338d1c4 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl +++ b/tests/std/tests/P1502R1_standard_library_header_units/custombuild.pl @@ -6,11 +6,12 @@ use JSON::PP; use Run; +use Try::Tiny; sub readFile { my $filename = $_[0]; - open(my $handle, "<", $filename) or die("Couldn't open $filename: $!"); + open(my $handle, "<", $filename) or Run::PrintError(__FILE__, __LINE__, "Couldn't open $filename: $!"); read($handle, my $string, -s $handle); return $string; } @@ -19,14 +20,26 @@ sub loadJson { my $filename = $_[0]; my $jsonStr = readFile($filename); - return JSON::PP->new->utf8->decode($jsonStr); + my $decoded = ""; + try { + $decoded = JSON::PP->new->utf8->decode($jsonStr); + } catch { + Run::PrintError(__FILE__, __LINE__, "Caught exception in loadJson."); + }; + return $decoded; } sub loadJsonWithComments { my $filename = $_[0]; my $jsonStr = readFile($filename); - return JSON::PP->new->relaxed->utf8->decode($jsonStr); + my $decoded = ""; + try { + $decoded = JSON::PP->new->relaxed->utf8->decode($jsonStr); + } catch { + Run::PrintError(__FILE__, __LINE__, "Caught exception in loadJsonWithComments."); + }; + return $decoded; } sub getAllHeaders From cb8e5ba0102e1754fedd2071fa6fdc5a4e4957dc Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 9 Nov 2024 01:18:03 +0800 Subject: [PATCH 03/16] ``: Small cleanups (#5058) Co-authored-by: Stephan T. Lavavej --- stl/inc/regex | 342 +++++++++--------- .../test.compile.pass.cpp | 12 +- .../test.compile.pass.cpp | 12 +- .../std/tests/VSO_0000000_regex_use/test.cpp | 49 +++ 4 files changed, 223 insertions(+), 192 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 8d31ac7854..22bde0c3df 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -175,21 +175,17 @@ struct _Cl_names { // structure to associate class name with mask value } }; -template -struct _Char_traits_eq { - using _Elem = typename _Traits::char_type; - - _STATIC_CALL_OPERATOR bool operator()(_Elem _Left, _Elem _Right) _CONST_CALL_OPERATOR noexcept { - return _Traits::eq(_Left, _Right); +template +struct _Std_char_traits_eq { + _STATIC_CALL_OPERATOR bool operator()(_CharT _Left, _CharT _Right) _CONST_CALL_OPERATOR noexcept { + return char_traits<_CharT>::eq(_Left, _Right); } }; -template -struct _Char_traits_lt { - using _Elem = typename _Traits::char_type; - - _STATIC_CALL_OPERATOR bool operator()(_Elem _Left, _Elem _Right) _CONST_CALL_OPERATOR noexcept { - return _Traits::lt(_Left, _Right); +template +struct _Std_char_traits_lt { + _STATIC_CALL_OPERATOR bool operator()(_CharT _Left, _CharT _Right) _CONST_CALL_OPERATOR noexcept { + return char_traits<_CharT>::lt(_Left, _Right); } }; @@ -199,23 +195,23 @@ constexpr bool _Is_predefined_char_like_type = _Is_character<_Ty>::value || is_u // library-provided char_traits::eq behaves like equal_to<_Elem> template -constexpr bool _Can_memcmp_elements_with_pred<_Elem, _Elem, _Char_traits_eq>> = +constexpr bool _Can_memcmp_elements_with_pred<_Elem, _Elem, _Std_char_traits_eq<_Elem>> = _Is_predefined_char_like_type<_Elem> && _Can_memcmp_elements<_Elem, _Elem>; template > -struct _Lex_compare_memcmp_classify_pred_for_char_traits_lt { +struct _Lex_compare_memcmp_classify_pred_for_std_char_traits_lt { using _UElem = make_unsigned_t<_Elem>; using _Pred = conditional_t<_Lex_compare_memcmp_classify_elements<_UElem, _UElem>, less, void>; }; template -struct _Lex_compare_memcmp_classify_pred_for_char_traits_lt<_Elem, false> { +struct _Lex_compare_memcmp_classify_pred_for_std_char_traits_lt<_Elem, false> { using _Pred = void; }; // library-provided char_traits::lt behaves like less> template -struct _Lex_compare_memcmp_classify_pred<_Elem, _Elem, _Char_traits_lt>> - : _Lex_compare_memcmp_classify_pred_for_char_traits_lt<_Elem> {}; +struct _Lex_compare_memcmp_classify_pred<_Elem, _Elem, _Std_char_traits_lt<_Elem>> + : _Lex_compare_memcmp_classify_pred_for_std_char_traits_lt<_Elem> {}; template struct _Cmp_cs { // functor to compare two character values for equality @@ -229,9 +225,9 @@ template struct _Cmp_icase { // functor to compare for case-insensitive equality using _Elem = typename _RxTraits::char_type; - explicit _Cmp_icase(const _RxTraits& _Tr) : _Traits(_Tr) {} + explicit _Cmp_icase(const _RxTraits& _Tr) noexcept : _Traits(_Tr) {} - bool operator()(_Elem _Ex1, _Elem _Ex2) { + bool operator()(_Elem _Ex1, _Elem _Ex2) const { return _Traits.translate_nocase(_Ex1) == _Traits.translate_nocase(_Ex2); } @@ -242,9 +238,9 @@ template struct _Cmp_collate { // functor to compare for locale-specific equality using _Elem = typename _RxTraits::char_type; - explicit _Cmp_collate(const _RxTraits& _Tr) : _Traits(_Tr) {} + explicit _Cmp_collate(const _RxTraits& _Tr) noexcept : _Traits(_Tr) {} - bool operator()(_Elem _Ex1, _Elem _Ex2) { + bool operator()(_Elem _Ex1, _Elem _Ex2) const { return _Traits.translate(_Ex1) == _Traits.translate(_Ex2); } @@ -393,15 +389,15 @@ public: return _Tmp; } - locale_type getloc() const { + locale_type getloc() const noexcept /* strengthened */ { return _Loc; } - const collate<_Elem>* _Getcoll() const { // get collate facet pointer + const collate<_Elem>* _Getcoll() const noexcept { // get collate facet pointer return _Pcoll; } - const ctype<_Elem>* _Getctype() const { // get ctype facet pointer + const ctype<_Elem>* _Getctype() const noexcept { // get ctype facet pointer return _Pctype; } @@ -531,50 +527,6 @@ private: regex_constants::error_type _Err; }; -template -int _Iter_compare(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) { - // compare two iterator ranges: - // if [_First1, _Last1) is lexicographically less than [_First2, _Last2), a negative value - // if [_First2, _Last2) is lexicographically less than [_First1, _Last1), a positive value - // otherwise, zero - using _Elem = typename _Traits::char_type; - static_assert(is_same_v<_Iter_value_t<_FwdIt1>, _Elem>, "bad _FwdIt1 to _Iter_compare"); - static_assert(is_same_v<_Iter_value_t<_FwdIt2>, _Elem>, "bad _FwdIt2 to _Iter_compare"); - - _Adl_verify_range(_First1, _Last1); - _Adl_verify_range(_First2, _Last2); - - auto _UFirst1 = _Get_unwrapped(_First1); - auto _ULast1 = _Get_unwrapped(_Last1); - auto _UFirst2 = _Get_unwrapped(_First2); - auto _ULast2 = _Get_unwrapped(_Last2); - - if constexpr (is_pointer_v && is_pointer_v) { - return _Traits_compare<_Traits>( - _UFirst1, static_cast(_ULast1 - _UFirst1), _UFirst2, static_cast(_ULast2 - _UFirst2)); - } else { - const auto _Cmp = _STD mismatch(_UFirst1, _ULast1, _UFirst2, _ULast2, _Char_traits_eq<_Traits>{}); - - if (_Cmp.first == _ULast1) { - if (_Cmp.second == _ULast2) { - return 0; - } else { - return -1; - } - } - - if (_Cmp.second == _ULast2) { - return 1; - } - - if (_Traits::lt(*_Cmp.first, *_Cmp.second)) { - return -1; - } else { - return 1; - } - } -} - inline bool _Is_word(unsigned char _UCh) { // special casing char to avoid branches for std::regex in this path static constexpr bool _Is_word_table[_STD _Max_limit() + 1] = { @@ -613,14 +565,10 @@ public: using difference_type = typename iterator_traits<_BidIt>::difference_type; using iterator = _BidIt; using string_type = basic_string; - // Note that _Traits should always be std::char_traits - using _Traits = typename string_type::traits_type; - // Note that _Size_type should always be std::size_t - using _Size_type = typename string_type::size_type; - constexpr sub_match() : _Mybase(), matched(false) {} + constexpr sub_match() = default; - bool matched; + bool matched = false; _NODISCARD difference_type length() const { const _Mybase _Range(_Effective_range()); @@ -639,7 +587,7 @@ public: _NODISCARD int compare(const sub_match& _Right) const { // compare *this to _Right const _Mybase _LRange(_Effective_range()); const _Mybase _RRange(_Right._Effective_range()); - return _Iter_compare<_Traits>(_LRange.first, _LRange.second, _RRange.first, _RRange.second); + return _Iter_compare(_LRange.first, _LRange.second, _RRange.first, _RRange.second); } _NODISCARD int compare(const string_type& _Right) const { // compare *this to _Right @@ -647,7 +595,7 @@ public: } _NODISCARD int compare(_In_z_ const value_type* _Ptr) const { // compare *this to array pointed to by _Ptr - return _Compare(_Ptr, _Traits::length(_Ptr)); + return _Compare(_Ptr, char_traits::length(_Ptr)); } void swap(sub_match& _Other) noexcept(_Is_nothrow_swappable<_BidIt>::value) { @@ -655,55 +603,98 @@ public: _STD swap(matched, _Other.matched); } - int _Compare(const value_type* const _Ptr, const _Size_type _Count) const { + template + static int _Iter_compare(_BidIt _First1, _BidIt _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) { + // compare two iterator ranges: + // if [_First1, _Last1) is lexicographically less than [_First2, _Last2), a negative value + // if [_First2, _Last2) is lexicographically less than [_First1, _Last1), a positive value + // otherwise, zero + static_assert(is_same_v<_Iter_value_t<_FwdIt2>, value_type>, "bad _FwdIt2 to _Iter_compare"); + + _Adl_verify_range(_First1, _Last1); + _Adl_verify_range(_First2, _Last2); + + auto _UFirst1 = _Get_unwrapped(_First1); + auto _ULast1 = _Get_unwrapped(_Last1); + auto _UFirst2 = _Get_unwrapped(_First2); + auto _ULast2 = _Get_unwrapped(_Last2); + + if constexpr (is_pointer_v && is_pointer_v) { + return _Traits_compare>( + _UFirst1, static_cast(_ULast1 - _UFirst1), _UFirst2, static_cast(_ULast2 - _UFirst2)); + } else { + const auto _Cmp = _STD mismatch(_UFirst1, _ULast1, _UFirst2, _ULast2, _Std_char_traits_eq{}); + + if (_Cmp.first == _ULast1) { + if (_Cmp.second == _ULast2) { + return 0; + } else { + return -1; + } + } + + if (_Cmp.second == _ULast2) { + return 1; + } + + if (char_traits::lt(*_Cmp.first, *_Cmp.second)) { + return -1; + } else { + return 1; + } + } + } + + int _Compare(const value_type* const _Ptr, const size_t _Count) const { // compare *this to array [_Ptr, _Ptr + _Count) const _Mybase _Range(_Effective_range()); - return _Iter_compare<_Traits>(_Range.first, _Range.second, _Ptr, _Ptr + _Count); + return _Iter_compare(_Range.first, _Range.second, _Ptr, _Ptr + _Count); } bool _Match_equal(const sub_match& _Right) const { // check *this to _Right for equality const _Mybase _LRange(_Effective_range()); const _Mybase _RRange(_Right._Effective_range()); - return _STD equal(_LRange.first, _LRange.second, _RRange.first, _RRange.second, _Char_traits_eq<_Traits>{}); + return _STD equal( + _LRange.first, _LRange.second, _RRange.first, _RRange.second, _Std_char_traits_eq{}); } - bool _Match_equal(const value_type* const _Ptr, const _Size_type _Count) const { + bool _Match_equal(const value_type* const _Ptr, const size_t _Count) const { // check *this to array [_Ptr, _Ptr + _Count) for equality const _Mybase _Range(_Effective_range()); - return _STD equal(_Range.first, _Range.second, _Ptr, _Ptr + _Count, _Char_traits_eq<_Traits>{}); + return _STD equal(_Range.first, _Range.second, _Ptr, _Ptr + _Count, _Std_char_traits_eq{}); } bool _Match_equal(const value_type* const _Ptr) const { // check *this to C-string _Ptr for equality - return _Match_equal(_Ptr, _Traits::length(_Ptr)); + return _Match_equal(_Ptr, char_traits::length(_Ptr)); } bool _Less(const sub_match& _Right) const { // check whether *this is less than _Right const _Mybase _LRange(_Effective_range()); const _Mybase _RRange(_Right._Effective_range()); return _STD lexicographical_compare( - _LRange.first, _LRange.second, _RRange.first, _RRange.second, _Char_traits_lt<_Traits>{}); + _LRange.first, _LRange.second, _RRange.first, _RRange.second, _Std_char_traits_lt{}); } - bool _Less(const value_type* const _Ptr, const _Size_type _Count) const { + bool _Less(const value_type* const _Ptr, const size_t _Count) const { // check whether *this is less than [_Ptr, _Ptr + _Count) const _Mybase _Range(_Effective_range()); return _STD lexicographical_compare( - _Range.first, _Range.second, _Ptr, _Ptr + _Count, _Char_traits_lt<_Traits>{}); + _Range.first, _Range.second, _Ptr, _Ptr + _Count, _Std_char_traits_lt{}); } bool _Less(const value_type* const _Ptr) const { // check whether *this is less than C-string _Ptr - return _Less(_Ptr, _Traits::length(_Ptr)); + return _Less(_Ptr, char_traits::length(_Ptr)); } - bool _Greater(const value_type* const _Ptr, const _Size_type _Count) const { + bool _Greater(const value_type* const _Ptr, const size_t _Count) const { // check whether *this is greater than [_Ptr, _Ptr + _Count) const _Mybase _Range(_Effective_range()); return _STD lexicographical_compare( - _Ptr, _Ptr + _Count, _Range.first, _Range.second, _Char_traits_lt<_Traits>{}); + _Ptr, _Ptr + _Count, _Range.first, _Range.second, _Std_char_traits_lt{}); } bool _Greater(const value_type* const _Ptr) const { // check whether *this is greater than C-string _Ptr - return _Greater(_Ptr, _Traits::length(_Ptr)); + return _Greater(_Ptr, char_traits::length(_Ptr)); } _Mybase _Effective_range() const { // if matched, returns *this; otherwise returns an empty range @@ -1031,7 +1022,7 @@ public: return _Matches.size(); } - _NODISCARD size_type max_size() const { + _NODISCARD size_type max_size() const noexcept /* strengthened */ { return _Matches.max_size(); } @@ -1244,13 +1235,13 @@ enum _Node_type { // type flag for nfa nodes template struct _Buf { // character buffer - _Buf() : _Sz(0), _Nchrs(0), _Chrs(nullptr) {} + _Buf() = default; ~_Buf() noexcept { _CSTD free(_Chrs); } - unsigned int _Size() const { + unsigned int _Size() const noexcept { return _Nchrs; } @@ -1274,7 +1265,7 @@ struct _Buf { // character buffer _Chrs[_Nchrs++] = _Ch; } - _Elem _Del() { // remove and return last character + _Elem _Del() noexcept { // remove and return last character return _Chrs[--_Nchrs]; } @@ -1296,52 +1287,49 @@ private: _Sz = _Len; } - unsigned int _Sz; - unsigned int _Nchrs; - _Elem* _Chrs; + unsigned int _Sz = 0; + unsigned int _Nchrs = 0; + _Elem* _Chrs = nullptr; }; struct _Bitmap { // accelerator table for small character values - _Bitmap() { - _CSTD memset(_Chrs, '\0', _Bmp_size); - } + _Bitmap() = default; template - void _Mark(_Elem _Ch) { // mark character _Ch + void _Mark(_Elem _Ch) noexcept { // mark character _Ch static_assert(is_unsigned_v<_Elem>, "_Elem must be unsigned"); unsigned int _Wide = _Ch; _Chrs[_Wide >> _Bmp_shift] |= (1 << (_Wide & _Bmp_mask)); } template - bool _Find(_Elem _Ch) const { + bool _Find(_Elem _Ch) const noexcept { static_assert(is_unsigned_v<_Elem>, "_Elem must be unsigned"); unsigned int _Wide = _Ch; return (_Chrs[_Wide >> _Bmp_shift] & (1 << (_Wide & _Bmp_mask))) != 0; } private: - unsigned char _Chrs[_Bmp_size]; + unsigned char _Chrs[_Bmp_size]{}; }; template struct _Sequence { // holds sequences of _Sz elements - explicit _Sequence(unsigned int _Len) : _Sz(_Len) {} + explicit _Sequence(unsigned int _Len) noexcept : _Sz(_Len) {} unsigned int _Sz; _Buf<_Elem> _Data; - _Sequence* _Next; + _Sequence* _Next = nullptr; }; class _Node_base { // base class for all nfa nodes public: - explicit _Node_base(_Node_type _Ty, _Node_flags _Fl = _Fl_none) - : _Kind(_Ty), _Flags(_Fl), _Next(nullptr), _Prev(nullptr) {} + explicit _Node_base(_Node_type _Ty, _Node_flags _Fl = _Fl_none) noexcept : _Kind(_Ty), _Flags(_Fl) {} _Node_type _Kind; _Node_flags _Flags; - _Node_base* _Next; - _Node_base* _Prev; + _Node_base* _Next = nullptr; + _Node_base* _Prev = nullptr; virtual ~_Node_base() noexcept {} }; @@ -1357,44 +1345,44 @@ inline void _Destroy_node(_Node_base* _Nx, _Node_base* _Ne = nullptr) noexcept { class _Root_node : public _Node_base { // root of parse tree public: - _Root_node() : _Node_base(_N_begin), _Loops(0), _Marks(0), _Refs(0) { + _Root_node() noexcept : _Node_base(_N_begin) { static_assert(sizeof(_Refs) == sizeof(_Atomic_counter_t), "invalid _Refs size"); } regex_constants::syntax_option_type _Fl{}; - unsigned int _Loops; - unsigned int _Marks; - unsigned int _Refs; + unsigned int _Loops = 0; + unsigned int _Marks = 0; + unsigned int _Refs = 0; }; class _Node_end_group : public _Node_base { // node that marks end of a group public: - _Node_end_group(_Node_type _Ty, _Node_flags _Fl, _Node_base* _Bx) : _Node_base(_Ty, _Fl), _Back(_Bx) {} + _Node_end_group(_Node_type _Ty, _Node_flags _Fl, _Node_base* _Bx) noexcept : _Node_base(_Ty, _Fl), _Back(_Bx) {} _Node_base* _Back; }; class _Node_assert : public _Node_base { // node that holds an ECMAScript assertion public: - explicit _Node_assert(_Node_type _Ty, _Node_flags _Fl = _Fl_none) : _Node_base(_Ty, _Fl), _Child(nullptr) {} + explicit _Node_assert(_Node_type _Ty, _Node_flags _Fl = _Fl_none) noexcept : _Node_base(_Ty, _Fl) {} ~_Node_assert() noexcept { _Destroy_node(_Child); } - _Node_base* _Child; + _Node_base* _Child = nullptr; }; class _Node_capture : public _Node_base { // node that marks beginning of a capture group public: - explicit _Node_capture(unsigned int _Ix) : _Node_base(_N_capture, _Fl_none), _Idx(_Ix) {} + explicit _Node_capture(unsigned int _Ix) noexcept : _Node_base(_N_capture, _Fl_none), _Idx(_Ix) {} unsigned int _Idx; }; class _Node_back : public _Node_base { // node that holds a back reference public: - explicit _Node_back(unsigned int _Ix) : _Node_base(_N_back, _Fl_none), _Idx(_Ix) {} + explicit _Node_back(unsigned int _Ix) noexcept : _Node_base(_N_back, _Fl_none), _Idx(_Ix) {} unsigned int _Idx; }; @@ -1402,7 +1390,7 @@ public: template class _Node_str : public _Node_base { // node that holds text public: - explicit _Node_str(_Node_flags _Fl = _Fl_none) : _Node_base(_N_str, _Fl) {} + explicit _Node_str(_Node_flags _Fl = _Fl_none) noexcept : _Node_base(_N_str, _Fl) {} _Buf<_Elem> _Data; }; @@ -1410,9 +1398,7 @@ public: template class _Node_class : public _Node_base { // node that holds a character class (POSIX bracket expression) public: - explicit _Node_class(_Node_type _Ty = _N_class, _Node_flags _Fl = _Fl_none) - : _Node_base(_Ty, _Fl), _Coll(nullptr), _Small(nullptr), _Large(nullptr), _Ranges(nullptr), _Classes{}, - _Equiv(nullptr) {} + explicit _Node_class(_Node_type _Ty = _N_class, _Node_flags _Fl = _Fl_none) noexcept : _Node_base(_Ty, _Fl) {} ~_Node_class() noexcept { _Tidy(_Coll); @@ -1430,23 +1416,23 @@ public: } } - _Sequence<_Elem>* _Coll; - _Bitmap* _Small; - _Buf<_Elem>* _Large; - _Buf<_Elem>* _Ranges; - typename _RxTraits::char_class_type _Classes; - _Sequence<_Elem>* _Equiv; + _Sequence<_Elem>* _Coll = nullptr; + _Bitmap* _Small = nullptr; + _Buf<_Elem>* _Large = nullptr; + _Buf<_Elem>* _Ranges = nullptr; + typename _RxTraits::char_class_type _Classes{}; + _Sequence<_Elem>* _Equiv = nullptr; }; class _Node_endif : public _Node_base { // node that marks the end of an alternative public: - _Node_endif() : _Node_base(_N_endif, _Fl_none) {} + _Node_endif() noexcept : _Node_base(_N_endif, _Fl_none) {} }; class _Node_if : public _Node_base { // node that marks the beginning of an alternative public: - explicit _Node_if(_Node_base* _End) - : _Node_base(_N_if, _Fl_none), _Endif(static_cast<_Node_endif*>(_End)), _Child(nullptr) {} + explicit _Node_if(_Node_base* _End) noexcept + : _Node_base(_N_if, _Fl_none), _Endif(static_cast<_Node_endif*>(_End)) {} ~_Node_if() noexcept { _Node_if* _Cur = _Child; @@ -1459,16 +1445,16 @@ public: } _Node_endif* _Endif; - _Node_if* _Child; + _Node_if* _Child = nullptr; }; class _Node_rep; class _Node_end_rep : public _Node_base { // node that marks the end of a repetition public: - _Node_end_rep() : _Node_base(_N_end_rep), _Begin_rep(nullptr) {} + _Node_end_rep() noexcept : _Node_base(_N_end_rep) {} - _Node_rep* _Begin_rep; + _Node_rep* _Begin_rep = nullptr; _Node_end_rep& operator=(const _Node_end_rep&) = delete; }; @@ -1480,15 +1466,15 @@ struct _Loop_vals_t { // storage for loop administration class _Node_rep : public _Node_base { // node that marks the beginning of a repetition public: - _Node_rep(bool _Greedy, int _Min_, int _Max_, _Node_end_rep* _End, unsigned int _Number) + _Node_rep(bool _Greedy, int _Min_, int _Max_, _Node_end_rep* _End, unsigned int _Number) noexcept : _Node_base(_N_rep, _Greedy ? _Fl_greedy : _Fl_none), _Min(_Min_), _Max(_Max_), _End_rep(_End), - _Loop_number(_Number), _Simple_loop(-1) {} + _Loop_number(_Number) {} const int _Min; const int _Max; _Node_end_rep* _End_rep; unsigned int _Loop_number; - int _Simple_loop; // -1 undetermined, 0 contains if/do, 1 simple + int _Simple_loop = -1; // -1 undetermined, 0 contains if/do, 1 simple _Node_rep& operator=(const _Node_rep&) = delete; }; @@ -1582,9 +1568,8 @@ class _Matcher { // provides ways to match a regular expression to a text sequen public: _Matcher(_It _Pfirst, _It _Plast, const _RxTraits& _Tr, _Root_node* _Re, unsigned int _Nx, regex_constants::syntax_option_type _Sf, regex_constants::match_flag_type _Mf) - : _End(_Plast), _First(_Pfirst), _Rep(_Re), _Sflags(_Sf), _Mflags(_Mf), _Matched(false), - _Ncap(static_cast(_Nx)), _Longest((_Re->_Flags & _Fl_longest) && !(_Mf & regex_constants::match_any)), - _Traits(_Tr) { + : _End(_Plast), _First(_Pfirst), _Rep(_Re), _Sflags(_Sf), _Mflags(_Mf), _Ncap(static_cast(_Nx)), + _Longest((_Re->_Flags & _Fl_longest) && !(_Mf & regex_constants::match_any)), _Traits(_Tr) { _Loop_vals.resize(_Re->_Loops); _Adl_verify_range(_Pfirst, _Plast); } @@ -1678,7 +1663,7 @@ private: _Node_base* _Rep; regex_constants::syntax_option_type _Sflags; regex_constants::match_flag_type _Mflags; - bool _Matched; + bool _Matched = false; bool _Cap; int _Ncap; // Do not use. Use _Get_ncap instead. bool _Longest; @@ -1705,7 +1690,7 @@ public: _Parser(const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx); _Root_node* _Compile(); - unsigned int _Mark_count() const { + unsigned int _Mark_count() const noexcept { return _Grp_idx + 1; } @@ -1746,8 +1731,8 @@ private: _FwdIt _Pat; _FwdIt _Begin; _FwdIt _End; - unsigned int _Grp_idx; - int _Disj_count; + unsigned int _Grp_idx = 0; + int _Disj_count = 0; vector _Finished_grps; _Builder<_FwdIt, _Elem, _RxTraits> _Nfa; const _RxTraits& _Traits; @@ -1828,14 +1813,13 @@ public: static constexpr flag_type grep = regex_constants::grep; static constexpr flag_type egrep = regex_constants::egrep; - basic_regex() : _Rep(nullptr) {} // construct empty object + basic_regex() = default; // construct empty object - explicit basic_regex(_In_z_ const _Elem* _Ptr, flag_type _Flags = regex_constants::ECMAScript) : _Rep(nullptr) { + explicit basic_regex(_In_z_ const _Elem* _Ptr, flag_type _Flags = regex_constants::ECMAScript) { _Reset(_Ptr, _Ptr + _RxTraits::length(_Ptr), _Flags); } - basic_regex(_In_reads_(_Count) const _Elem* _Ptr, size_t _Count, flag_type _Flags = regex_constants::ECMAScript) - : _Rep(nullptr) { + basic_regex(_In_reads_(_Count) const _Elem* _Ptr, size_t _Count, flag_type _Flags = regex_constants::ECMAScript) { if (_Ptr) { _Reset(_Ptr, _Ptr + _Count, _Flags); return; @@ -1846,34 +1830,33 @@ public: template explicit basic_regex( - const basic_string<_Elem, _STtraits, _STalloc>& _Str, flag_type _Flags = regex_constants::ECMAScript) - : _Rep(nullptr) { + const basic_string<_Elem, _STtraits, _STalloc>& _Str, flag_type _Flags = regex_constants::ECMAScript) { _Reset(_Str.data(), _Str.data() + static_cast(_Str.size()), _Flags); } template - basic_regex(_InIt _First, _InIt _Last, flag_type _Flags) : _Rep(nullptr) { + basic_regex(_InIt _First, _InIt _Last, flag_type _Flags) { _Adl_verify_range(_First, _Last); _Reset(_Get_unwrapped(_First), _Get_unwrapped(_Last), _Flags); } template - basic_regex(_InIt _First, _InIt _Last) : _Rep(nullptr) { + basic_regex(_InIt _First, _InIt _Last) { _Adl_verify_range(_First, _Last); _Reset(_Get_unwrapped(_First), _Get_unwrapped(_Last), regex_constants::ECMAScript); } basic_regex(const basic_regex& _Right) #if _ENHANCED_REGEX_VISUALIZER - : _Rep(nullptr), _Traits(_Right._Traits), _Visualization(_Right._Visualization) + : _Traits(_Right._Traits), _Visualization(_Right._Visualization) #else - : _Rep(nullptr), _Traits(_Right._Traits) + : _Traits(_Right._Traits) #endif { // construct copy of _Right _Reset(_Right._Rep); } - basic_regex(initializer_list<_Elem> _Ilist, flag_type _Flags = regex_constants::ECMAScript) : _Rep(nullptr) { + basic_regex(initializer_list<_Elem> _Ilist, flag_type _Flags = regex_constants::ECMAScript) { _Reset(_Ilist.begin(), _Ilist.end(), _Flags); } @@ -1887,7 +1870,7 @@ public: return *this; } - basic_regex(basic_regex&& _Right) noexcept : _Rep(nullptr) { + basic_regex(basic_regex&& _Right) noexcept { _Assign_rv(_STD move(_Right)); } @@ -1933,11 +1916,11 @@ public: return *this; } - unsigned int _Loop_count() const { + unsigned int _Loop_count() const noexcept { return _Rep ? _Rep->_Loops : 0; } - _NODISCARD unsigned int mark_count() const { + _NODISCARD unsigned int mark_count() const noexcept /* strengthened */ { return _Rep ? _Rep->_Marks - 1 : 0; } @@ -1974,7 +1957,7 @@ public: return *this; } - _NODISCARD flag_type flags() const { + _NODISCARD flag_type flags() const noexcept /* strengthened */ { return _Rep ? _Rep->_Fl : flag_type{}; } @@ -1995,20 +1978,20 @@ public: #endif // _ENHANCED_REGEX_VISUALIZER } - _Root_node* _Get() const { + _Root_node* _Get() const noexcept { return _Rep; } - bool _Empty() const { + bool _Empty() const noexcept { return _Rep == nullptr; } - const _RxTraits& _Get_traits() const { + const _RxTraits& _Get_traits() const noexcept { return _Traits; } private: - _Root_node* _Rep; + _Root_node* _Rep = nullptr; _RxTraits _Traits; #if _ENHANCED_REGEX_VISUALIZER @@ -2428,7 +2411,7 @@ public: using iterator_concept = input_iterator_tag; #endif // _HAS_CXX20 - regex_iterator() : _MyRe(nullptr) {} // construct end of sequence iterator + regex_iterator() = default; // construct end of sequence iterator regex_iterator(_BidIt _First, _BidIt _Last, const regex_type& _Re, regex_constants::match_flag_type _Fl = regex_constants::match_default) @@ -2462,12 +2445,12 @@ public: #endif // !_HAS_CXX20 #if _HAS_CXX20 - _NODISCARD bool operator==(default_sentinel_t) const { + _NODISCARD bool operator==(default_sentinel_t) const noexcept /* strengthened */ { return !_MyRe; } #endif // _HAS_CXX20 - _NODISCARD const value_type& operator*() const { + _NODISCARD const value_type& operator*() const noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_MyRe, "regex_iterator not dereferenceable"); #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -2475,7 +2458,7 @@ public: return _MyVal; } - _NODISCARD const value_type* operator->() const { + _NODISCARD const value_type* operator->() const noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_MyRe, "regex_iterator not dereferenceable"); #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -2536,15 +2519,15 @@ public: return _Tmp; } - bool _Atend() const { // test for end iterator + bool _Atend() const noexcept { // test for end iterator return !_MyRe; } private: - _BidIt _Begin; // input sequence - _BidIt _End; // input sequence - const regex_type* _MyRe; // pointer to basic_regex object - regex_constants::match_flag_type _Flags; + _BidIt _Begin{}; // input sequence + _BidIt _End{}; // input sequence + const regex_type* _MyRe = nullptr; // pointer to basic_regex object + regex_constants::match_flag_type _Flags{}; match_results<_BidIt> _MyVal; // lookahead value (if _MyRe not null) }; @@ -2567,7 +2550,7 @@ public: using iterator_concept = input_iterator_tag; #endif // _HAS_CXX20 - regex_token_iterator() : _Res(nullptr) {} // construct end of sequence iterator + regex_token_iterator() = default; // construct end of sequence iterator regex_token_iterator(_BidIt _First, _BidIt _Last, const regex_type& _Re, int _Sub = 0, regex_constants::match_flag_type _Fl = regex_constants::match_default) @@ -2655,12 +2638,12 @@ public: #endif // !_HAS_CXX20 #if _HAS_CXX20 - _NODISCARD bool operator==(default_sentinel_t) const { + _NODISCARD bool operator==(default_sentinel_t) const noexcept /* strengthened */ { return !_Res; } #endif // _HAS_CXX20 - _NODISCARD const value_type& operator*() const { + _NODISCARD const value_type& operator*() const noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Res, "regex_token_iterator not dereferenceable"); #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -2669,7 +2652,7 @@ public: return *_Res; } - _NODISCARD const value_type* operator->() const { + _NODISCARD const value_type* operator->() const noexcept /* strengthened */ { #if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Res, "regex_token_iterator not dereferenceable"); #endif // _ITERATOR_DEBUG_LEVEL != 0 @@ -2713,9 +2696,9 @@ public: private: _Position _Pos; - const value_type* _Res; + const value_type* _Res = nullptr; value_type _Suffix; - size_t _Cur; + size_t _Cur = 0; vector _Subs; bool _Has_suffix() const { // check for suffix specifier @@ -2736,7 +2719,7 @@ private: } } - const value_type* _Current() const { + const value_type* _Current() const noexcept { return &(_Subs[_Cur] == -1 ? _Pos->prefix() : (*_Pos)[static_cast(_Subs[_Cur])]); } }; @@ -4581,8 +4564,7 @@ _Root_node* _Parser<_FwdIt, _Elem, _RxTraits>::_Compile() { // compile regular e template _Parser<_FwdIt, _Elem, _RxTraits>::_Parser( const _RxTraits& _Tr, _FwdIt _Pfirst, _FwdIt _Plast, regex_constants::syntax_option_type _Fx) - : _Pat(_Pfirst), _Begin(_Pfirst), _End(_Plast), _Grp_idx(0), _Disj_count(0), _Finished_grps(0), _Nfa(_Tr, _Fx), - _Traits(_Tr), _Flags(_Fx) { + : _Pat(_Pfirst), _Begin(_Pfirst), _End(_Plast), _Nfa(_Tr, _Fx), _Traits(_Tr), _Flags(_Fx) { constexpr unsigned int _ECMA_flags = _L_ext_rep | _L_alt_pipe | _L_nex_grp | _L_nex_rep | _L_nc_grp | _L_asrt_gen | _L_asrt_wrd | _L_bckr | _L_ngr_rep | _L_esc_uni | _L_esc_hex | _L_esc_bsl diff --git a/tests/std/tests/GH_000431_equal_memcmp_is_safe/test.compile.pass.cpp b/tests/std/tests/GH_000431_equal_memcmp_is_safe/test.compile.pass.cpp index 3fefa3cca2..0d19218dbf 100644 --- a/tests/std/tests/GH_000431_equal_memcmp_is_safe/test.compile.pass.cpp +++ b/tests/std/tests/GH_000431_equal_memcmp_is_safe/test.compile.pass.cpp @@ -500,14 +500,14 @@ STATIC_ASSERT(test_equal_memcmp_is_safe_for_types()); -// Test _Char_traits_eq -STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>>()); -STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>>()); +// Test _Std_char_traits_eq +STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>()); +STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>()); #ifdef __cpp_lib_char8_t -STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>>()); +STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>()); #endif // __cpp_lib_char8_t -STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>>()); -STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>>()); +STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>()); +STATIC_ASSERT(test_equal_memcmp_is_safe_for_pred>()); // Test different containers #if _HAS_CXX20 diff --git a/tests/std/tests/GH_000431_lex_compare_memcmp_classify/test.compile.pass.cpp b/tests/std/tests/GH_000431_lex_compare_memcmp_classify/test.compile.pass.cpp index 8f6be97461..85f43c2201 100644 --- a/tests/std/tests/GH_000431_lex_compare_memcmp_classify/test.compile.pass.cpp +++ b/tests/std/tests/GH_000431_lex_compare_memcmp_classify/test.compile.pass.cpp @@ -296,17 +296,17 @@ void lex_compare_memcmp_classify_test_cases() { // Don't allow user-defined types test_lex_compare_memcmp_classify_for_types(); - // Test _Char_traits_lt - test_lex_compare_memcmp_classify_for_pred, char, char, _Char_traits_lt>>(); + // Test _Std_char_traits_lt + test_lex_compare_memcmp_classify_for_pred, char, char, _Std_char_traits_lt>(); #ifdef __cpp_lib_char8_t - test_lex_compare_memcmp_classify_for_pred, char8_t, char8_t, _Char_traits_lt>>(); + test_lex_compare_memcmp_classify_for_pred, char8_t, char8_t, _Std_char_traits_lt>(); #endif // __cpp_lib_char8_t using vless = conditional_t, void>; - test_lex_compare_memcmp_classify_for_pred>>(); - test_lex_compare_memcmp_classify_for_pred>>(); - test_lex_compare_memcmp_classify_for_pred>>(); + test_lex_compare_memcmp_classify_for_pred>(); + test_lex_compare_memcmp_classify_for_pred>(); + test_lex_compare_memcmp_classify_for_pred>(); // Test different containers #if _HAS_CXX20 diff --git a/tests/std/tests/VSO_0000000_regex_use/test.cpp b/tests/std/tests/VSO_0000000_regex_use/test.cpp index f5abd2955e..fcd27f0beb 100644 --- a/tests/std/tests/VSO_0000000_regex_use/test.cpp +++ b/tests/std/tests/VSO_0000000_regex_use/test.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include #include @@ -581,6 +582,53 @@ void test_gh_993() { } } +void test_gh_5058() { + // GH-5058 ": Small cleanups" changed some default constructors to be defaulted. + // Verify that types are still const-default-constructible (N4993 [dcl.init.general]/8). + { + const regex r; + assert(!regex_match("cats", r)); + } + { + const csub_match csm; + assert(!csm.matched); + assert(csm.first == nullptr); + assert(csm.second == nullptr); + } + { + const ssub_match ssm; + assert(!ssm.matched); + assert(ssm.first == string::const_iterator{}); + assert(ssm.second == string::const_iterator{}); + } + { + const cmatch cmr; + assert(!cmr.ready()); + assert(cmr.size() == 0); + } + { + const smatch smr; + assert(!smr.ready()); + assert(smr.size() == 0); + } + { + const cregex_iterator cri; + assert(cri == cregex_iterator{}); + } + { + const sregex_iterator sri; + assert(sri == sregex_iterator{}); + } + { + const cregex_token_iterator crti; + assert(crti == cregex_token_iterator{}); + } + { + const sregex_token_iterator srti; + assert(srti == sregex_token_iterator{}); + } +} + int main() { test_dev10_449367_case_insensitivity_should_work(); test_dev11_462743_regex_collate_should_not_disable_regex_icase(); @@ -608,6 +656,7 @@ int main() { test_VSO_225160_match_eol_flag(); test_VSO_226914_word_boundaries(); test_gh_993(); + test_gh_5058(); return g_regexTester.result(); } From 4b697a86434bf0b08521952084f79b9c4994d389 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 8 Nov 2024 09:20:42 -0800 Subject: [PATCH 04/16] Guard `__restrict` usage for CUDA (#5061) --- stl/inc/numeric | 2 +- stl/inc/yvals_core.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/stl/inc/numeric b/stl/inc/numeric index b0d0e8a25c..5b56450626 100644 --- a/stl/inc/numeric +++ b/stl/inc/numeric @@ -463,7 +463,7 @@ _FwdIt2 transform_inclusive_scan(_ExPo&& _Exec, _FwdIt1 _First, _FwdIt1 _Last, _ template void _Adjacent_difference_no_overlap( - _TyDest* const __restrict _Dest, _TySrc* const __restrict _Src, const ptrdiff_t _Count, _BinOp _Func) { + _TyDest* const _RESTRICT _Dest, _TySrc* const _RESTRICT _Src, const ptrdiff_t _Count, _BinOp _Func) { _Dest[0] = _Src[0]; for (ptrdiff_t _Ix = 1; _Ix != _Count; ++_Ix) { #if _HAS_CXX20 diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 296e4b7189..52c6f689d2 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -2016,5 +2016,11 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #define _CONST_CALL_OPERATOR const #endif // ^^^ !defined(__cpp_static_call_operator) ^^^ +#ifdef __CUDACC__ // TRANSITION, CUDA 12.4 doesn't recognize __restrict +#define _RESTRICT +#else // ^^^ defined(__CUDACC__) / !defined(__CUDACC__) vvv +#define _RESTRICT __restrict +#endif // ^^^ !defined(__CUDACC__) ^^^ + #endif // _STL_COMPILER_PREPROCESSOR #endif // _YVALS_CORE_H_ From 2e5c25139dbcd9aac1b5aa167b69ff2d2ded7efc Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Fri, 8 Nov 2024 09:24:24 -0800 Subject: [PATCH 05/16] Partition vector algorithms test: move out lex compare family (#5063) --- tests/std/test.lst | 1 + .../VSO_0000000_vector_algorithms/test.cpp | 238 ---------------- .../env.lst | 7 + .../test.cpp | 264 ++++++++++++++++++ 4 files changed, 272 insertions(+), 238 deletions(-) create mode 100644 tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/env.lst create mode 100644 tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index b0815e4075..94f80f9dce 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -724,6 +724,7 @@ tests\VSO_0000000_string_view_idl tests\VSO_0000000_type_traits tests\VSO_0000000_vector_algorithms tests\VSO_0000000_vector_algorithms_floats +tests\VSO_0000000_vector_algorithms_mismatch_and_lex_compare tests\VSO_0000000_wcfb01_idempotent_container_destructors tests\VSO_0000000_wchar_t_filebuf_xsmeown tests\VSO_0095468_clr_exception_ptr_bad_alloc diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index bba38a1d3d..54876e3849 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -537,221 +537,6 @@ void test_min_max_element_special_cases() { == v.begin() + 2 * block_size_in_elements + last_vector_first_elem + 9); } -template -auto last_known_good_mismatch(FwdIt first1, FwdIt last1, FwdIt first2, FwdIt last2) { - for (; first1 != last1 && first2 != last2; ++first1, ++first2) { - if (*first1 != *first2) { - break; - } - } - - return make_pair(first1, first2); -} - -template -bool last_known_good_lex_compare(pair expected_mismatch, FwdIt last1, FwdIt last2) { - if (expected_mismatch.second == last2) { - return false; - } else if (expected_mismatch.first == last1) { - return true; - } else if (*expected_mismatch.first < *expected_mismatch.second) { - return true; - } else { - assert(*expected_mismatch.second < *expected_mismatch.first); - return false; - } -} - -#if _HAS_CXX20 -template -auto last_known_good_lex_compare_3way(pair expected_mismatch, FwdIt last1, FwdIt last2) { - if (expected_mismatch.second == last2) { - if (expected_mismatch.first == last1) { - return strong_ordering::equal; - } else { - return strong_ordering::greater; - } - } else if (expected_mismatch.first == last1) { - return strong_ordering::less; - } else { - auto order = *expected_mismatch.first <=> *expected_mismatch.second; - assert(order != 0); - return order; - } -} -#endif // _HAS_CXX20 - -template -void test_case_mismatch_and_lex_compare_family(const vector& a, const vector& b) { - auto expected_mismatch = last_known_good_mismatch(a.begin(), a.end(), b.begin(), b.end()); - auto actual_mismatch = mismatch(a.begin(), a.end(), b.begin(), b.end()); - assert(expected_mismatch == actual_mismatch); - - auto expected_lex = last_known_good_lex_compare(expected_mismatch, a.end(), b.end()); - auto actual_lex = lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); - assert(expected_lex == actual_lex); - -#if _HAS_CXX20 - auto ranges_actual_mismatch = ranges::mismatch(a, b); - assert(get<0>(expected_mismatch) == ranges_actual_mismatch.in1); - assert(get<1>(expected_mismatch) == ranges_actual_mismatch.in2); - - auto ranges_actual_lex = ranges::lexicographical_compare(a, b); - assert(expected_lex == ranges_actual_lex); - - auto expected_lex_3way = last_known_good_lex_compare_3way(expected_mismatch, a.end(), b.end()); - auto actual_lex_3way = lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end()); - assert(expected_lex_3way == actual_lex_3way); -#endif // _HAS_CXX20 -} - -template -void test_mismatch_and_lex_compare_family(mt19937_64& gen) { - constexpr size_t shrinkCount = 4; - constexpr size_t mismatchCount = 10; - using TD = conditional_t; - uniform_int_distribution dis('a', 'z'); - vector input_a; - vector input_b; - input_a.reserve(dataCount); - input_b.reserve(dataCount); - - for (;;) { - // equal - test_case_mismatch_and_lex_compare_family(input_a, input_b); - - // different sizes - for (size_t i = 0; i != shrinkCount && !input_b.empty(); ++i) { - input_b.pop_back(); - test_case_mismatch_and_lex_compare_family(input_a, input_b); - test_case_mismatch_and_lex_compare_family(input_b, input_a); - } - - // actual mismatch (or maybe not, depending on random) - if (!input_b.empty()) { - uniform_int_distribution mismatch_dis(0, input_a.size() - 1); - - for (size_t attempts = 0; attempts < mismatchCount; ++attempts) { - const size_t possible_mismatch_pos = mismatch_dis(gen); - input_a[possible_mismatch_pos] = static_cast(dis(gen)); - test_case_mismatch_and_lex_compare_family(input_a, input_b); - test_case_mismatch_and_lex_compare_family(input_b, input_a); - } - } - - if (input_a.size() == dataCount) { - break; - } - - input_a.push_back(static_cast(dis(gen))); - input_b = input_a; - } -} - -template -void test_mismatch_and_lex_compare_family_containers() { - C1 a{'m', 'e', 'o', 'w', ' ', 'C', 'A', 'T', 'S'}; - C2 b{'m', 'e', 'o', 'w', ' ', 'K', 'I', 'T', 'T', 'E', 'N', 'S'}; - - const auto result_mismatch_4 = mismatch(a.begin(), a.end(), b.begin(), b.end()); - const auto result_mismatch_3 = mismatch(a.begin(), a.end(), b.begin()); - assert(get<0>(result_mismatch_4) == a.begin() + 5); - assert(get<1>(result_mismatch_4) == b.begin() + 5); - assert(get<0>(result_mismatch_3) == a.begin() + 5); - assert(get<1>(result_mismatch_3) == b.begin() + 5); - - const auto result_lex = lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); - assert(result_lex == true); - -#if _HAS_CXX20 - const auto result_mismatch_r = ranges::mismatch(a, b); - assert(result_mismatch_r.in1 == a.begin() + 5); - assert(result_mismatch_r.in2 == b.begin() + 5); - - const auto result_lex_r = ranges::lexicographical_compare(a, b); - assert(result_lex_r == true); - - const auto result_lex_3way = lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end()); - assert(result_lex_3way == strong_ordering::less); -#endif // _HAS_CXX20 -} - -namespace test_mismatch_sizes_and_alignments { - constexpr size_t range = 33; - constexpr size_t alignment = 32; - -#pragma pack(push, 1) - template - struct with_pad { - char p[PadSize]; - T v[Size]; - }; -#pragma pack(pop) - - template - char stack_array_various_alignments_impl() { - with_pad a = {}; - with_pad b = {}; - assert(mismatch(begin(a.v), end(a.v), begin(b.v), end(b.v)) == make_pair(end(a.v), end(b.v))); - return 0; - } - - template - void stack_array_various_alignments(index_sequence) { - char ignored[] = {stack_array_various_alignments_impl()...}; - (void) ignored; - } - - template - char stack_array_impl() { - T a[Size + 1] = {}; - T b[Size + 1] = {}; - assert(mismatch(begin(a), end(a), begin(b), end(b)) == make_pair(end(a), end(b))); - stack_array_various_alignments(make_index_sequence{}); - return 0; - } - - template - void stack_array(index_sequence) { - char ignored[] = {stack_array_impl()...}; - (void) ignored; - } - - template - void test() { - // stack with different sizes and alignments. ASan would catch out-of-range reads - stack_array(make_index_sequence{}); - - // vector with different sizes. ASan vector annotations would catch out-of-range reads - for (size_t i = 0; i != range; ++i) { - vector a(i, 0); - vector b(i, 0); - assert(mismatch(begin(a), end(a), begin(b), end(b)) == make_pair(end(a), end(b))); - } - - // heap with different sizes. ASan would catch out-of-range reads - for (size_t i = 0; i != range; ++i) { - T* a = static_cast(calloc(i, sizeof(T))); - T* b = static_cast(calloc(i, sizeof(T))); - assert(mismatch(a, a + i, b, b + i) == make_pair(a + i, b + i)); - free(a); - free(b); - } - - // subarray from stack array. We would have wrong results if we run out of the range. - T a[range + 1] = {}; - T b[range + 1] = {}; - for (size_t i = 0; i != range; ++i) { - a[i + 1] = 1; - // whole range mismatch finds mismatch after past-the-end of the subarray - assert(mismatch(a, a + range + 1, b, b + range + 1) == make_pair(a + i + 1, b + i + 1)); - // limited range mismatch gets to past-the-end of the subarray - assert(mismatch(a, a + i, b, b + i) == make_pair(a + i, b + i)); - a[i + 1] = 0; - } - } -} // namespace test_mismatch_sizes_and_alignments - template void last_known_good_replace(FwdIt first, FwdIt last, const T old_val, const T new_val) { for (; first != last; ++first) { @@ -1063,29 +848,6 @@ void test_vector_algorithms(mt19937_64& gen) { test_case_min_max_element( vector{-6604286336755016904, -4365366089374418225, 6104371530830675888, -8582621853879131834}); - test_mismatch_and_lex_compare_family(gen); - test_mismatch_and_lex_compare_family(gen); - test_mismatch_and_lex_compare_family(gen); - test_mismatch_and_lex_compare_family(gen); - test_mismatch_and_lex_compare_family(gen); - test_mismatch_and_lex_compare_family(gen); - test_mismatch_and_lex_compare_family(gen); - test_mismatch_and_lex_compare_family(gen); - test_mismatch_and_lex_compare_family(gen); - - test_mismatch_and_lex_compare_family_containers, vector>(); - test_mismatch_and_lex_compare_family_containers, vector>(); - test_mismatch_and_lex_compare_family_containers, vector>(); - test_mismatch_and_lex_compare_family_containers, const vector>(); - test_mismatch_and_lex_compare_family_containers, const vector>(); - test_mismatch_and_lex_compare_family_containers, vector>(); - test_mismatch_and_lex_compare_family_containers, vector>(); - - test_mismatch_sizes_and_alignments::test(); - test_mismatch_sizes_and_alignments::test(); - test_mismatch_sizes_and_alignments::test(); - test_mismatch_sizes_and_alignments::test(); - // replace() is vectorized for 4 and 8 bytes only. test_replace(gen); test_replace(gen); diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/env.lst b/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/env.lst new file mode 100644 index 0000000000..78fbe6b49a --- /dev/null +++ b/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/env.lst @@ -0,0 +1,7 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst +RUNALL_CROSSLIST +* PM_CL="" +* PM_CL="/D_USE_STD_VECTOR_ALGORITHMS=0" diff --git a/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp new file mode 100644 index 0000000000..458d431407 --- /dev/null +++ b/tests/std/tests/VSO_0000000_vector_algorithms_mismatch_and_lex_compare/test.cpp @@ -0,0 +1,264 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include + +#if _HAS_CXX20 +#include +#include +#endif // _HAS_CXX20 + +#include "test_vector_algorithms_support.hpp" + +using namespace std; + +template +auto last_known_good_mismatch(FwdIt first1, FwdIt last1, FwdIt first2, FwdIt last2) { + for (; first1 != last1 && first2 != last2; ++first1, ++first2) { + if (*first1 != *first2) { + break; + } + } + + return make_pair(first1, first2); +} + +template +bool last_known_good_lex_compare(pair expected_mismatch, FwdIt last1, FwdIt last2) { + if (expected_mismatch.second == last2) { + return false; + } else if (expected_mismatch.first == last1) { + return true; + } else if (*expected_mismatch.first < *expected_mismatch.second) { + return true; + } else { + assert(*expected_mismatch.second < *expected_mismatch.first); + return false; + } +} + +#if _HAS_CXX20 +template +auto last_known_good_lex_compare_3way(pair expected_mismatch, FwdIt last1, FwdIt last2) { + if (expected_mismatch.second == last2) { + if (expected_mismatch.first == last1) { + return strong_ordering::equal; + } else { + return strong_ordering::greater; + } + } else if (expected_mismatch.first == last1) { + return strong_ordering::less; + } else { + auto order = *expected_mismatch.first <=> *expected_mismatch.second; + assert(order != 0); + return order; + } +} +#endif // _HAS_CXX20 + +template +void test_case_mismatch_and_lex_compare_family(const vector& a, const vector& b) { + auto expected_mismatch = last_known_good_mismatch(a.begin(), a.end(), b.begin(), b.end()); + auto actual_mismatch = mismatch(a.begin(), a.end(), b.begin(), b.end()); + assert(expected_mismatch == actual_mismatch); + + auto expected_lex = last_known_good_lex_compare(expected_mismatch, a.end(), b.end()); + auto actual_lex = lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + assert(expected_lex == actual_lex); + +#if _HAS_CXX20 + auto ranges_actual_mismatch = ranges::mismatch(a, b); + assert(get<0>(expected_mismatch) == ranges_actual_mismatch.in1); + assert(get<1>(expected_mismatch) == ranges_actual_mismatch.in2); + + auto ranges_actual_lex = ranges::lexicographical_compare(a, b); + assert(expected_lex == ranges_actual_lex); + + auto expected_lex_3way = last_known_good_lex_compare_3way(expected_mismatch, a.end(), b.end()); + auto actual_lex_3way = lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end()); + assert(expected_lex_3way == actual_lex_3way); +#endif // _HAS_CXX20 +} + +template +void test_mismatch_and_lex_compare_family(mt19937_64& gen) { + constexpr size_t shrinkCount = 4; + constexpr size_t mismatchCount = 10; + using TD = conditional_t; + uniform_int_distribution dis('a', 'z'); + vector input_a; + vector input_b; + input_a.reserve(dataCount); + input_b.reserve(dataCount); + + for (;;) { + // equal + test_case_mismatch_and_lex_compare_family(input_a, input_b); + + // different sizes + for (size_t i = 0; i != shrinkCount && !input_b.empty(); ++i) { + input_b.pop_back(); + test_case_mismatch_and_lex_compare_family(input_a, input_b); + test_case_mismatch_and_lex_compare_family(input_b, input_a); + } + + // actual mismatch (or maybe not, depending on random) + if (!input_b.empty()) { + uniform_int_distribution mismatch_dis(0, input_a.size() - 1); + + for (size_t attempts = 0; attempts < mismatchCount; ++attempts) { + const size_t possible_mismatch_pos = mismatch_dis(gen); + input_a[possible_mismatch_pos] = static_cast(dis(gen)); + test_case_mismatch_and_lex_compare_family(input_a, input_b); + test_case_mismatch_and_lex_compare_family(input_b, input_a); + } + } + + if (input_a.size() == dataCount) { + break; + } + + input_a.push_back(static_cast(dis(gen))); + input_b = input_a; + } +} + +template +void test_mismatch_and_lex_compare_family_containers() { + C1 a{'m', 'e', 'o', 'w', ' ', 'C', 'A', 'T', 'S'}; + C2 b{'m', 'e', 'o', 'w', ' ', 'K', 'I', 'T', 'T', 'E', 'N', 'S'}; + + const auto result_mismatch_4 = mismatch(a.begin(), a.end(), b.begin(), b.end()); + const auto result_mismatch_3 = mismatch(a.begin(), a.end(), b.begin()); + assert(get<0>(result_mismatch_4) == a.begin() + 5); + assert(get<1>(result_mismatch_4) == b.begin() + 5); + assert(get<0>(result_mismatch_3) == a.begin() + 5); + assert(get<1>(result_mismatch_3) == b.begin() + 5); + + const auto result_lex = lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); + assert(result_lex == true); + +#if _HAS_CXX20 + const auto result_mismatch_r = ranges::mismatch(a, b); + assert(result_mismatch_r.in1 == a.begin() + 5); + assert(result_mismatch_r.in2 == b.begin() + 5); + + const auto result_lex_r = ranges::lexicographical_compare(a, b); + assert(result_lex_r == true); + + const auto result_lex_3way = lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end()); + assert(result_lex_3way == strong_ordering::less); +#endif // _HAS_CXX20 +} + +namespace test_mismatch_sizes_and_alignments { + constexpr size_t range = 33; + constexpr size_t alignment = 32; + +#pragma pack(push, 1) + template + struct with_pad { + char p[PadSize]; + T v[Size]; + }; +#pragma pack(pop) + + template + char stack_array_various_alignments_impl() { + with_pad a = {}; + with_pad b = {}; + assert(mismatch(begin(a.v), end(a.v), begin(b.v), end(b.v)) == make_pair(end(a.v), end(b.v))); + return 0; + } + + template + void stack_array_various_alignments(index_sequence) { + char ignored[] = {stack_array_various_alignments_impl()...}; + (void) ignored; + } + + template + char stack_array_impl() { + T a[Size + 1] = {}; + T b[Size + 1] = {}; + assert(mismatch(begin(a), end(a), begin(b), end(b)) == make_pair(end(a), end(b))); + stack_array_various_alignments(make_index_sequence{}); + return 0; + } + + template + void stack_array(index_sequence) { + char ignored[] = {stack_array_impl()...}; + (void) ignored; + } + + template + void test() { + // stack with different sizes and alignments. ASan would catch out-of-range reads + stack_array(make_index_sequence{}); + + // vector with different sizes. ASan vector annotations would catch out-of-range reads + for (size_t i = 0; i != range; ++i) { + vector a(i, 0); + vector b(i, 0); + assert(mismatch(begin(a), end(a), begin(b), end(b)) == make_pair(end(a), end(b))); + } + + // heap with different sizes. ASan would catch out-of-range reads + for (size_t i = 0; i != range; ++i) { + T* a = static_cast(calloc(i, sizeof(T))); + T* b = static_cast(calloc(i, sizeof(T))); + assert(mismatch(a, a + i, b, b + i) == make_pair(a + i, b + i)); + free(a); + free(b); + } + + // subarray from stack array. We would have wrong results if we run out of the range. + T a[range + 1] = {}; + T b[range + 1] = {}; + for (size_t i = 0; i != range; ++i) { + a[i + 1] = 1; + // whole range mismatch finds mismatch after past-the-end of the subarray + assert(mismatch(a, a + range + 1, b, b + range + 1) == make_pair(a + i + 1, b + i + 1)); + // limited range mismatch gets to past-the-end of the subarray + assert(mismatch(a, a + i, b, b + i) == make_pair(a + i, b + i)); + a[i + 1] = 0; + } + } +} // namespace test_mismatch_sizes_and_alignments + +void test_vector_algorithms(mt19937_64& gen) { + test_mismatch_and_lex_compare_family(gen); + test_mismatch_and_lex_compare_family(gen); + test_mismatch_and_lex_compare_family(gen); + test_mismatch_and_lex_compare_family(gen); + test_mismatch_and_lex_compare_family(gen); + test_mismatch_and_lex_compare_family(gen); + test_mismatch_and_lex_compare_family(gen); + test_mismatch_and_lex_compare_family(gen); + test_mismatch_and_lex_compare_family(gen); + + test_mismatch_and_lex_compare_family_containers, vector>(); + test_mismatch_and_lex_compare_family_containers, vector>(); + test_mismatch_and_lex_compare_family_containers, vector>(); + test_mismatch_and_lex_compare_family_containers, const vector>(); + test_mismatch_and_lex_compare_family_containers, const vector>(); + test_mismatch_and_lex_compare_family_containers, vector>(); + test_mismatch_and_lex_compare_family_containers, vector>(); + + test_mismatch_sizes_and_alignments::test(); + test_mismatch_sizes_and_alignments::test(); + test_mismatch_sizes_and_alignments::test(); + test_mismatch_sizes_and_alignments::test(); +} + +int main() { + run_randomized_tests_with_different_isa_levels(test_vector_algorithms); +} From b287e6f50b74958eba5d782286aa52012dcf0d73 Mon Sep 17 00:00:00 2001 From: Ksar Date: Sat, 9 Nov 2024 01:30:34 +0800 Subject: [PATCH 06/16] Update _MSVC_STL_UPDATE to November 2024 (#5064) --- stl/inc/yvals_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 52c6f689d2..d242f28ea9 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -913,7 +913,7 @@ #define _CPPLIB_VER 650 #define _MSVC_STL_VERSION 143 -#define _MSVC_STL_UPDATE 202410L +#define _MSVC_STL_UPDATE 202411L #ifndef _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH #if defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) From 532670b0faa332633482451d738d3bad28dcecd3 Mon Sep 17 00:00:00 2001 From: Ksar Date: Sat, 9 Nov 2024 01:32:14 +0800 Subject: [PATCH 07/16] Clarify `optional::swap` conditions (#5065) Co-authored-by: Casey Carter --- stl/inc/optional | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/stl/inc/optional b/stl/inc/optional index b6d4bcc69f..b65045b016 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -349,10 +349,12 @@ public: _CONSTEXPR20 void swap(optional& _Right) noexcept(is_nothrow_move_constructible_v<_Ty> && is_nothrow_swappable_v<_Ty>) { - static_assert(is_move_constructible_v<_Ty>, - "optional::swap requires T to be move constructible (N4950 [optional.swap]/1)."); - static_assert(!is_move_constructible_v<_Ty> || is_swappable_v<_Ty>, - "optional::swap requires T to be swappable (N4950 [optional.swap]/2)."); + if constexpr (is_move_constructible_v<_Ty>) { + static_assert( + is_swappable_v<_Ty>, "optional::swap requires T to be swappable (N4993 [optional.swap]/2)."); + } else { + static_assert(false, "optional::swap requires T to be move constructible (N4993 [optional.swap]/1)."); + } using _STD swap; if constexpr (_Is_trivially_swappable_v<_Ty>) { using _TrivialBaseTy = _Optional_destruct_base<_Ty>; From 25dc2b72b6f594326253cf3a05543f7a5750f802 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 9 Nov 2024 01:39:15 +0800 Subject: [PATCH 08/16] ``: Hide some non-Standard functions of `locale::id` (#5067) Co-authored-by: Stephan T. Lavavej --- stl/inc/locale | 2 +- stl/inc/xlocale | 22 ++++++++++++++----- stl/src/locale.cpp | 4 ++-- stl/src/locale0.cpp | 10 ++++----- stl/src/wlocale.cpp | 6 ++--- stl/src/xlocale.cpp | 4 ++-- .../Dev09_056375_locale_cleanup/test.cpp | 18 +++++++++++++++ 7 files changed, 48 insertions(+), 18 deletions(-) diff --git a/stl/inc/locale b/stl/inc/locale index 7439424258..73f075b227 100644 --- a/stl/inc/locale +++ b/stl/inc/locale @@ -157,7 +157,7 @@ protected: _EXPORT_STD template _NODISCARD bool has_facet(const locale& _Loc) noexcept { _BEGIN_LOCK(_LOCK_LOCALE) // the thread lock, make get atomic - size_t _Id = _Facet::id; + size_t _Id = _Facet::id._Get_index(); return _Loc._Getfacet(_Id) || _Facet::_Getcat() != static_cast(-1); _END_LOCK() } diff --git a/stl/inc/xlocale b/stl/inc/xlocale index f1f84c8bc7..40f3719d52 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -74,12 +74,18 @@ public: class _CRTIMP2_PURE_IMPORT id { // identifier stamp, unique for each distinct kind of facet public: +#ifdef _CRTBLD // TRANSITION, ABI: preserved for binary compatibility __CLR_OR_THIS_CALL id(size_t _Val = 0) : _Id(_Val) {} +#else // ^^^ defined(_CRTBLD) / !defined(_CRTBLD) vvv + template // TRANSITION, ABI + id() noexcept /* strengthened */ {} +#endif // ^^^ !defined(_CRTBLD) ^^^ id(const id&) = delete; id& operator=(const id&) = delete; - __CLR_OR_THIS_CALL operator size_t() { // get stamp, with lazy allocation + template // TRANSITION, ABI + size_t _Get_index() { // get stamp, with lazy allocation if (_Id == 0) { // still zero, allocate stamp _BEGIN_LOCK(_LOCK_LOCALE) if (_Id == 0) { @@ -90,8 +96,14 @@ public: return _Id; } +#ifdef _CRTBLD // TRANSITION, ABI: preserved for binary compatibility + __CLR_OR_THIS_CALL operator size_t() { + return _Get_index(); + } +#endif // defined(_CRTBLD) + private: - size_t _Id; // the identifier stamp + size_t _Id = 0; // the identifier stamp __PURE_APPDOMAIN_GLOBAL static int _Id_cnt; }; @@ -223,7 +235,7 @@ public: _CATCH_END _Locimp* _Newimp = _Locimp::_New_Locimp(*_Ptr); - _Newimp->_Addfac(_Facptr, _Facet::id); + _Newimp->_Addfac(_Facptr, _Facet::id._Get_index()); _Newimp->_Catmask = none; _Newimp->_Name = "*"; return locale{_Secret_locale_construct_tag{}, _Newimp}; @@ -232,7 +244,7 @@ public: template locale(const locale& _Loc, const _Facet* _Facptr) : _Ptr(_Locimp::_New_Locimp(*_Loc._Ptr)) { if (_Facptr) { // replace facet - _Ptr->_Addfac(const_cast<_Facet*>(_Facptr), _Facet::id); + _Ptr->_Addfac(const_cast<_Facet*>(_Facptr), _Facet::id._Get_index()); _Ptr->_Catmask = none; _Ptr->_Name = "*"; } @@ -421,7 +433,7 @@ const _Facet& __CRTDECL use_facet(const locale& _Loc) { // get facet reference f _BEGIN_LOCK(_LOCK_LOCALE) // the thread lock, make get atomic const locale::facet* _Psave = _Facetptr<_Facet>::_Psave; // static pointer to lazy facet - const size_t _Id = _Facet::id; + const size_t _Id = _Facet::id._Get_index(); const locale::facet* _Pf = _Loc._Getfacet(_Id); if (!_Pf) { diff --git a/stl/src/locale.cpp b/stl/src/locale.cpp index 4c607cf5d8..8dc8f4a1f0 100644 --- a/stl/src/locale.cpp +++ b/stl/src/locale.cpp @@ -47,11 +47,11 @@ _MRTIMP2_PURE locale __CLRCALL_PURE_OR_CDECL locale::global(const locale& loc) { if ((_CATMASK(Facet::_Getcat()) & cat) == 0) { \ ; \ } else if (ptrloc == nullptr) { \ - ptrimp->_Addfac(new Facet(lobj), Facet::id); \ + ptrimp->_Addfac(new Facet(lobj), Facet::id._Get_index()); \ } else { \ ptrimp->_Addfac( \ const_cast(static_cast(&_STD use_facet(*ptrloc))), \ - Facet::id); \ + Facet::id._Get_index()); \ } using _Tc1 = ctype; diff --git a/stl/src/locale0.cpp b/stl/src/locale0.cpp index 74ef152f0c..032dbb2d98 100644 --- a/stl/src/locale0.cpp +++ b/stl/src/locale0.cpp @@ -125,15 +125,15 @@ __PURE_APPDOMAIN_GLOBAL locale::_Locimp* locale::_Locimp::_Clocptr = nullptr; // __PURE_APPDOMAIN_GLOBAL int locale::id::_Id_cnt = 0; // unique id counter for facets -__PURE_APPDOMAIN_GLOBAL locale::id ctype::id(0); +__PURE_APPDOMAIN_GLOBAL locale::id ctype::id{}; -__PURE_APPDOMAIN_GLOBAL locale::id ctype::id(0); +__PURE_APPDOMAIN_GLOBAL locale::id ctype::id{}; -__PURE_APPDOMAIN_GLOBAL locale::id codecvt::id(0); +__PURE_APPDOMAIN_GLOBAL locale::id codecvt::id{}; -__PURE_APPDOMAIN_GLOBAL locale::id ctype::id(0); +__PURE_APPDOMAIN_GLOBAL locale::id ctype::id{}; -__PURE_APPDOMAIN_GLOBAL locale::id codecvt::id(0); +__PURE_APPDOMAIN_GLOBAL locale::id codecvt::id{}; _MRTIMP2_PURE const locale& __CLRCALL_PURE_OR_CDECL locale::classic() { // get reference to "C" locale #if !defined(_M_CEE_PURE) diff --git a/stl/src/wlocale.cpp b/stl/src/wlocale.cpp index b0648b54db..8c33f321ab 100644 --- a/stl/src/wlocale.cpp +++ b/stl/src/wlocale.cpp @@ -15,11 +15,11 @@ _STD_BEGIN if ((_CATMASK(Facet::_Getcat()) & cat) == 0) { \ ; \ } else if (ptrloc == nullptr) { \ - ptrimp->_Addfac(new Facet(lobj), Facet::id); \ + ptrimp->_Addfac(new Facet(lobj), Facet::id._Get_index()); \ } else { \ ptrimp->_Addfac( \ const_cast(static_cast(&_STD use_facet(*ptrloc))), \ - Facet::id); \ + Facet::id._Get_index()); \ } // moved from locale to ease subsetting @@ -36,7 +36,7 @@ using _Tw10 = moneypunct; using _Tw11 = time_get; using _Tw12 = time_put; using _Tw13 = codecvt; -__PURE_APPDOMAIN_GLOBAL locale::id time_put::id(0); +__PURE_APPDOMAIN_GLOBAL locale::id time_put::id{}; void __CLRCALL_OR_CDECL locale::_Locimp::_Makewloc(const _Locinfo& lobj, locale::category cat, _Locimp* ptrimp, const locale* ptrloc) { // setup wide part of a new locale diff --git a/stl/src/xlocale.cpp b/stl/src/xlocale.cpp index 24185c36d4..6ba71b0d02 100644 --- a/stl/src/xlocale.cpp +++ b/stl/src/xlocale.cpp @@ -15,11 +15,11 @@ _STD_BEGIN if ((_CATMASK(Facet::_Getcat()) & cat) == 0) { \ ; \ } else if (ptrloc == nullptr) { \ - ptrimp->_Addfac(new Facet(lobj), Facet::id); \ + ptrimp->_Addfac(new Facet(lobj), Facet::id._Get_index()); \ } else { \ ptrimp->_Addfac( \ const_cast(static_cast(&_STD use_facet(*ptrloc))), \ - Facet::id); \ + Facet::id._Get_index()); \ } // moved from locale to ease subsetting diff --git a/tests/std/tests/Dev09_056375_locale_cleanup/test.cpp b/tests/std/tests/Dev09_056375_locale_cleanup/test.cpp index 7d0c000ae6..0e8f1b29da 100644 --- a/tests/std/tests/Dev09_056375_locale_cleanup/test.cpp +++ b/tests/std/tests/Dev09_056375_locale_cleanup/test.cpp @@ -6,7 +6,9 @@ #include #include +#include #include +#include #pragma warning(push) // TRANSITION, OS-23694920 #pragma warning(disable : 4668) // 'MEOW' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' @@ -47,6 +49,22 @@ STATIC_ASSERT(!is_implicitly_default_constructible); STATIC_ASSERT(!is_implicitly_default_constructible>); STATIC_ASSERT(!is_implicitly_default_constructible>); +// Test mandatory locale::id properties and strengthened exception specification. +STATIC_ASSERT(is_nothrow_default_constructible_v); // strengthened +STATIC_ASSERT(!is_copy_constructible_v); +STATIC_ASSERT(!is_move_constructible_v); +STATIC_ASSERT(!is_copy_assignable_v); +STATIC_ASSERT(!is_move_assignable_v); +STATIC_ASSERT(is_nothrow_destructible_v); + +// Test that non-Standard locale::id constructor and conversion function are not user-visible. +STATIC_ASSERT(!is_constructible_v); +STATIC_ASSERT(!is_constructible_v); +STATIC_ASSERT(!is_constructible_v); +STATIC_ASSERT(!is_convertible_v); +STATIC_ASSERT(!is_convertible_v); +STATIC_ASSERT(!is_convertible_v); + void test_dll() { puts("Calling dll"); #ifdef _M_CEE From dec656913ca72826329912afb9ff1afe9ed49742 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 14 Nov 2024 12:08:53 -0800 Subject: [PATCH 09/16] Fix `filesystem::directory_entry::refresh` on Win11 24H2 (#5077) --- stl/inc/xfilesystem_abi.h | 2 ++ tests/std/tests/P0218R1_filesystem/test.cpp | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/stl/inc/xfilesystem_abi.h b/stl/inc/xfilesystem_abi.h index f11c87024c..2813e99951 100644 --- a/stl/inc/xfilesystem_abi.h +++ b/stl/inc/xfilesystem_abi.h @@ -33,6 +33,7 @@ enum class __std_win_error : unsigned long { _Sharing_violation = 32, // #define ERROR_SHARING_VIOLATION 32L _Not_supported = 50, // #define ERROR_NOT_SUPPORTED 50L _Error_bad_netpath = 53, // #define ERROR_BAD_NETPATH 53L + _Error_netname_deleted = 64, // #define ERROR_NETNAME_DELETED 64L _File_exists = 80, // #define ERROR_FILE_EXISTS 80L _Invalid_parameter = 87, // #define ERROR_INVALID_PARAMETER 87L _Insufficient_buffer = 122, // #define ERROR_INSUFFICIENT_BUFFER 122L @@ -54,6 +55,7 @@ _NODISCARD inline bool __std_is_file_not_found(const __std_win_error _Error) noe case __std_win_error::_Error_bad_netpath: case __std_win_error::_Invalid_name: case __std_win_error::_Directory_name_is_invalid: // Windows 11 24H2 + case __std_win_error::_Error_netname_deleted: // Windows 11 24H2 return true; default: return false; diff --git a/tests/std/tests/P0218R1_filesystem/test.cpp b/tests/std/tests/P0218R1_filesystem/test.cpp index 7f656e02a7..ef3e44f79c 100644 --- a/tests/std/tests/P0218R1_filesystem/test.cpp +++ b/tests/std/tests/P0218R1_filesystem/test.cpp @@ -4082,11 +4082,15 @@ int wmain(int argc, wchar_t* argv[]) { try { return run_all_tests(argc, argv); } catch (const filesystem_error& fe) { - cout << "filesystem_error: " << fe.what() << endl; + cout << "Caught filesystem_error." << endl; + cout << " what: " << fe.what() << endl; + cout << " value: " << fe.code().value() << endl; + cout << "category: " << fe.code().category().name() << endl; } catch (const exception& e) { - cout << "exception: " << e.what() << endl; + cout << "Caught exception." << endl; + cout << "what: " << e.what() << endl; } catch (...) { - cout << "Unknown exception." << endl; + cout << "Caught unknown exception." << endl; } return EXIT_FAILURE; From b9eeaa85141a614d3eeb1a4de46b72f2ce790f61 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 14 Nov 2024 12:16:25 -0800 Subject: [PATCH 10/16] Toolset update: VS 2022 17.13 Preview 1, Windows Server 2025 (#5082) --- CMakeLists.txt | 2 +- README.md | 8 ++++---- azure-devops/config.yml | 2 +- azure-devops/create-1es-hosted-pool.ps1 | 2 +- azure-devops/provision-image.ps1 | 2 +- benchmarks/CMakeLists.txt | 2 +- tools/CMakeLists.txt | 2 +- tools/format/CMakeLists.txt | 2 +- tools/validate/CMakeLists.txt | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f85527c87f..9d6f36924e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.29.0) +cmake_minimum_required(VERSION 3.30.0) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) project(msvc_standard_libraries LANGUAGES CXX) diff --git a/README.md b/README.md index 82aa03604e..354a729e36 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem # How To Build With The Visual Studio IDE -1. Install Visual Studio 2022 17.12 Preview 3 or later. +1. Install Visual Studio 2022 17.13 Preview 1 or later. * Select "Windows 11 SDK (10.0.22621.0)" in the VS Installer. * Select "MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (Latest)" in the VS Installer if you would like to build the ARM64/ARM64EC target. @@ -149,7 +149,7 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem if you would like to build the ARM target. * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. This will ensure that you're using supported versions of CMake and Ninja. - * Otherwise, install [CMake][] 3.29.0 or later, and [Ninja][] 1.12.1 or later. + * Otherwise, install [CMake][] 3.30.0 or later, and [Ninja][] 1.12.1 or later. * Make sure [Python][] 3.13 or later is available to CMake. 2. Open Visual Studio, and choose the "Clone or check out code" option. Enter the URL of this repository, `https://github.com/microsoft/STL`. @@ -160,7 +160,7 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem # How To Build With A Native Tools Command Prompt -1. Install Visual Studio 2022 17.12 Preview 3 or later. +1. Install Visual Studio 2022 17.13 Preview 1 or later. * Select "Windows 11 SDK (10.0.22621.0)" in the VS Installer. * Select "MSVC v143 - VS 2022 C++ ARM64/ARM64EC build tools (Latest)" in the VS Installer if you would like to build the ARM64/ARM64EC target. @@ -168,7 +168,7 @@ Just try to follow these rules, so we can spend more time fixing bugs and implem if you would like to build the ARM target. * We recommend selecting "C++ CMake tools for Windows" in the VS Installer. This will ensure that you're using supported versions of CMake and Ninja. - * Otherwise, install [CMake][] 3.29.0 or later, and [Ninja][] 1.12.1 or later. + * Otherwise, install [CMake][] 3.30.0 or later, and [Ninja][] 1.12.1 or later. * Make sure [Python][] 3.13 or later is available to CMake. 2. Open a command prompt. 3. Change directories to a location where you'd like a clone of this STL repository. diff --git a/azure-devops/config.yml b/azure-devops/config.yml index 2080005861..2c81cfd639 100644 --- a/azure-devops/config.yml +++ b/azure-devops/config.yml @@ -5,7 +5,7 @@ variables: - name: poolName - value: 'StlBuild-2024-10-15T1118-Pool' + value: 'StlBuild-2024-11-12T1255-Pool' readonly: true - name: poolDemands value: 'EnableSpotVM -equals false' diff --git a/azure-devops/create-1es-hosted-pool.ps1 b/azure-devops/create-1es-hosted-pool.ps1 index 307c511a7c..0ac42dded3 100644 --- a/azure-devops/create-1es-hosted-pool.ps1 +++ b/azure-devops/create-1es-hosted-pool.ps1 @@ -18,7 +18,7 @@ $VMSize = 'Standard_D32ads_v5' $ProtoVMName = 'PROTOTYPE' $ImagePublisher = 'MicrosoftWindowsServer' $ImageOffer = 'WindowsServer' -$ImageSku = '2022-datacenter-g2' +$ImageSku = '2025-datacenter-g2' $ProgressActivity = 'Preparing STL CI pool' $TotalProgress = 26 diff --git a/azure-devops/provision-image.ps1 b/azure-devops/provision-image.ps1 index 94ecd3de0d..344fbb7b8e 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -40,7 +40,7 @@ foreach ($workload in $VisualStudioWorkloads) { } # https://github.com/PowerShell/PowerShell/releases/latest -$PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.4.5/PowerShell-7.4.5-win-x64.msi' +$PowerShellUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.4.6/PowerShell-7.4.6-win-x64.msi' $PowerShellArgs = @('/quiet', '/norestart') $PythonUrl = 'https://www.python.org/ftp/python/3.13.0/python-3.13.0-amd64.exe' diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 122d11879b..edc5309b14 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.29.0) +cmake_minimum_required(VERSION 3.30.0) project(msvc_standard_libraries_benchmarks LANGUAGES CXX) if(DEFINED STL_BINARY_DIR) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 73d6727320..91d829a60c 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.29.0) +cmake_minimum_required(VERSION 3.30.0) project(msvc_standard_libraries_tools LANGUAGES CXX) add_subdirectory(format) diff --git a/tools/format/CMakeLists.txt b/tools/format/CMakeLists.txt index 59ba6df7c1..6be5aac78b 100644 --- a/tools/format/CMakeLists.txt +++ b/tools/format/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.29.0) +cmake_minimum_required(VERSION 3.30.0) project(msvc_standard_libraries_format NONE) find_program(CLANG_FORMAT diff --git a/tools/validate/CMakeLists.txt b/tools/validate/CMakeLists.txt index 5d2d5f34d7..175103401f 100644 --- a/tools/validate/CMakeLists.txt +++ b/tools/validate/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 3.29.0) +cmake_minimum_required(VERSION 3.30.0) project(msvc_standard_libraries_validate LANGUAGES CXX) add_executable(validate-binary validate.cpp) From 7657fb0ffaa54962c1379ffb6b1176f8c5e165f4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 14 Nov 2024 12:18:52 -0800 Subject: [PATCH 11/16] Vectorize `basic_string::rfind` (the string needle overload) (#5057) Co-authored-by: Stephan T. Lavavej --- benchmarks/src/search.cpp | 56 ++++++++++++++----- stl/inc/__msvc_string_view.hpp | 23 +++++++- stl/inc/algorithm | 18 ------ stl/inc/xutility | 18 ++++++ .../VSO_0000000_vector_algorithms/test.cpp | 22 ++++++++ 5 files changed, 103 insertions(+), 34 deletions(-) diff --git a/benchmarks/src/search.cpp b/benchmarks/src/search.cpp index ad026b994f..4540860c92 100644 --- a/benchmarks/src/search.cpp +++ b/benchmarks/src/search.cpp @@ -12,8 +12,9 @@ #include #include "lorem.hpp" -using namespace std::string_view_literals; +#include "skewed_allocator.hpp" +using namespace std::string_view_literals; template constexpr auto make_fill_pattern_array() { @@ -48,12 +49,18 @@ constexpr data_and_pattern patterns[] = { /* 5. Large, evil */ {fill_pattern_view<3000, false>, fill_pattern_view<20, true>}, }; +template +using not_highly_aligned_basic_string = std::basic_string, not_highly_aligned_allocator>; + +using not_highly_aligned_string = not_highly_aligned_basic_string; +using not_highly_aligned_wstring = not_highly_aligned_basic_string; + void c_strstr(benchmark::State& state) { const auto& src_haystack = patterns[static_cast(state.range())].data; const auto& src_needle = patterns[static_cast(state.range())].pattern; - const std::string haystack(src_haystack); - const std::string needle(src_needle); + const not_highly_aligned_string haystack(src_haystack); + const not_highly_aligned_string needle(src_needle); for (auto _ : state) { benchmark::DoNotOptimize(haystack); @@ -68,8 +75,8 @@ void classic_search(benchmark::State& state) { const auto& src_haystack = patterns[static_cast(state.range())].data; const auto& src_needle = patterns[static_cast(state.range())].pattern; - const std::vector haystack(src_haystack.begin(), src_haystack.end()); - const std::vector needle(src_needle.begin(), src_needle.end()); + const std::vector> haystack(src_haystack.begin(), src_haystack.end()); + const std::vector> needle(src_needle.begin(), src_needle.end()); for (auto _ : state) { benchmark::DoNotOptimize(haystack); @@ -84,8 +91,8 @@ void ranges_search(benchmark::State& state) { const auto& src_haystack = patterns[static_cast(state.range())].data; const auto& src_needle = patterns[static_cast(state.range())].pattern; - const std::vector haystack(src_haystack.begin(), src_haystack.end()); - const std::vector needle(src_needle.begin(), src_needle.end()); + const std::vector> haystack(src_haystack.begin(), src_haystack.end()); + const std::vector> needle(src_needle.begin(), src_needle.end()); for (auto _ : state) { benchmark::DoNotOptimize(haystack); @@ -100,8 +107,8 @@ void search_default_searcher(benchmark::State& state) { const auto& src_haystack = patterns[static_cast(state.range())].data; const auto& src_needle = patterns[static_cast(state.range())].pattern; - const std::vector haystack(src_haystack.begin(), src_haystack.end()); - const std::vector needle(src_needle.begin(), src_needle.end()); + const std::vector> haystack(src_haystack.begin(), src_haystack.end()); + const std::vector> needle(src_needle.begin(), src_needle.end()); for (auto _ : state) { benchmark::DoNotOptimize(haystack); @@ -132,8 +139,8 @@ void classic_find_end(benchmark::State& state) { const auto& src_haystack = patterns[static_cast(state.range())].data; const auto& src_needle = patterns[static_cast(state.range())].pattern; - const std::vector haystack(src_haystack.begin(), src_haystack.end()); - const std::vector needle(src_needle.begin(), src_needle.end()); + const std::vector> haystack(src_haystack.begin(), src_haystack.end()); + const std::vector> needle(src_needle.begin(), src_needle.end()); for (auto _ : state) { benchmark::DoNotOptimize(haystack); @@ -148,8 +155,8 @@ void ranges_find_end(benchmark::State& state) { const auto& src_haystack = patterns[static_cast(state.range())].data; const auto& src_needle = patterns[static_cast(state.range())].pattern; - const std::vector haystack(src_haystack.begin(), src_haystack.end()); - const std::vector needle(src_needle.begin(), src_needle.end()); + const std::vector> haystack(src_haystack.begin(), src_haystack.end()); + const std::vector> needle(src_needle.begin(), src_needle.end()); for (auto _ : state) { benchmark::DoNotOptimize(haystack); @@ -159,6 +166,22 @@ void ranges_find_end(benchmark::State& state) { } } +template +void member_rfind(benchmark::State& state) { + const auto& src_haystack = patterns[static_cast(state.range())].data; + const auto& src_needle = patterns[static_cast(state.range())].pattern; + + const T haystack(src_haystack.begin(), src_haystack.end()); + const T needle(src_needle.begin(), src_needle.end()); + + for (auto _ : state) { + benchmark::DoNotOptimize(haystack); + benchmark::DoNotOptimize(needle); + auto res = haystack.rfind(needle); + benchmark::DoNotOptimize(res); + } +} + void common_args(auto bm) { bm->DenseRange(0, std::size(patterns) - 1, 1); } @@ -174,8 +197,8 @@ BENCHMARK(ranges_search)->Apply(common_args); BENCHMARK(search_default_searcher)->Apply(common_args); BENCHMARK(search_default_searcher)->Apply(common_args); -BENCHMARK(member_find)->Apply(common_args); -BENCHMARK(member_find)->Apply(common_args); +BENCHMARK(member_find)->Apply(common_args); +BENCHMARK(member_find)->Apply(common_args); BENCHMARK(classic_find_end)->Apply(common_args); BENCHMARK(classic_find_end)->Apply(common_args); @@ -183,4 +206,7 @@ BENCHMARK(classic_find_end)->Apply(common_args); BENCHMARK(ranges_find_end)->Apply(common_args); BENCHMARK(ranges_find_end)->Apply(common_args); +BENCHMARK(member_rfind)->Apply(common_args); +BENCHMARK(member_rfind)->Apply(common_args); + BENCHMARK_MAIN(); diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index a0a4d6f009..75ac8b6249 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -683,7 +683,28 @@ constexpr size_t _Traits_rfind(_In_reads_(_Hay_size) const _Traits_ptr_t<_Traits return static_cast(-1); } - for (auto _Match_try = _Haystack + (_STD min)(_Start_at, _Hay_size - _Needle_size);; --_Match_try) { + const size_t _Actual_start_at = (_STD min)(_Start_at, _Hay_size - _Needle_size); + +#if _USE_STD_VECTOR_ALGORITHMS + if constexpr (_Is_implementation_handled_char_traits<_Traits> && sizeof(typename _Traits::char_type) <= 2) { + if (!_STD _Is_constant_evaluated()) { + // _Find_end_vectorized takes into account the needle length when locating the search start. + // As a potentially earlier start position can be specified, we need to take it into account, + // and pick between the maximum possible start position and the specified one, + // and then add _Needle_size, so that it is subtracted back in _Find_end_vectorized. + const auto _End = _Haystack + _Actual_start_at + _Needle_size; + const auto _Ptr = _STD _Find_end_vectorized(_Haystack, _End, _Needle, _Needle_size); + + if (_Ptr != _End) { + return static_cast(_Ptr - _Haystack); + } else { + return static_cast(-1); + } + } + } +#endif // _USE_STD_VECTOR_ALGORITHMS + + for (auto _Match_try = _Haystack + _Actual_start_at;; --_Match_try) { if (_Traits::eq(*_Match_try, *_Needle) && _Traits::compare(_Match_try, _Needle, _Needle_size) == 0) { return static_cast(_Match_try - _Haystack); // found a match } diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 23d74b52f6..40f3f965d2 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -59,11 +59,6 @@ const void* __stdcall __std_find_last_trivial_2(const void* _First, const void* const void* __stdcall __std_find_last_trivial_4(const void* _First, const void* _Last, uint32_t _Val) noexcept; const void* __stdcall __std_find_last_trivial_8(const void* _First, const void* _Last, uint64_t _Val) noexcept; -const void* __stdcall __std_find_end_1( - const void* _First1, const void* _Last1, const void* _First2, size_t _Count2) noexcept; -const void* __stdcall __std_find_end_2( - const void* _First1, const void* _Last1, const void* _First2, size_t _Count2) noexcept; - __declspec(noalias) _Min_max_1i __stdcall __std_minmax_1i(const void* _First, const void* _Last) noexcept; __declspec(noalias) _Min_max_1u __stdcall __std_minmax_1u(const void* _First, const void* _Last) noexcept; __declspec(noalias) _Min_max_2i __stdcall __std_minmax_2i(const void* _First, const void* _Last) noexcept; @@ -194,19 +189,6 @@ _Ty* _Find_last_vectorized(_Ty* const _First, _Ty* const _Last, const _TVal _Val } } -template -_Ty1* _Find_end_vectorized( - _Ty1* const _First1, _Ty1* const _Last1, _Ty2* const _First2, const size_t _Count2) noexcept { - _STL_INTERNAL_STATIC_ASSERT(sizeof(_Ty1) == sizeof(_Ty2)); - if constexpr (sizeof(_Ty1) == 1) { - return const_cast<_Ty1*>(static_cast(::__std_find_end_1(_First1, _Last1, _First2, _Count2))); - } else if constexpr (sizeof(_Ty1) == 2) { - return const_cast<_Ty1*>(static_cast(::__std_find_end_2(_First1, _Last1, _First2, _Count2))); - } else { - _STL_INTERNAL_STATIC_ASSERT(false); // unexpected size - } -} - template __declspec(noalias) void _Replace_vectorized( _Ty* const _First, _Ty* const _Last, const _TVal1 _Old_val, const _TVal2 _New_val) noexcept { diff --git a/stl/inc/xutility b/stl/inc/xutility index f9793535d6..04bdd476df 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -107,6 +107,11 @@ const void* __stdcall __std_search_1( const void* __stdcall __std_search_2( const void* _First1, const void* _Last1, const void* _First2, size_t _Count2) noexcept; +const void* __stdcall __std_find_end_1( + const void* _First1, const void* _Last1, const void* _First2, size_t _Count2) noexcept; +const void* __stdcall __std_find_end_2( + const void* _First1, const void* _Last1, const void* _First2, size_t _Count2) noexcept; + const void* __stdcall __std_min_element_1(const void* _First, const void* _Last, bool _Signed) noexcept; const void* __stdcall __std_min_element_2(const void* _First, const void* _Last, bool _Signed) noexcept; const void* __stdcall __std_min_element_4(const void* _First, const void* _Last, bool _Signed) noexcept; @@ -248,6 +253,19 @@ _Ty1* _Search_vectorized(_Ty1* const _First1, _Ty1* const _Last1, _Ty2* const _F } } +template +_Ty1* _Find_end_vectorized( + _Ty1* const _First1, _Ty1* const _Last1, _Ty2* const _First2, const size_t _Count2) noexcept { + _STL_INTERNAL_STATIC_ASSERT(sizeof(_Ty1) == sizeof(_Ty2)); + if constexpr (sizeof(_Ty1) == 1) { + return const_cast<_Ty1*>(static_cast(::__std_find_end_1(_First1, _Last1, _First2, _Count2))); + } else if constexpr (sizeof(_Ty1) == 2) { + return const_cast<_Ty1*>(static_cast(::__std_find_end_2(_First1, _Last1, _First2, _Count2))); + } else { + _STL_INTERNAL_STATIC_ASSERT(false); // unexpected size + } +} + template _Ty* _Min_element_vectorized(_Ty* const _First, _Ty* const _Last) noexcept { constexpr bool _Signed = is_signed_v<_Ty>; diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index 54876e3849..e7aec69bea 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -1109,6 +1109,25 @@ void test_case_string_find_str(const basic_string& input_haystack, const basi assert(expected == actual); } +template +void test_case_string_rfind_str(const basic_string& input_haystack, const basic_string& input_needle) { + ptrdiff_t expected; + if (input_needle.empty()) { + expected = static_cast(input_haystack.size()); + } else { + const auto expected_iter = last_known_good_find_end( + input_haystack.begin(), input_haystack.end(), input_needle.begin(), input_needle.end()); + + if (expected_iter != input_haystack.end()) { + expected = expected_iter - input_haystack.begin(); + } else { + expected = -1; + } + } + const auto actual = static_cast(input_haystack.rfind(input_needle)); + assert(expected == actual); +} + template void test_basic_string_dis(mt19937_64& gen, D& dis) { basic_string input_haystack; @@ -1124,12 +1143,14 @@ void test_basic_string_dis(mt19937_64& gen, D& dis) { test_case_string_find_first_of(input_haystack, input_needle); test_case_string_find_last_of(input_haystack, input_needle); test_case_string_find_str(input_haystack, input_needle); + test_case_string_rfind_str(input_haystack, input_needle); for (size_t attempts = 0; attempts < needleDataCount; ++attempts) { input_needle.push_back(static_cast(dis(gen))); test_case_string_find_first_of(input_haystack, input_needle); test_case_string_find_last_of(input_haystack, input_needle); test_case_string_find_str(input_haystack, input_needle); + test_case_string_rfind_str(input_haystack, input_needle); // For large needles the chance of a match is low, so test a guaranteed match if (input_haystack.size() > input_needle.size() * 2) { @@ -1139,6 +1160,7 @@ void test_basic_string_dis(mt19937_64& gen, D& dis) { temp.assign(overwritten_first, overwritten_first + static_cast(input_needle.size())); copy(input_needle.begin(), input_needle.end(), overwritten_first); test_case_string_find_str(input_haystack, input_needle); + test_case_string_rfind_str(input_haystack, input_needle); copy(temp.begin(), temp.end(), overwritten_first); } } From c18bcea38f4936c5b8b5a958d8d136026fe3a625 Mon Sep 17 00:00:00 2001 From: nikola-sh Date: Thu, 14 Nov 2024 23:22:04 +0300 Subject: [PATCH 12/16] ``: Improve `symlink_status` performance (#5071) Co-authored-by: Stephan T. Lavavej --- benchmarks/CMakeLists.txt | 1 + benchmarks/src/filesystem.cpp | 22 ++++++++++++++++++++++ stl/src/filesystem.cpp | 7 +++++++ 3 files changed, 30 insertions(+) create mode 100644 benchmarks/src/filesystem.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index edc5309b14..4e4f47894e 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -110,6 +110,7 @@ add_benchmark(adjacent_difference src/adjacent_difference.cpp) add_benchmark(bitset_from_string src/bitset_from_string.cpp) add_benchmark(bitset_to_string src/bitset_to_string.cpp) add_benchmark(efficient_nonlocking_print src/efficient_nonlocking_print.cpp) +add_benchmark(filesystem src/filesystem.cpp) add_benchmark(find_and_count src/find_and_count.cpp) add_benchmark(find_first_of src/find_first_of.cpp) add_benchmark(iota src/iota.cpp) diff --git a/benchmarks/src/filesystem.cpp b/benchmarks/src/filesystem.cpp new file mode 100644 index 0000000000..33c8e69e87 --- /dev/null +++ b/benchmarks/src/filesystem.cpp @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +void symlink_status(benchmark::State& state) { + const auto path = std::filesystem::temp_directory_path(); + + for (auto _ : state) { + std::error_code ec; + benchmark::DoNotOptimize(path); + const auto status = std::filesystem::symlink_status(path, ec); + benchmark::DoNotOptimize(status); + benchmark::DoNotOptimize(ec); + } +} + +BENCHMARK(symlink_status); + +BENCHMARK_MAIN(); diff --git a/stl/src/filesystem.cpp b/stl/src/filesystem.cpp index 4ea23edc59..ba05446a1d 100644 --- a/stl/src/filesystem.cpp +++ b/stl/src/filesystem.cpp @@ -900,6 +900,13 @@ namespace { _Flags &= ~_Get_file_attributes_data; } + + if (!_STD _Bitmask_includes_any(_Attributes, __std_fs_file_attr::_Reparse_point) + && _STD _Bitmask_includes_any(_Flags, __std_fs_stats_flags::_Reparse_tag)) { + // if reparse tag is requested by caller but the file is not a reparse point, set tag to _None + _Stats->_Reparse_point_tag = __std_fs_reparse_tag::_None; + _Flags &= ~__std_fs_stats_flags::_Reparse_tag; + } } } From e87ae3761809a45bc3bb55dc9e3c95dd08f9d1c5 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 14 Nov 2024 12:27:52 -0800 Subject: [PATCH 13/16] ``: Silence CodeQL false positive warning (#5072) --- stl/inc/regex | 1 + 1 file changed, 1 insertion(+) diff --git a/stl/inc/regex b/stl/inc/regex index 22bde0c3df..f5f8e75bf4 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -3567,6 +3567,7 @@ bool _Matcher<_BidIt, _Elem, _RxTraits, _It>::_Match_pat(_Node_base* _Nx) { // c { // record current position _Node_capture* _Node = static_cast<_Node_capture*>(_Nx); _Tgt_state._Grps[_Node->_Idx]._Begin = _Tgt_state._Cur; + // CodeQL [SM02323] Comparing unchanging unsigned int _Node->_Idx to decreasing size_t _Idx is safe. for (size_t _Idx = _Tgt_state._Grp_valid.size(); _Node->_Idx < _Idx;) { _Tgt_state._Grp_valid[--_Idx] = false; } From ca1af94c87a811dedda2353e056a3a2b44d83682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20M=C3=BCller?= Date: Thu, 14 Nov 2024 21:31:57 +0100 Subject: [PATCH 14/16] Properly null-terminate output buffer in `basic_istream::get[line]` (#5073) Co-authored-by: Stephan T. Lavavej --- stl/inc/istream | 20 +- tests/libcxx/expected_results.txt | 4 - .../GH_001858_iostream_exception/test.cpp | 254 ++++++++++++++++++ 3 files changed, 272 insertions(+), 6 deletions(-) diff --git a/stl/inc/istream b/stl/inc/istream index 07d8681a84..7e820b16e0 100644 --- a/stl/inc/istream +++ b/stl/inc/istream @@ -17,6 +17,16 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN +template +struct _NODISCARD _Null_terminator_guard { + _Elem** _Str_ref; + ~_Null_terminator_guard() { + if (_Str_ref) { + **_Str_ref = _Elem(); // add terminating null character + } + } +}; + #pragma vtordisp(push, 2) // compiler bug workaround _EXPORT_STD extern "C++" template @@ -367,6 +377,10 @@ public: // get up to _Count characters into NTCS, stop before _Delim ios_base::iostate _State = ios_base::goodbit; _Chcount = 0; + + // ensure null termination of buffer with nonzero length + const _Null_terminator_guard<_Elem> _Guard{0 < _Count ? &_Str : nullptr}; + const sentry _Ok(*this, true); if (_Ok && 0 < _Count) { // state okay, extract characters @@ -388,7 +402,6 @@ public: } _Myios::setstate(_Chcount == 0 ? _State | ios_base::failbit : _State); - *_Str = _Elem(); // add terminating null character return *this; } @@ -450,6 +463,10 @@ public: // get up to _Count characters into NTCS, discard _Delim ios_base::iostate _State = ios_base::goodbit; _Chcount = 0; + + // ensure null termination of buffer with nonzero length + const _Null_terminator_guard<_Elem> _Guard{0 < _Count ? &_Str : nullptr}; + const sentry _Ok(*this, true); if (_Ok && 0 < _Count) { // state okay, use facet to extract @@ -477,7 +494,6 @@ public: _CATCH_IO_END } - *_Str = _Elem(); // add terminating null character _Myios::setstate(_Chcount == 0 ? _State | ios_base::failbit : _State); return *this; } diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 7e690a8242..28d2fc987a 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -488,10 +488,6 @@ std/diagnostics/syserr/syserr.syserr/syserr.syserr.members/ctor_int_error_catego std/diagnostics/syserr/syserr.syserr/syserr.syserr.members/ctor_int_error_category_string.pass.cpp FAIL std/diagnostics/syserr/syserr.syserr/syserr.syserr.members/ctor_int_error_category.pass.cpp FAIL -# libc++ disagrees with libstdc++ and MSVC on whether setstate calls during I/O that throw set failbit; see open issue LWG-2349 -std/input.output/iostream.format/input.streams/istream.unformatted/get_pointer_size_chart.pass.cpp FAIL -std/input.output/iostream.format/input.streams/istream.unformatted/get_pointer_size.pass.cpp FAIL - # Sensitive to implementation details. Assertion failed: test_alloc_base::count == expected_num_allocs std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp FAIL diff --git a/tests/std/tests/GH_001858_iostream_exception/test.cpp b/tests/std/tests/GH_001858_iostream_exception/test.cpp index 5991d5e131..7c23e0ff11 100644 --- a/tests/std/tests/GH_001858_iostream_exception/test.cpp +++ b/tests/std/tests/GH_001858_iostream_exception/test.cpp @@ -3,6 +3,7 @@ #define _SILENCE_CXX17_STRSTREAM_DEPRECATION_WARNING +#include #include #include #include @@ -11,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -148,6 +150,255 @@ void test_istream_exceptions() { } } +template +CharT meow_array; +template <> +constexpr array meow_array = {"meow"}; +template <> +constexpr array meow_array = {L"meow"}; + +// testing GH-5070: basic_istream::get[line](char_type* s, std::streamsize n, char_type delim) +// do not null-terminate the output buffer correctly +template +void test_gh5070_istream_get_null_termination_under_exceptions() { + throwing_buffer buffer; + const basic_string stream_content(1U, meow_array[2]); + + { // get, exception during input extraction, no exception rethrow + basic_istream is(buffer.to_buf()); + auto buf = meow_array; + assert(!is.bad()); + is.get(buf.data(), static_cast(buf.size())); + assert(is.bad()); + assert(buf[0] == CharT()); + } + + { // get, exception during input extraction, exception rethrow enabled + basic_istream is(buffer.to_buf()); + auto buf = meow_array; + is.exceptions(ios_base::badbit); + assert(!is.bad()); + try { + is.get(buf.data(), static_cast(buf.size())); + assert(false); + } catch (const ios_base::failure&) { + assert(false); + } catch (const test_exception&) { + // Expected case + } + assert(is.bad()); + assert(buf[0] == CharT()); + } + + { // get, empty output buffer, no exception raised + basic_istream is(buffer.to_buf()); + auto buf = meow_array; + assert(!is.bad()); + is.get(buf.data(), 0); + assert(is.fail()); + assert(buf[0] == meow_array[0]); + } + + { // get, empty output buffer, exception raised on failbit + basic_istream is(buffer.to_buf()); + auto buf = meow_array; + is.exceptions(ios_base::failbit); + assert(!is.bad()); + try { + is.get(buf.data(), 0); + assert(false); + } catch (const ios_base::failure&) { + // Expected case + } + assert(is.fail()); + assert(buf[0] == meow_array[0]); + } + + { // get, sentry construction fails, no exception raised + basic_stringbuf strbuf{stream_content}; + basic_istream is(&strbuf); + assert(!is.bad()); + + // tests null termination on eof and + // sets eofbit, preparing sentry failure + auto buf1 = meow_array; + is.get(buf1.data(), static_cast(buf1.size())); + assert(is.eof()); + assert(!is.fail()); + assert(buf1[0] == meow_array[2]); + assert(buf1[1] == CharT()); + + // actually tests sentry construction failure + auto buf2 = meow_array; + is.get(buf2.data(), static_cast(buf2.size())); + assert(is.fail()); + assert(buf2[0] == CharT()); + } + + { // get, sentry construction fails, exception raised on failbit + basic_stringbuf strbuf{stream_content}; + basic_istream is(&strbuf); + is.exceptions(ios_base::failbit); + assert(!is.bad()); + + // tests null termination on eof and + // sets eofbit, preparing sentry failure + auto buf1 = meow_array; + is.get(buf1.data(), static_cast(buf1.size())); + assert(is.eof()); + assert(!is.fail()); + assert(buf1[0] == meow_array[2]); + assert(buf1[1] == CharT()); + + // actually tests sentry construction failure + auto buf2 = meow_array; + try { + is.get(buf2.data(), static_cast(buf2.size())); + assert(false); + } catch (const ios_base::failure&) { + // Expected case + } + assert(is.fail()); + assert(buf2[0] == CharT()); + } + + { // get, exception raised on eofbit + basic_stringbuf strbuf{stream_content}; + basic_istream is(&strbuf); + is.exceptions(ios_base::eofbit); + assert(!is.bad()); + + auto buf = meow_array; + try { + is.get(buf.data(), static_cast(buf.size())); + assert(false); + } catch (const ios_base::failure&) { + // Expected case + } + assert(is.eof()); + assert(!is.fail()); + assert(buf[0] == meow_array[2]); + assert(buf[1] == CharT()); + } + + { // getline, exception during input extraction, no exception rethrow + basic_istream is(buffer.to_buf()); + auto buf = meow_array; + assert(!is.bad()); + is.getline(buf.data(), static_cast(buf.size())); + assert(is.bad()); + assert(buf[0] == CharT()); + } + + { // getline, exception during input extraction, exception rethrow enabled + basic_istream is(buffer.to_buf()); + auto buf = meow_array; + is.exceptions(ios_base::badbit); + assert(!is.bad()); + try { + is.getline(buf.data(), static_cast(buf.size())); + assert(false); + } catch (const ios_base::failure&) { + assert(false); + } catch (const test_exception&) { + // Expected case + } + assert(is.bad()); + assert(buf[0] == CharT()); + } + + { // getline, empty output buffer, no exception raised + basic_istream is(buffer.to_buf()); + auto buf = meow_array; + assert(!is.bad()); + is.getline(buf.data(), 0); + assert(is.fail()); + assert(buf[0] == meow_array[0]); + } + + { // getline, empty output buffer, exception raised on failbit + basic_istream is(buffer.to_buf()); + auto buf = meow_array; + is.exceptions(ios_base::failbit); + assert(!is.bad()); + try { + is.getline(buf.data(), 0); + assert(false); + } catch (const ios_base::failure&) { + // Expected case + } + assert(is.fail()); + assert(buf[0] == meow_array[0]); + } + + { // getline, sentry construction fails, no exception raised + basic_stringbuf strbuf{stream_content}; + basic_istream is(&strbuf); + assert(!is.bad()); + + // tests null termination on eof and + // sets eofbit, preparing sentry failure + auto buf1 = meow_array; + is.getline(buf1.data(), static_cast(buf1.size())); + assert(is.eof()); + assert(!is.fail()); + assert(buf1[0] == meow_array[2]); + assert(buf1[1] == CharT()); + + // actually tests sentry construction failure + auto buf2 = meow_array; + is.getline(buf2.data(), static_cast(buf2.size())); + assert(is.fail()); + assert(buf2[0] == CharT()); + } + + { // getline, sentry construction fails, exception raised on failbit + basic_stringbuf strbuf{stream_content}; + basic_istream is(&strbuf); + is.exceptions(ios_base::failbit); + assert(!is.bad()); + + // tests null termination on eof and + // sets eofbit, preparing sentry failure + auto buf1 = meow_array; + is.getline(buf1.data(), static_cast(buf1.size())); + assert(is.eof()); + assert(!is.fail()); + assert(buf1[0] == meow_array[2]); + assert(buf1[1] == CharT()); + + // actually tests sentry construction failure + auto buf2 = meow_array; + try { + is.getline(buf2.data(), static_cast(buf2.size())); + assert(false); + } catch (const ios_base::failure&) { + // Expected case + } + assert(is.fail()); + assert(buf2[0] == CharT()); + } + + { // getline, exception raised on eofbit + basic_stringbuf strbuf{stream_content}; + basic_istream is(&strbuf); + is.exceptions(ios_base::eofbit); + assert(!is.bad()); + + auto buf = meow_array; + try { + is.getline(buf.data(), static_cast(buf.size())); + assert(false); + } catch (const ios_base::failure&) { + // Expected case + } + assert(is.eof()); + assert(!is.fail()); + assert(buf[0] == meow_array[2]); + assert(buf[1] == CharT()); + } +} + template void test_ostream_exceptions() { throwing_buffer buffer; @@ -481,6 +732,9 @@ int main() { test_istream_exceptions(); test_istream_exceptions(); + test_gh5070_istream_get_null_termination_under_exceptions(); + test_gh5070_istream_get_null_termination_under_exceptions(); + test_ostream_exceptions(); test_ostream_exceptions(); } From 6e56c128bbd2694f7ea8403677307bb581883ffc Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 15 Nov 2024 04:40:26 +0800 Subject: [PATCH 15/16] ``: Extend vectorization condition for `_Synth_three_way` (#5078) --- stl/inc/xutility | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/stl/inc/xutility b/stl/inc/xutility index 04bdd476df..df69b60e6c 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -5895,6 +5895,13 @@ struct _Lex_compare_three_way_memcmp_classify_comp<_Elem1, _Elem2, compare_three compare_three_way, void>; }; +template +struct _Lex_compare_three_way_memcmp_classify_comp<_Elem1, _Elem2, _Synth_three_way> { + using _Comp = conditional_t<_Lex_compare_memcmp_classify_elements<_Elem1, _Elem2> + && three_way_comparable_with, + _Synth_three_way, void>; +}; + template struct _Lex_compare_three_way_memcmp_classify_comp<_Elem1, _Elem2, _Strong_order::_Cpo> { using _Comp = From 44a276fdff3463f7e0ab547458850c16925cab06 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 15 Nov 2024 04:47:56 +0800 Subject: [PATCH 16/16] Use `__restrict__` for CUDA (#5079) --- stl/inc/yvals_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index d242f28ea9..a904ea7d01 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -2017,7 +2017,7 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #endif // ^^^ !defined(__cpp_static_call_operator) ^^^ #ifdef __CUDACC__ // TRANSITION, CUDA 12.4 doesn't recognize __restrict -#define _RESTRICT +#define _RESTRICT __restrict__ #else // ^^^ defined(__CUDACC__) / !defined(__CUDACC__) vvv #define _RESTRICT __restrict #endif // ^^^ !defined(__CUDACC__) ^^^