From dfdccda510737c1e5fe8f84d7101df5aec269451 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 21 Feb 2025 15:31:28 -0800 Subject: [PATCH 01/13] STL Hardening (#5274) --- stl/inc/__msvc_string_view.hpp | 18 +- stl/inc/array | 16 +- stl/inc/bitset | 18 +- stl/inc/deque | 51 +- stl/inc/expected | 44 +- stl/inc/forward_list | 8 +- stl/inc/generator | 6 +- stl/inc/list | 12 +- stl/inc/mdspan | 106 +-- stl/inc/mutex | 4 +- stl/inc/optional | 18 +- stl/inc/ranges | 82 +- stl/inc/span | 73 +- stl/inc/valarray | 60 +- stl/inc/vector | 30 +- stl/inc/xstring | 24 +- stl/inc/xutility | 28 +- stl/inc/yvals.h | 117 ++- stl/inc/yvals_core.h | 2 +- tests/libcxx/usual_matrix.lst | 2 +- tests/std/test.lst | 1 + .../std/tests/GH_005090_stl_hardening/env.lst | 6 + .../tests/GH_005090_stl_hardening/test.cpp | 711 ++++++++++++++++++ .../P0009R18_mdspan_extents_death/test.cpp | 6 +- .../test.cpp | 8 +- .../test.cpp | 8 +- .../test.cpp | 6 +- .../P0009R18_mdspan_mdspan_death/test.cpp | 6 +- tests/std/tests/P0122R7_span_death/test.cpp | 10 +- .../std/tests/P0220R1_optional_death/test.cpp | 4 +- tests/std/tests/P0323R12_expected/test.cpp | 2 - .../P0896R4_views_counted_death/test.cpp | 6 +- .../tests/P0896R4_views_drop_death/test.cpp | 6 +- .../P0896R4_views_drop_while_death/test.cpp | 4 +- .../tests/P0896R4_views_filter_death/test.cpp | 7 - .../tests/P0896R4_views_iota_death/test.cpp | 6 +- .../tests/P0896R4_views_take_death/test.cpp | 6 +- .../P0896R4_views_take_while_death/test.cpp | 4 +- .../env.lst | 2 +- .../tests/P1899R3_views_stride_death/test.cpp | 6 - .../test.cpp | 7 - .../tests/P2442R1_views_chunk_death/test.cpp | 7 - .../tests/P2442R1_views_slide_death/test.cpp | 4 +- .../P2443R1_views_chunk_by_death/test.cpp | 7 - .../tests/P2474R2_views_repeat_death/test.cpp | 5 +- .../tests/P2502R2_generator_death/test.cpp | 4 +- .../test.cpp | 4 +- .../VSO_0000000_string_view_idl/test.cpp | 18 +- .../test.cpp | 6 +- .../test.cpp | 17 +- tests/std/tests/modules_20_matrix.lst | 2 +- tests/std/tests/prefix.lst | 2 +- tests/tr1/prefix.lst | 2 +- 53 files changed, 1203 insertions(+), 416 deletions(-) create mode 100644 tests/std/tests/GH_005090_stl_hardening/env.lst create mode 100644 tests/std/tests/GH_005090_stl_hardening/test.cpp diff --git a/stl/inc/__msvc_string_view.hpp b/stl/inc/__msvc_string_view.hpp index 5e973ade480..c078de097fc 100644 --- a/stl/inc/__msvc_string_view.hpp +++ b/stl/inc/__msvc_string_view.hpp @@ -1379,8 +1379,8 @@ class basic_string_view { // wrapper for any kind of contiguous character buffer constexpr basic_string_view( _In_reads_(_Count) const const_pointer _Cts, const size_type _Count) noexcept // strengthened : _Mydata(_Cts), _Mysize(_Count) { -#if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Count == 0 || _Cts, "non-zero size null string_view"); +#if _ITERATOR_DEBUG_LEVEL != 0 + _STL_VERIFY(_Count == 0 || _Cts, "cannot construct a string_view from a null pointer and a non-zero size"); #endif } @@ -1474,7 +1474,7 @@ class basic_string_view { // wrapper for any kind of contiguous character buffer } _NODISCARD constexpr const_reference operator[](const size_type _Off) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING_VIEW || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off < _Mysize, "string_view subscript out of range"); #endif @@ -1489,31 +1489,35 @@ class basic_string_view { // wrapper for any kind of contiguous character buffer } _NODISCARD constexpr const_reference front() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING_VIEW || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize != 0, "front() called on empty string_view"); #endif + return _Mydata[0]; } _NODISCARD constexpr const_reference back() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING_VIEW || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize != 0, "back() called on empty string_view"); #endif + return _Mydata[_Mysize - 1]; } constexpr void remove_prefix(const size_type _Count) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING_VIEW || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize >= _Count, "cannot remove_prefix() larger than string_view size"); #endif + _Mydata += _Count; _Mysize -= _Count; } constexpr void remove_suffix(const size_type _Count) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING_VIEW || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize >= _Count, "cannot remove_suffix() larger than string_view size"); #endif + _Mysize -= _Count; } diff --git a/stl/inc/array b/stl/inc/array index 77bf40f14f1..5be4b29622d 100644 --- a/stl/inc/array +++ b/stl/inc/array @@ -531,7 +531,7 @@ public: } _NODISCARD _CONSTEXPR17 reference operator[](_In_range_(<, _Size) size_type _Pos) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_ARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pos < _Size, "array subscript out of range"); #endif @@ -540,7 +540,7 @@ public: _NODISCARD constexpr const_reference operator[](_In_range_(<, _Size) size_type _Pos) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_ARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pos < _Size, "array subscript out of range"); #endif @@ -707,7 +707,7 @@ public: } _NODISCARD reference operator[](size_type) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_ARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_REPORT_ERROR("array subscript is invalid"); #endif @@ -715,7 +715,7 @@ public: } _NODISCARD const_reference operator[](size_type) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_ARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_REPORT_ERROR("array subscript is invalid"); #endif @@ -723,7 +723,7 @@ public: } _NODISCARD reference front() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_ARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_REPORT_ERROR("array::front() is invalid"); #endif @@ -731,7 +731,7 @@ public: } _NODISCARD const_reference front() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_ARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_REPORT_ERROR("array::front() is invalid"); #endif @@ -739,7 +739,7 @@ public: } _NODISCARD reference back() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_ARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_REPORT_ERROR("array::back() is invalid"); #endif @@ -747,7 +747,7 @@ public: } _NODISCARD const_reference back() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_ARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_REPORT_ERROR("array::back() is invalid"); #endif diff --git a/stl/inc/bitset b/stl/inc/bitset index 7374ea0676b..7792605af47 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -116,14 +116,6 @@ public: }; private: - static constexpr void _Validate(const size_t _Pos) noexcept { // verify that _Pos is within bounds -#if _ITERATOR_DEBUG_LEVEL == 0 - (void) _Pos; -#else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL != 0 vvv - _STL_VERIFY(_Pos < _Bits, "bitset subscript out of range"); -#endif // ^^^ _ITERATOR_DEBUG_LEVEL != 0 ^^^ - } - constexpr bool _Subscript(size_t _Pos) const noexcept { return (_Array[_Pos / _Bitsperword] & (_Ty{1} << _Pos % _Bitsperword)) != 0; } @@ -133,12 +125,18 @@ private: public: _NODISCARD constexpr bool operator[](const size_t _Pos) const noexcept /* strengthened */ { - _Validate(_Pos); +#if _MSVC_STL_HARDENING_BITSET || _ITERATOR_DEBUG_LEVEL != 0 + _STL_VERIFY(_Pos < _Bits, "bitset subscript out of range"); +#endif + return _Subscript(_Pos); } _NODISCARD _CONSTEXPR23 reference operator[](const size_t _Pos) noexcept /* strengthened */ { - _Validate(_Pos); +#if _MSVC_STL_HARDENING_BITSET || _ITERATOR_DEBUG_LEVEL != 0 + _STL_VERIFY(_Pos < _Bits, "bitset subscript out of range"); +#endif + return reference(*this, _Pos); } diff --git a/stl/inc/deque b/stl/inc/deque index cab1a2a804e..b6fcee81c38 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -1063,7 +1063,7 @@ public: } _NODISCARD const_reference operator[](size_type _Pos) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_DEQUE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pos < _Mysize(), "deque subscript out of range"); #endif @@ -1071,7 +1071,7 @@ public: } _NODISCARD reference operator[](size_type _Pos) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_DEQUE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pos < _Mysize(), "deque subscript out of range"); #endif @@ -1095,7 +1095,7 @@ public: } _NODISCARD reference front() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_DEQUE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!empty(), "front() called on empty deque"); #endif @@ -1103,7 +1103,7 @@ public: } _NODISCARD const_reference front() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_DEQUE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!empty(), "front() called on empty deque"); #endif @@ -1111,7 +1111,7 @@ public: } _NODISCARD reference back() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_DEQUE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!empty(), "back() called on empty deque"); #endif @@ -1119,7 +1119,7 @@ public: } _NODISCARD const_reference back() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_DEQUE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!empty(), "back() called on empty deque"); #endif @@ -1473,47 +1473,34 @@ private: public: void pop_front() noexcept /* strengthened */ { +#if _MSVC_STL_HARDENING_DEQUE || _ITERATOR_DEBUG_LEVEL != 0 + _STL_VERIFY(!empty(), "pop_front() called on empty deque"); +#endif + #if _ITERATOR_DEBUG_LEVEL == 2 - if (empty()) { - _STL_REPORT_ERROR("pop_front() called on empty deque"); - } else { // something to erase, do it - _Orphan_off(_Myoff()); - _Alty_traits::destroy(_Getal(), _Get_data()._Address_subscript(_Myoff())); - if (--_Mysize() == 0) { - _Myoff() = 0; - } else { - ++_Myoff(); - } - } -#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 / _ITERATOR_DEBUG_LEVEL < 2 vvv + _Orphan_off(_Myoff()); +#endif _Alty_traits::destroy(_Getal(), _Get_data()._Address_subscript(_Myoff())); if (--_Mysize() == 0) { _Myoff() = 0; } else { ++_Myoff(); } -#endif // ^^^ _ITERATOR_DEBUG_LEVEL < 2 ^^^ } void pop_back() noexcept /* strengthened */ { -#if _ITERATOR_DEBUG_LEVEL == 2 - if (empty()) { - _STL_REPORT_ERROR("pop_back() called on empty deque"); - } else { // something to erase, do it - size_type _Newoff = _Myoff() + _Mysize() - 1; - _Orphan_off(_Newoff); - _Alty_traits::destroy(_Getal(), _Get_data()._Address_subscript(_Newoff)); - if (--_Mysize() == 0) { - _Myoff() = 0; - } - } -#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 / _ITERATOR_DEBUG_LEVEL < 2 vvv +#if _MSVC_STL_HARDENING_DEQUE || _ITERATOR_DEBUG_LEVEL != 0 + _STL_VERIFY(!empty(), "pop_back() called on empty deque"); +#endif + size_type _Newoff = _Myoff() + _Mysize() - 1; +#if _ITERATOR_DEBUG_LEVEL == 2 + _Orphan_off(_Newoff); +#endif _Alty_traits::destroy(_Getal(), _Get_data()._Address_subscript(_Newoff)); if (--_Mysize() == 0) { _Myoff() = 0; } -#endif // ^^^ _ITERATOR_DEBUG_LEVEL < 2 ^^^ } iterator erase(const_iterator _Where) noexcept(is_nothrow_move_assignable_v) /* strengthened */ { diff --git a/stl/inc/expected b/stl/inc/expected index 45eb51a5fb6..4080ad8b5ef 100644 --- a/stl/inc/expected +++ b/stl/inc/expected @@ -620,40 +620,46 @@ public: // [expected.object.obs] _NODISCARD constexpr const _Ty* operator->() const noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Has_value, "operator->() called on a std::expected that contains an error, not a value"); #endif + return _STD addressof(_Value); } _NODISCARD constexpr _Ty* operator->() noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Has_value, "operator->() called on a std::expected that contains an error, not a value"); #endif + return _STD addressof(_Value); } _NODISCARD constexpr const _Ty& operator*() const& noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Has_value, "operator*() called on a std::expected that contains an error, not a value"); #endif + return _Value; } _NODISCARD constexpr _Ty& operator*() & noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Has_value, "operator*() called on a std::expected that contains an error, not a value"); #endif + return _Value; } _NODISCARD constexpr const _Ty&& operator*() const&& noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Has_value, "operator*() called on a std::expected that contains an error, not a value"); #endif + return _STD move(_Value); } _NODISCARD constexpr _Ty&& operator*() && noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Has_value, "operator*() called on a std::expected that contains an error, not a value"); #endif + return _STD move(_Value); } @@ -706,27 +712,31 @@ public: } _NODISCARD constexpr const _Err& error() const& noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Has_value, "error() called on a std::expected that contains a value, not an error"); #endif + return _Unexpected; } _NODISCARD constexpr _Err& error() & noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Has_value, "error() called on a std::expected that contains a value, not an error"); #endif + return _Unexpected; } _NODISCARD constexpr const _Err&& error() const&& noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Has_value, "error() called on a std::expected that contains a value, not an error"); #endif + return _STD move(_Unexpected); } _NODISCARD constexpr _Err&& error() && noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Has_value, "error() called on a std::expected that contains a value, not an error"); #endif + return _STD move(_Unexpected); } @@ -1468,7 +1478,7 @@ public: } constexpr void operator*() const noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Has_value, "operator*() called on a std::expected that contains an error, not a value"); #endif } @@ -1489,27 +1499,31 @@ public: } _NODISCARD constexpr const _Err& error() const& noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Has_value, "error() called on a std::expected that contains a value, not an error"); #endif + return _Unexpected; } _NODISCARD constexpr _Err& error() & noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Has_value, "error() called on a std::expected that contains a value, not an error"); #endif + return _Unexpected; } _NODISCARD constexpr const _Err&& error() const&& noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Has_value, "error() called on a std::expected that contains a value, not an error"); #endif + return _STD move(_Unexpected); } _NODISCARD constexpr _Err&& error() && noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_EXPECTED || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Has_value, "error() called on a std::expected that contains a value, not an error"); #endif + return _STD move(_Unexpected); } diff --git a/stl/inc/forward_list b/stl/inc/forward_list index 3e801e48e23..f0fb5398ef5 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -900,7 +900,7 @@ public: } _NODISCARD reference front() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_FORWARD_LIST || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Myhead != nullptr, "front() called on empty forward_list"); #endif @@ -908,7 +908,7 @@ public: } _NODISCARD const_reference front() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_FORWARD_LIST || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Myhead != nullptr, "front() called on empty forward_list"); #endif @@ -927,6 +927,10 @@ public: #endif // _HAS_CXX23 void pop_front() noexcept /* strengthened */ { +#if _MSVC_STL_HARDENING_FORWARD_LIST || _ITERATOR_DEBUG_LEVEL != 0 + _STL_VERIFY(_Mypair._Myval2._Myhead != nullptr, "pop_front() called on empty forward_list"); +#endif + _Erase_after(_Mypair._Myval2._Before_head()); } diff --git a/stl/inc/generator b/stl/inc/generator index 3374d9bb589..fbc69d90e11 100644 --- a/stl/inc/generator +++ b/stl/inc/generator @@ -484,14 +484,14 @@ namespace _Gen_detail { _NODISCARD _Ref operator*() const noexcept(noexcept(static_cast<_Ref>(*_Coro.promise()._Get_top().promise()._Ptr))) /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Coro.done(), "Can't dereference generator end iterator"); #endif return static_cast<_Ref>(*_Coro.promise()._Get_top().promise()._Ptr); } _Iterator& operator++() { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_Coro.done(), "Can't increment generator end iterator"); #endif _Coro.promise()._Get_top().resume(); @@ -572,7 +572,7 @@ public: _NODISCARD _Gen_detail::_Iter_provider<_Value, _Ref>::_Iterator begin() { // Pre: _Coro is suspended at its initial suspend point -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Coro, "Can't call begin on moved-from generator"); #endif _Coro.resume(); diff --git a/stl/inc/list b/stl/inc/list index fc5093dca87..1d67c2e4810 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -1208,7 +1208,7 @@ public: } _NODISCARD reference front() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_LIST || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty list"); #endif @@ -1216,7 +1216,7 @@ public: } _NODISCARD const_reference front() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_LIST || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty list"); #endif @@ -1224,7 +1224,7 @@ public: } _NODISCARD reference back() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_LIST || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty list"); #endif @@ -1232,7 +1232,7 @@ public: } _NODISCARD const_reference back() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_LIST || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty list"); #endif @@ -1253,7 +1253,7 @@ public: #endif // _HAS_CXX23 void pop_front() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_LIST || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "pop_front() called on empty list"); #endif @@ -1274,7 +1274,7 @@ public: #endif // _HAS_CXX23 void pop_back() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_LIST || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "pop_back() called on empty list"); #endif diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 714c6120c71..bedc6046035 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -100,7 +100,7 @@ private: _STL_INTERNAL_STATIC_ASSERT(sizeof...(_OtherExtents) == _Rank); _STL_INTERNAL_STATIC_ASSERT( ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...)); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (rank() > 0) { for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { if constexpr (rank() != rank_dynamic()) { @@ -114,7 +114,7 @@ private: "r (N4950 [mdspan.extents.cons]/2.2)"); } } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } template @@ -126,7 +126,7 @@ private: requires (tuple_size_v<_ExtsTuple> != _Rank_dynamic) constexpr explicit extents(_Extents_from_tuple, _ExtsTuple _Tpl, index_sequence<_DynIndices...>) noexcept : _Base{static_cast(_STD move(_STD get<_Dynamic_indices_inv[_DynIndices]>(_Tpl)))...} { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 [&](index_sequence<_MixedIndices...>) { _STL_VERIFY(((_Static_extents[_MixedIndices] == dynamic_extent || _STD cmp_equal(_Static_extents[_MixedIndices], @@ -135,7 +135,7 @@ private: "Value of exts_arr[r] must be equal to extent(r) for each r for which extent(r) is a static extent " "(N4950 [mdspan.extents.cons]/7.1)"); }(make_index_sequence{}); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } template @@ -143,13 +143,13 @@ private: : _Base{static_cast(_STD as_const(_Dynamic_exts[_Indices]))...} { _STL_INTERNAL_STATIC_ASSERT(is_convertible_v && is_nothrow_constructible_v); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Is_standard_integer<_OtherIndexType> && _Rank_dynamic != 0) { _STL_VERIFY(((_Dynamic_exts[_Indices] >= 0 && _STD in_range(_Dynamic_exts[_Indices])) && ...), "exts[r] must be representable as a nonnegative value of type index_type for every rank index r " "(N4950 [mdspan.extents.cons]/10.2)"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } template @@ -158,7 +158,7 @@ private: _STL_INTERNAL_STATIC_ASSERT(_Size != _Rank_dynamic); _STL_INTERNAL_STATIC_ASSERT(is_convertible_v && is_nothrow_constructible_v); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Is_standard_integer<_OtherIndexType>) { for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { _STL_VERIFY( @@ -170,7 +170,7 @@ private: "(N4950 [mdspan.extents.cons]/10.2)"); } } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } public: @@ -183,14 +183,14 @@ public: } _NODISCARD static constexpr size_t static_extent(_In_range_(<, _Rank) const rank_type _Idx) noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)"); #endif return _Static_extents[_Idx]; } _NODISCARD constexpr index_type extent(_In_range_(<, _Rank) const rank_type _Idx) const noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Idx < _Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/3)"); #endif if constexpr (rank_dynamic() == 0) { @@ -222,7 +222,7 @@ public: && (sizeof...(_OtherIndexTypes) == rank_dynamic() || sizeof...(_OtherIndexTypes) == rank()) constexpr explicit extents(_OtherIndexTypes... _Exts) noexcept : extents(_Extents_from_tuple{}, _STD tie(_Exts...), make_index_sequence{}) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 auto _Check_extent = [](const _Ty& _Ext) { if constexpr (_Is_standard_integer<_Ty>) { return _Ext >= 0 && _STD in_range(_Ext); @@ -235,7 +235,7 @@ public: }; _STL_VERIFY((_Check_extent(_Exts) && ...), "Each argument must be representable as a nonnegative value of type " "index_type (N4950 [mdspan.extents.cons]/7.2)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } template @@ -463,7 +463,7 @@ struct _Maybe_fully_static_extents<_Extents> { template constexpr explicit _Maybe_fully_static_extents([[maybe_unused]] const _OtherExtents& _Exts_) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 (void) _Extents{_Exts_}; // NB: temporary created for preconditions check #endif } @@ -495,13 +495,13 @@ public: constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type& _Exts_) noexcept : _Base(_Exts_) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (extents_type::rank_dynamic() != 0) { _STL_VERIFY(_Exts_._Is_dynamic_multidim_index_space_size_representable(), "The size of the multidimensional index space e must be representable as a value of type index_type " "(N4950 [mdspan.layout.left.cons]/1)."); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } template @@ -509,7 +509,7 @@ public: constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& _Other) noexcept : _Base(_Other.extents()) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " "[mdspan.layout.left.cons]/4)."); @@ -521,7 +521,7 @@ public: constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_right::mapping<_OtherExtents>& _Other) noexcept : _Base(_Other.extents()) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " "[mdspan.layout.left.cons]/7)."); @@ -533,7 +533,7 @@ public: constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::mapping<_OtherExtents>& _Other) noexcept // strengthened : _Base(_Other.extents()) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (extents_type::rank() > 0) { index_type _Prod = 1; for (size_t _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { @@ -546,7 +546,7 @@ public: _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " "[mdspan.layout.left.cons]/10.2)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } constexpr mapping& operator=(const mapping&) noexcept = default; @@ -594,7 +594,7 @@ public: _NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept requires (extents_type::rank() > 0) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Idx < extents_type::_Rank, "Value of i must be less than extents_type::rank() (N4950 [mdspan.layout.left.obs]/6)."); #endif @@ -612,7 +612,7 @@ private: _NODISCARD constexpr index_type _Index_impl( [[maybe_unused]] index_sequence<_Seq...> _Index_seq, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT(conjunction_v...>); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), "Value of extents_type::index-cast(i) must be a multidimensional index in extents_ (N4950 " "[mdspan.layout.left.obs]/3)."); @@ -649,13 +649,13 @@ public: constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type& _Exts_) noexcept : _Base(_Exts_) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (extents_type::rank_dynamic() != 0) { _STL_VERIFY(_Exts_._Is_dynamic_multidim_index_space_size_representable(), "The size of the multidimensional index space e must be representable as a value of type index_type " "(N4950 [mdspan.layout.right.cons]/1)."); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } template @@ -663,7 +663,7 @@ public: constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& _Other) noexcept : _Base(_Other.extents()) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " "[mdspan.layout.right.cons]/4)."); @@ -675,7 +675,7 @@ public: constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_left::mapping<_OtherExtents>& _Other) noexcept : _Base(_Other.extents()) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " "[mdspan.layout.right.cons]/7)."); @@ -686,7 +686,7 @@ public: requires is_constructible_v constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::mapping<_OtherExtents>& _Other) noexcept : _Base(_Other.extents()) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (extents_type::rank() > 0) { index_type _Prod = 1; for (size_t _Idx = extents_type::_Rank; _Idx-- > 0;) { @@ -699,7 +699,7 @@ public: _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " "[mdspan.layout.right.cons]/10.2)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } constexpr mapping& operator=(const mapping&) noexcept = default; @@ -747,7 +747,7 @@ public: _NODISCARD constexpr index_type stride(_In_range_(<, extents_type::_Rank) const rank_type _Idx) const noexcept requires (extents_type::rank() > 0) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Idx < extents_type::_Rank, "Value of i must be less than extents_type::rank() (N4950 [mdspan.layout.right.obs]/6)."); #endif @@ -765,7 +765,7 @@ private: _NODISCARD constexpr index_type _Index_impl( [[maybe_unused]] index_sequence<_Seq...> _Index_seq, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT(conjunction_v...>); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), "Value of extents_type::index-cast(i) must be a multidimensional index in extents_ (N4950 " "[mdspan.layout.right.obs]/3)."); @@ -815,7 +815,7 @@ private: : _Extents_base(_Exts_), _Strides_base{static_cast(_STD as_const(_Strides_[_Indices]))...} { _STL_INTERNAL_STATIC_ASSERT(is_convertible_v && is_nothrow_constructible_v); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (extents_type::rank() != 0) { bool _Found_zero = false; bool _Overflow = false; @@ -838,7 +838,7 @@ private: _STL_VERIFY(_Found_zero || !_Overflow, "REQUIRED-SPAN-SIZE(e, s) must be representable as a value of type " "index_type (N4950 [mdspan.layout.stride.cons]/4.2)."); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } public: @@ -846,7 +846,7 @@ public: if constexpr (extents_type::rank() != 0) { this->_Array.back() = 1; for (rank_type _Idx = extents_type::_Rank - 1; _Idx-- > 0;) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 const bool _Overflow = _Mul_overflow(this->_Array[_Idx + 1], this->_Exts.extent(_Idx + 1), this->_Array[_Idx]); // NB: N4950 requires value of 'layout_right::mapping().required_span_size()' to be @@ -855,9 +855,9 @@ public: _STL_VERIFY(!_Overflow, "Value of layout_right::mapping().required_span_size() must be " "representable as a value of type index_type (N4950 [mdspan.layout.stride.cons]/1)."); -#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL == 0 vvv +#else // ^^^ _ITERATOR_DEBUG_LEVEL != 0 / _ITERATOR_DEBUG_LEVEL == 0 vvv this->_Array[_Idx] = static_cast(this->_Array[_Idx + 1] * this->_Exts.extent(_Idx + 1)); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ } } } @@ -887,17 +887,17 @@ public: || _Is_mapping_of) )) mapping(const _StridedLayoutMapping& _Other) noexcept : _Extents_base(_Other.extents()) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " "[mdspan.layout.stride.cons]/7.3)."); _STL_VERIFY( _Offset(_Other) == 0, "Value of OFFSET(other) must be equal to 0 (N4950 [mdspan.layout.stride.cons]/7.4)."); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 if constexpr (extents_type::_Rank != 0) { for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { const auto _Stride = _Other.stride(_Idx); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Stride > 0, "Value of other.stride(r) must be greater than 0 for every rank index r of " "extents() (N4950 [mdspan.layout.stride.cons]/7.2)."); #endif @@ -980,7 +980,7 @@ public: _STL_REPORT_ERROR("The argument to stride must be nonnegative and less than extents_type::rank()."); return 1; } else { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Idx < extents_type::_Rank, "The argument to stride must be nonnegative and less than extents_type::rank()."); #endif @@ -1028,7 +1028,7 @@ private: _NODISCARD constexpr index_type _Index_impl( [[maybe_unused]] index_sequence<_Seq...> _Index_seq, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT(conjunction_v...>); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), "Value of extents_type::index-cast(i) must be a multidimensional index in extents_ (N4950 " "[mdspan.layout.stride.obs]/3)."); @@ -1142,7 +1142,7 @@ struct _Mdspan_accessor_base<_AccessorPolicy> { static constexpr _AccessorPolicy _Acc{}; }; -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 template _NODISCARD constexpr _IndexType _Mdspan_checked_index_cast(_OtherIndexType&& _Idx) noexcept(is_nothrow_constructible_v<_IndexType, _OtherIndexType>) { @@ -1156,7 +1156,7 @@ _NODISCARD constexpr _IndexType _Mdspan_checked_index_cast(_OtherIndexType&& _Id } return static_cast<_IndexType>(_STD forward<_OtherIndexType>(_Idx)); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 _EXPORT_STD template > @@ -1201,7 +1201,7 @@ public: } _NODISCARD static constexpr size_t static_extent(_In_range_(<, extents_type::_Rank) const rank_type _Idx) noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Idx < extents_type::_Rank, "Index must be less than rank() (N4950 [mdspan.extents.obs]/1)"); #endif return extents_type::_Static_extents[_Idx]; @@ -1286,14 +1286,14 @@ public: "[mdspan.mdspan.cons]/20.1)."); static_assert(is_constructible_v, "The extents_type must be constructible from OtherExtents (N4950 [mdspan.mdspan.cons]/20.2)."); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_MDSPAN || _ITERATOR_DEBUG_LEVEL != 0 for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { const auto _Static_ext = extents_type::_Static_extents[_Idx]; _STL_VERIFY(_STD cmp_equal(_Static_ext, dynamic_extent) || _STD cmp_equal(_Static_ext, _Other.extent(_Idx)), "For each rank index r of extents_type, static_extent(r) == dynamic_extent || static_extent(r) == " "other.extent(r) must be true (N4950 [mdspan.mdspan.cons]/21.1)."); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_MDSPAN || _ITERATOR_DEBUG_LEVEL != 0 } constexpr mdspan& operator=(const mdspan&) = default; @@ -1306,11 +1306,11 @@ public: && (sizeof...(_OtherIndexTypes) == rank()) _NODISCARD constexpr reference operator[](_OtherIndexTypes... _Indices) const noexcept(noexcept(_Access_impl(static_cast(_STD move(_Indices))...))) /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 return _Access_impl(_STD _Mdspan_checked_index_cast(_STD move(_Indices))...); -#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL <= 0 vvv +#else // ^^^ _ITERATOR_DEBUG_LEVEL != 0 / _ITERATOR_DEBUG_LEVEL == 0 vvv return _Access_impl(static_cast(_STD move(_Indices))...); -#endif // ^^^ _CONTAINER_DEBUG_LEVEL <= 0 ^^^ +#endif // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ } #endif // ^^^ defined(__cpp_multidimensional_subscript) ^^^ @@ -1319,11 +1319,11 @@ private: _NODISCARD constexpr reference _Multidimensional_subscript( span<_OtherIndexType, rank()> _Indices, index_sequence<_Seq...>) const noexcept(noexcept(_Access_impl(static_cast(_STD as_const(_Indices[_Seq]))...))) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 return _Access_impl(_STD _Mdspan_checked_index_cast(_STD as_const(_Indices[_Seq]))...); -#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL <= 0 vvv +#else // ^^^ _ITERATOR_DEBUG_LEVEL != 0 / _ITERATOR_DEBUG_LEVEL == 0 vvv return _Access_impl(static_cast(_STD as_const(_Indices[_Seq]))...); -#endif // ^^^ _CONTAINER_DEBUG_LEVEL <= 0 ^^^ +#endif // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ } public: @@ -1344,13 +1344,13 @@ public: } _NODISCARD constexpr size_type size() const noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (rank_dynamic() != 0) { _STL_VERIFY(this->_Map.extents().template _Is_dynamic_multidim_index_space_size_representable(), "The size of the multidimensional index space extents() must be representable as a value of type " "size_type (N4950 [mdspan.mdspan.members]/7)."); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 return static_cast( _Fwd_prod_of_extents::_Calculate(this->_Map.extents(), extents_type::_Rank)); } @@ -1434,7 +1434,7 @@ private: _NODISCARD constexpr reference _Access_impl(_OtherIndexTypes... _Indices) const noexcept(noexcept(this->_Acc.access(_Ptr, static_cast(this->_Map(_Indices...))))) { _STL_INTERNAL_STATIC_ASSERT(conjunction_v...>); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_MDSPAN || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Map.extents()._Contains_multidimensional_index(make_index_sequence{}, _Indices...), "mdspan subscript out of range; extents_type::index-cast(std::move(indices)) must be " "a multidimensional index in extents() (N5001 [mdspan.mdspan.members]/3)."); diff --git a/stl/inc/mutex b/stl/inc/mutex index 6e333716403..25cb1aed891 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -584,12 +584,12 @@ public: cv_status wait_until(unique_lock& _Lck, const chrono::time_point<_Clock, _Duration>& _Abs_time) { // wait until time point static_assert(chrono::_Is_clock_v<_Clock>, "Clock type required"); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY( _Lck.owns_lock(), "wait_until's caller must own the lock argument (N4958 [thread.condition.condvar]/17)"); _STL_VERIFY(_Mtx_current_owns(_Lck.mutex()->_Mymtx()), "wait_until's calling thread must hold the lock argument's mutex (N4958 [thread.condition.condvar]/17)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 for (;;) { const auto _Now = _Clock::now(); if (_Abs_time <= _Now) { diff --git a/stl/inc/optional b/stl/inc/optional index 7a527fff616..196374892eb 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -181,30 +181,34 @@ struct _Optional_construct_base : _Optional_destruct_base<_Ty> { } _NODISCARD constexpr _Ty& operator*() & noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_OPTIONAL || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Has_value, "operator*() called on empty optional"); #endif + return this->_Value; } _NODISCARD constexpr const _Ty& operator*() const& noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_OPTIONAL || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Has_value, "operator*() called on empty optional"); #endif + return this->_Value; } _NODISCARD constexpr _Ty&& operator*() && noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_OPTIONAL || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Has_value, "operator*() called on empty optional"); #endif + return _STD move(this->_Value); } _NODISCARD constexpr const _Ty&& operator*() const&& noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_OPTIONAL || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Has_value, "operator*() called on empty optional"); #endif + return _STD move(this->_Value); } }; @@ -376,15 +380,17 @@ public: } _NODISCARD constexpr const _Ty* operator->() const noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_OPTIONAL || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Has_value, "operator->() called on empty optional"); #endif + return _STD addressof(this->_Value); } _NODISCARD constexpr _Ty* operator->() noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_OPTIONAL || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Has_value, "operator->() called on empty optional"); #endif + return _STD addressof(this->_Value); } diff --git a/stl/inc/ranges b/stl/inc/ranges index 821e2aad4e4..06520461db3 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -959,34 +959,34 @@ namespace ranges { constexpr explicit iota_view(_Wi _Value_) noexcept(is_nothrow_move_constructible_v<_Wi> && is_nothrow_default_constructible_v<_Bo>) // strengthened : _Value(_STD move(_Value_)) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (totally_ordered_with<_Wi, _Bo>) { _STL_VERIFY(_Value_ <= _Bound, "Per N4981 [range.iota.view]/6, the first argument must not exceed the " "value-initialized bound when their types are totally ordered."); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } constexpr explicit iota_view(type_identity_t<_Wi> _Value_, type_identity_t<_Bo> _Bound_) noexcept(is_nothrow_move_constructible_v<_Wi> && is_nothrow_move_constructible_v<_Bo>) // strengthened : _Value(_STD move(_Value_)), _Bound(_STD move(_Bound_)) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (totally_ordered_with<_Wi, _Bo>) { _STL_VERIFY(_Value_ <= _Bound_, "Per N4981 [range.iota.view]/8, the first argument must not exceed the " "second when their types are totally ordered."); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } constexpr explicit iota_view(_It _First, _Se _Last) noexcept(is_nothrow_move_constructible_v<_Wi> && is_nothrow_move_constructible_v<_Bo>) // strengthened : _Value(_STD move(_First._Current)), _Bound(_STD move(_Bound_from(_Last))) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (totally_ordered_with<_Wi, _Bo>) { _STL_VERIFY(_Value <= _Bound, "Per N4981 [range.iota.view]/8 and /10, the iterator must not exceed the " "sentinel when their types are totally ordered."); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } _NODISCARD constexpr _It begin() const noexcept(is_nothrow_copy_constructible_v<_Wi>) /* strengthened */ { @@ -1109,7 +1109,7 @@ namespace ranges { } constexpr _Iterator& operator++() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Current < (numeric_limits<_Index_type>::max)(), "cannot increment repeat_view iterator past end (integer overflow)"); #endif @@ -1123,14 +1123,14 @@ namespace ranges { } constexpr _Iterator& operator--() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (is_same_v<_Bo, unreachable_sentinel_t>) { _STL_VERIFY(_Current > (numeric_limits<_Index_type>::min)(), "cannot decrement repeat_view iterator before begin (integer overflow)"); } else { _STL_VERIFY(_Current > 0, "cannot decrement below 0"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 --_Current; return *this; } @@ -1141,7 +1141,7 @@ namespace ranges { } constexpr _Iterator& operator+=(difference_type _Off) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (sizeof(difference_type) > sizeof(_Index_type)) { _STL_VERIFY(static_cast<_Index_type>(_Off) == _Off, _Off > 0 ? "cannot advance repeat_view iterator past end (integer overflow)" @@ -1159,12 +1159,12 @@ namespace ranges { if constexpr (!is_same_v<_Bo, unreachable_sentinel_t>) { _STL_VERIFY(_Current + _Off >= 0, "cannot subtract below 0"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 _Current += static_cast<_Index_type>(_Off); return *this; } constexpr _Iterator& operator-=(difference_type _Off) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (sizeof(difference_type) > sizeof(_Index_type)) { _STL_VERIFY(static_cast<_Index_type>(_Off) == _Off, _Off < 0 ? "cannot advance repeat_view iterator past end (integer overflow)" @@ -1182,7 +1182,7 @@ namespace ranges { if constexpr (!is_same_v<_Bo, unreachable_sentinel_t>) { _STL_VERIFY(_Current - _Off >= 0, "cannot subtract below 0"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 _Current -= static_cast<_Index_type>(_Off); return *this; } @@ -1239,20 +1239,20 @@ namespace ranges { noexcept(is_nothrow_copy_constructible_v<_Ty>) // strengthened requires copy_constructible<_Ty> : _Value(in_place, _Value_), _Bound(_STD move(_Bound_)) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Signed_integer_like<_Bo>) { _STL_VERIFY(_Bound >= 0, "Bound must be >= 0"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } _NODISCARD_CTOR constexpr explicit repeat_view(_Ty&& _Value_, _Bo _Bound_ = _Bo{}) noexcept(is_nothrow_move_constructible_v<_Ty>) // strengthened : _Value(in_place, _STD move(_Value_)), _Bound(_STD move(_Bound_)) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Signed_integer_like<_Bo>) { _STL_VERIFY(_Bound >= 0, "Bound must be >= 0"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } template requires constructible_from<_Ty, _TArgs...> && constructible_from<_Bo, _BArgs...> @@ -1261,11 +1261,11 @@ namespace ranges { noexcept(is_nothrow_constructible_v<_Ty, _TArgs...> && noexcept(_STD make_from_tuple<_Bo>(_Bound_args))) // strengthened : repeat_view(_Val_args, index_sequence_for<_TArgs...>{}, _STD make_from_tuple<_Bo>(_Bound_args)) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Signed_integer_like<_Bo>) { _STL_VERIFY(_Bound >= 0, "Bound must be >= 0"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 } _NODISCARD constexpr _Iterator begin() const noexcept /* strengthened */ { @@ -1759,14 +1759,14 @@ namespace ranges { } _NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pred, "filter_view has no predicate"); #endif return *_Pred; } _NODISCARD constexpr _Iterator begin() { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY( _Pred, "N4950 [range.filter.view]/3 forbids calling begin on a filter_view that holds no predicate"); #endif @@ -1915,7 +1915,7 @@ namespace ranges { constexpr explicit take_view(_Vw _Range_, const range_difference_t<_Vw> _Count_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened : _Range(_STD move(_Range_)), _Count{_Count_} { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Count_ >= 0, "Number of elements to take must be non-negative (N4971 [range.take.view]/1)"); #endif } @@ -2223,7 +2223,7 @@ namespace ranges { } _NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pred, "take_while_view has no predicate"); #endif return *_Pred; @@ -2245,7 +2245,7 @@ namespace ranges { noexcept(_RANGES end(_Range)) && is_nothrow_move_constructible_v<_Sentinel>) /* strengthened */ requires (!_Simple_view<_Vw>) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pred, "cannot call end on a take_while_view with no predicate"); #endif return _Sentinel{_RANGES end(_Range), _STD addressof(*_Pred)}; @@ -2255,7 +2255,7 @@ namespace ranges { noexcept(_RANGES end(_Range)) && is_nothrow_move_constructible_v<_Sentinel>) /* strengthened */ requires range && indirect_unary_predicate> { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pred, "cannot call end on a take_while_view with no predicate"); #endif return _Sentinel{_RANGES end(_Range), _STD addressof(*_Pred)}; @@ -2335,7 +2335,7 @@ namespace ranges { constexpr explicit drop_view(_Vw _Range_, const range_difference_t<_Vw> _Count_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened : _Range(_STD move(_Range_)), _Count{_Count_} { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Count_ >= 0, "Number of elements to drop must be non-negative (N4971 [range.drop.view]/1)"); #endif } @@ -2557,14 +2557,14 @@ namespace ranges { } _NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pred, "drop_while_view has no predicate"); #endif return *_Pred; } _NODISCARD constexpr auto begin() { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY( _Pred, "N4950 [range.drop.while.view]/3 forbids calling begin on a drop_while_view with no predicate"); #endif @@ -4237,7 +4237,7 @@ namespace ranges { requires (input_or_output_iterator> && _Choice<_It>._Strategy != _St::_None) _NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_It&& _First, const iter_difference_t> _Count) _CONST_CALL_OPERATOR noexcept(_Choice<_It>._No_throw) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Count >= 0, "The size passed to views::counted must be non-negative"); #endif constexpr _St _Strat = _Choice<_It>._Strategy; @@ -5669,7 +5669,7 @@ namespace ranges { constexpr explicit chunk_view(_Vw _Range_, const range_difference_t<_Vw> _Count_) noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ : _Range(_STD move(_Range_)), _Count{_Count_} { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Count > 0, "chunk size must be greater than 0"); #endif } @@ -5942,7 +5942,7 @@ namespace ranges { constexpr explicit chunk_view(_Vw _Range_, const range_difference_t<_Vw> _Count_) noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ : _Range(_STD move(_Range_)), _Count{_Count_} { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Count > 0, "chunk size must be greater than 0"); #endif } @@ -6319,7 +6319,7 @@ namespace ranges { constexpr explicit slide_view(_Vw _Range_, const range_difference_t<_Vw> _Count_) noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ : _Range(_STD move(_Range_)), _Count{_Count_} { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Count > 0, "The window size must be positive (N4950 [range.slide.view]/1)"); #endif } @@ -6595,14 +6595,14 @@ namespace ranges { } _NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pred, "chunk_by_view has no predicate"); #endif return *_Pred; } _NODISCARD constexpr _Iterator begin() { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Pred, "cannot call begin on a chunk_by_view with no predicate"); #endif @@ -6927,7 +6927,7 @@ namespace ranges { constexpr explicit stride_view(_Vw _Range_, range_difference_t<_Vw> _Stride_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened : _Range(_STD move(_Range_)), _Stride(_Stride_) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Stride > 0, "stride must be greater than 0"); #endif } @@ -9152,7 +9152,7 @@ namespace ranges { requires _Cartesian_product_is_sized<_First, _Rest...> { return [&](index_sequence<_Indices...>) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 const array _Sizes = {static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases)))...}; const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...); if (_Any_zero) { @@ -9164,9 +9164,9 @@ namespace ranges { _STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 " "[range.cartesian.view]/10)."); return _Product; -#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL == 0 vvv +#else // ^^^ _ITERATOR_DEBUG_LEVEL != 0 / _ITERATOR_DEBUG_LEVEL == 0 vvv return (static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases))) * ...); -#endif // ^^^ _CONTAINER_DEBUG_LEVEL == 0 ^^^ +#endif // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ }(make_index_sequence<1 + sizeof...(_Rest)>{}); } @@ -9174,7 +9174,7 @@ namespace ranges { requires _Cartesian_product_is_sized { return [&](index_sequence<_Indices...>) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 const array _Sizes = {static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases)))...}; const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...); if (_Any_zero) { @@ -9186,9 +9186,9 @@ namespace ranges { _STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 " "[range.cartesian.view]/10)."); return _Product; -#else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL == 0 vvv +#else // ^^^ _ITERATOR_DEBUG_LEVEL != 0 / _ITERATOR_DEBUG_LEVEL == 0 vvv return (static_cast<_Size_type>(_RANGES size(_STD get<_Indices>(_Bases))) * ...); -#endif // ^^^ _CONTAINER_DEBUG_LEVEL == 0 ^^^ +#endif // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ }(make_index_sequence<1 + sizeof...(_Rest)>{}); } }; diff --git a/stl/inc/span b/stl/inc/span index 4f043ea279d..ec504c98775 100644 --- a/stl/inc/span +++ b/stl/inc/span @@ -206,7 +206,11 @@ struct _Span_extent_type { constexpr _Span_extent_type() noexcept = default; - constexpr explicit _Span_extent_type(const pointer _Data, size_t) noexcept : _Mydata{_Data} {} + constexpr explicit _Span_extent_type(const pointer _Data, size_t) noexcept : _Mydata{_Data} { + // Verify that later calls to size_bytes() won't overflow: + static_assert( + _Mysize <= dynamic_extent / sizeof(_Ty), "size of span in bytes exceeds numeric_limits::max()"); + } pointer _Mydata{nullptr}; static constexpr size_t _Mysize = _Extent; @@ -219,7 +223,13 @@ struct _Span_extent_type<_Ty, dynamic_extent> { constexpr _Span_extent_type() noexcept = default; constexpr explicit _Span_extent_type(const pointer _Data, const size_t _Size) noexcept - : _Mydata{_Data}, _Mysize{_Size} {} + : _Mydata{_Data}, _Mysize{_Size} { +#if _ITERATOR_DEBUG_LEVEL != 0 + // Verify that later calls to size_bytes() won't overflow: + _STL_VERIFY( + _Mysize <= dynamic_extent / sizeof(_Ty), "size of span in bytes exceeds numeric_limits::max()"); +#endif + } pointer _Mydata{nullptr}; size_t _Mysize{0}; @@ -294,12 +304,12 @@ public: template <_Span_compatible_iterator _It> constexpr explicit(_Extent != dynamic_extent) span(_It _First, size_type _Count) noexcept // strengthened : _Mybase(_STD to_address(_STD _Get_unwrapped_n(_First, _Count)), _Count) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Extent != dynamic_extent) { _STL_VERIFY(_Count == _Extent, "Cannot construct span with static extent from range [first, first + count) as count != extent"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 } template <_Span_compatible_iterator _It, _Span_compatible_sentinel<_It> _Sentinel> @@ -307,12 +317,12 @@ public: noexcept(noexcept(_Last - _First)) // strengthened : _Mybase(_STD to_address(_First), static_cast(_Last - _First)) { _STD _Adl_verify_range(_First, _Last); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Extent != dynamic_extent) { _STL_VERIFY(_Last - _First == _Extent, "Cannot construct span with static extent from range [first, last) as last - first != extent"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 } template @@ -331,12 +341,12 @@ public: template <_Span_compatible_range _Rng> constexpr explicit(_Extent != dynamic_extent) span(_Rng&& _Range) : _Mybase(_RANGES data(_Range), static_cast(_RANGES size(_Range))) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Extent != dynamic_extent) { _STL_VERIFY(_RANGES size(_Range) == _Extent, "Cannot construct span with static extent from range r as std::ranges::size(r) != extent"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 } template @@ -345,12 +355,12 @@ public: constexpr explicit(_Extent != dynamic_extent && _OtherExtent == dynamic_extent) span(const span<_OtherTy, _OtherExtent>& _Other) noexcept : _Mybase(_Other.data(), _Other.size()) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 if constexpr (_Extent != dynamic_extent) { _STL_VERIFY(_Other.size() == _Extent, "Cannot construct span with static extent from other span as other.size() != extent"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 } // [span.sub] Subviews @@ -359,18 +369,20 @@ public: if constexpr (_Extent != dynamic_extent) { static_assert(_Count <= _Extent, "Count out of range in span::first()"); } -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 else { _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::first()"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 + return span{_Mydata, _Count}; } _NODISCARD constexpr auto first(const size_type _Count) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::first(count)"); #endif + return span{_Mydata, _Count}; } @@ -379,18 +391,20 @@ public: if constexpr (_Extent != dynamic_extent) { static_assert(_Count <= _Extent, "Count out of range in span::last()"); } -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 else { _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::last()"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 + return span{_Mydata + (_Mysize - _Count), _Count}; } _NODISCARD constexpr auto last(const size_type _Count) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Count <= _Mysize, "Count out of range in span::last(count)"); #endif + return span{_Mydata + (_Mysize - _Count), _Count}; } @@ -401,7 +415,7 @@ public: static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset, "Count out of range in span::subspan()"); } -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 else { _STL_VERIFY(_Offset <= _Mysize, "Offset out of range in span::subspan()"); @@ -409,7 +423,8 @@ public: _STL_VERIFY(_Count <= _Mysize - _Offset, "Count out of range in span::subspan()"); } } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 + using _ReturnType = span; return _ReturnType{_Mydata + _Offset, _Count == dynamic_extent ? _Mysize - _Offset : _Count}; @@ -417,11 +432,12 @@ public: _NODISCARD constexpr auto subspan(const size_type _Offset, const size_type _Count = dynamic_extent) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Offset <= _Mysize, "Offset out of range in span::subspan(offset, count)"); _STL_VERIFY(_Count == dynamic_extent || _Count <= _Mysize - _Offset, "Count out of range in span::subspan(offset, count)"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 + using _ReturnType = span; return _ReturnType{_Mydata + _Offset, _Count == dynamic_extent ? _Mysize - _Offset : _Count}; } @@ -431,16 +447,10 @@ public: return _Mysize; } -#pragma warning(push) -#pragma warning(disable : 4127) // conditional expression is constant _NODISCARD constexpr size_type size_bytes() const noexcept { -#if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Mysize <= dynamic_extent / sizeof(element_type), - "size of span in bytes exceeds std::numeric_limits::max()"); -#endif + // Under _ITERATOR_DEBUG_LEVEL != 0, span's constructors verify that this multiplication won't overflow. return _Mysize * sizeof(element_type); } -#pragma warning(pop) _NODISCARD constexpr bool empty() const noexcept { return _Mysize == 0; @@ -448,25 +458,28 @@ public: // [span.elem] Element access _NODISCARD constexpr reference operator[](const size_type _Off) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off < _Mysize, "span subscript out of range"); #endif + return _Mydata[_Off]; } #pragma warning(push) #pragma warning(disable : 4127) // conditional expression is constant _NODISCARD constexpr reference front() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize > 0, "front() called on empty span"); #endif + return _Mydata[0]; } _NODISCARD constexpr reference back() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_SPAN || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize > 0, "back() called on empty span"); #endif + return _Mydata[_Mysize - 1]; } #pragma warning(pop) diff --git a/stl/inc/valarray b/stl/inc/valarray index 5773a639e20..bb30c016487 100644 --- a/stl/inc/valarray +++ b/stl/inc/valarray @@ -290,7 +290,7 @@ public: } valarray& operator*=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -301,7 +301,7 @@ public: } valarray& operator/=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -312,7 +312,7 @@ public: } valarray& operator%=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -323,7 +323,7 @@ public: } valarray& operator+=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -334,7 +334,7 @@ public: } valarray& operator-=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -345,7 +345,7 @@ public: } valarray& operator^=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -356,7 +356,7 @@ public: } valarray& operator|=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -367,7 +367,7 @@ public: } valarray& operator&=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -378,7 +378,7 @@ public: } valarray& operator<<=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -389,7 +389,7 @@ public: } valarray& operator>>=(const valarray& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mysize == _Right._Mysize, "valarrays of different lengths"); #endif const size_t _Size = _Mysize; // eliminating indirection helps vectorization @@ -404,7 +404,7 @@ public: } _NODISCARD const _Ty& operator[](size_t _Off) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VALARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off < _Mysize, "valarray subscript out of range"); #endif @@ -412,7 +412,7 @@ public: } _NODISCARD _Ty& operator[](size_t _Off) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VALARRAY || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off < _Mysize, "valarray subscript out of range"); #endif @@ -866,7 +866,7 @@ _NODISCARD _Boolarray operator||(const typename valarray<_Ty>::value_type& _Left _EXPORT_STD template _NODISCARD valarray<_Ty> operator*(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -879,7 +879,7 @@ _NODISCARD valarray<_Ty> operator*(const valarray<_Ty>& _Left, const valarray<_T _EXPORT_STD template _NODISCARD valarray<_Ty> operator/(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -892,7 +892,7 @@ _NODISCARD valarray<_Ty> operator/(const valarray<_Ty>& _Left, const valarray<_T _EXPORT_STD template _NODISCARD valarray<_Ty> operator%(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -905,7 +905,7 @@ _NODISCARD valarray<_Ty> operator%(const valarray<_Ty>& _Left, const valarray<_T _EXPORT_STD template _NODISCARD valarray<_Ty> operator+(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -918,7 +918,7 @@ _NODISCARD valarray<_Ty> operator+(const valarray<_Ty>& _Left, const valarray<_T _EXPORT_STD template _NODISCARD valarray<_Ty> operator-(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -931,7 +931,7 @@ _NODISCARD valarray<_Ty> operator-(const valarray<_Ty>& _Left, const valarray<_T _EXPORT_STD template _NODISCARD valarray<_Ty> operator^(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -944,7 +944,7 @@ _NODISCARD valarray<_Ty> operator^(const valarray<_Ty>& _Left, const valarray<_T _EXPORT_STD template _NODISCARD valarray<_Ty> operator&(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -957,7 +957,7 @@ _NODISCARD valarray<_Ty> operator&(const valarray<_Ty>& _Left, const valarray<_T _EXPORT_STD template _NODISCARD valarray<_Ty> operator|(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -970,7 +970,7 @@ _NODISCARD valarray<_Ty> operator|(const valarray<_Ty>& _Left, const valarray<_T _EXPORT_STD template _NODISCARD valarray<_Ty> operator<<(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -983,7 +983,7 @@ _NODISCARD valarray<_Ty> operator<<(const valarray<_Ty>& _Left, const valarray<_ _EXPORT_STD template _NODISCARD valarray<_Ty> operator>>(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -996,7 +996,7 @@ _NODISCARD valarray<_Ty> operator>>(const valarray<_Ty>& _Left, const valarray<_ _EXPORT_STD template _NODISCARD _Boolarray operator&&(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -1009,7 +1009,7 @@ _NODISCARD _Boolarray operator&&(const valarray<_Ty>& _Left, const valarray<_Ty> _EXPORT_STD template _NODISCARD _Boolarray operator||(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -1042,7 +1042,7 @@ _NODISCARD _Boolarray operator==(const typename valarray<_Ty>::value_type& _Left _EXPORT_STD template _NODISCARD _Boolarray operator==(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -1075,7 +1075,7 @@ _NODISCARD _Boolarray operator!=(const typename valarray<_Ty>::value_type& _Left _EXPORT_STD template _NODISCARD _Boolarray operator!=(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -1108,7 +1108,7 @@ _NODISCARD _Boolarray operator<(const typename valarray<_Ty>::value_type& _Left, _EXPORT_STD template _NODISCARD _Boolarray operator<(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -1141,7 +1141,7 @@ _NODISCARD _Boolarray operator>(const typename valarray<_Ty>::value_type& _Left, _EXPORT_STD template _NODISCARD _Boolarray operator>(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -1174,7 +1174,7 @@ _NODISCARD _Boolarray operator<=(const typename valarray<_Ty>::value_type& _Left _EXPORT_STD template _NODISCARD _Boolarray operator<=(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); @@ -1207,7 +1207,7 @@ _NODISCARD _Boolarray operator>=(const typename valarray<_Ty>::value_type& _Left _EXPORT_STD template _NODISCARD _Boolarray operator>=(const valarray<_Ty>& _Left, const valarray<_Ty>& _Right) { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Left.size() == _Right.size(), "valarrays of different lengths"); #endif const size_t _Size = _Left.size(); diff --git a/stl/inc/vector b/stl/inc/vector index ae8330bf2d2..1450120f061 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -1736,7 +1736,7 @@ public: auto& _My_data = _Mypair._Myval2; pointer& _Mylast = _My_data._Mylast; -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_My_data._Myfirst != _Mylast, "pop_back() called on empty vector"); #endif @@ -1913,7 +1913,7 @@ public: _NODISCARD _CONSTEXPR20 _Ty& operator[](const size_type _Pos) noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY( _Pos < static_cast(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range"); #endif @@ -1923,7 +1923,7 @@ public: _NODISCARD _CONSTEXPR20 const _Ty& operator[](const size_type _Pos) const noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY( _Pos < static_cast(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range"); #endif @@ -1951,7 +1951,7 @@ public: _NODISCARD _CONSTEXPR20 _Ty& front() noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "front() called on empty vector"); #endif @@ -1960,7 +1960,7 @@ public: _NODISCARD _CONSTEXPR20 const _Ty& front() const noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "front() called on empty vector"); #endif @@ -1969,7 +1969,7 @@ public: _NODISCARD _CONSTEXPR20 _Ty& back() noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "back() called on empty vector"); #endif @@ -1978,7 +1978,7 @@ public: _NODISCARD _CONSTEXPR20 const _Ty& back() const noexcept /* strengthened */ { auto& _My_data = _Mypair._Myval2; -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_My_data._Myfirst != _My_data._Mylast, "back() called on empty vector"); #endif @@ -3209,7 +3209,7 @@ public: } _NODISCARD _CONSTEXPR20 const_reference operator[](size_type _Off) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off < this->_Mysize, "vector subscript out of range"); #endif @@ -3219,7 +3219,7 @@ public: } _NODISCARD _CONSTEXPR20 reference operator[](size_type _Off) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off < this->_Mysize, "vector subscript out of range"); #endif @@ -3229,7 +3229,7 @@ public: } _NODISCARD _CONSTEXPR20 reference front() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Mysize != 0, "front() called on empty vector"); #endif @@ -3237,7 +3237,7 @@ public: } _NODISCARD _CONSTEXPR20 const_reference front() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Mysize != 0, "front() called on empty vector"); #endif @@ -3245,7 +3245,7 @@ public: } _NODISCARD _CONSTEXPR20 reference back() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Mysize != 0, "back() called on empty vector"); #endif @@ -3253,7 +3253,7 @@ public: } _NODISCARD _CONSTEXPR20 const_reference back() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(this->_Mysize != 0, "back() called on empty vector"); #endif @@ -3272,6 +3272,10 @@ public: #endif // _HAS_CXX23 _CONSTEXPR20 void pop_back() noexcept /* strengthened */ { +#if _MSVC_STL_HARDENING_VECTOR || _ITERATOR_DEBUG_LEVEL != 0 + _STL_VERIFY(this->_Mysize != 0, "pop_back() called on empty vector"); +#endif + erase(end() - 1); } diff --git a/stl/inc/xstring b/stl/inc/xstring index 02d8fc784ee..52926040086 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -2246,17 +2246,19 @@ public: } _NODISCARD _CONSTEXPR20 reference operator[](const size_type _Off) noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off <= _Mypair._Myval2._Mysize, "string subscript out of range"); #endif + return _Mypair._Myval2._Myptr()[_Off]; } _NODISCARD _CONSTEXPR20 const_reference operator[](const size_type _Off) const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Off <= _Mypair._Myval2._Mysize, "string subscript out of range"); #endif + return _Mypair._Myval2._Myptr()[_Off]; } @@ -2291,14 +2293,16 @@ public: _CONSTEXPR20 void pop_back() noexcept /* strengthened */ { const size_type _Old_size = _Mypair._Myval2._Mysize; -#if _ITERATOR_DEBUG_LEVEL >= 1 + +#if _MSVC_STL_HARDENING_BASIC_STRING || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Old_size != 0, "pop_back() called on empty string"); -#endif // _ITERATOR_DEBUG_LEVEL >= 1 +#endif + _Eos(_Old_size - 1); } _NODISCARD _CONSTEXPR20 reference front() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty string"); #endif @@ -2306,7 +2310,7 @@ public: } _NODISCARD _CONSTEXPR20 const_reference front() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "front() called on empty string"); #endif @@ -2314,7 +2318,7 @@ public: } _NODISCARD _CONSTEXPR20 reference back() noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty string"); #endif @@ -2322,7 +2326,7 @@ public: } _NODISCARD _CONSTEXPR20 const_reference back() const noexcept /* strengthened */ { -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _MSVC_STL_HARDENING_BASIC_STRING || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Mypair._Myval2._Mysize != 0, "back() called on empty string"); #endif @@ -2391,10 +2395,10 @@ public: auto _Arg_size = _New_size; const auto _Result_size = _STD move(_Op)(_Arg_ptr, _Arg_size); const auto _Result_as_size_type = static_cast(_Result_size); -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(_Result_size >= 0, "the returned size can't be smaller than 0"); _STL_VERIFY(_Result_as_size_type <= _New_size, "the returned size can't be greater than the passed size"); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 _Eos(_Result_as_size_type); } diff --git a/stl/inc/xutility b/stl/inc/xutility index 0d5b9872e48..966a1d66036 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3823,9 +3823,11 @@ namespace ranges { requires forward_range<_Derived> { auto& _Self = _Cast(); -#if _CONTAINER_DEBUG_LEVEL > 0 + +#if _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_RANGES empty(_Self), "front() called on empty ranges::view_interface"); #endif + return *_RANGES begin(_Self); } @@ -3833,9 +3835,11 @@ namespace ranges { requires forward_range { auto& _Self = _Cast(); -#if _CONTAINER_DEBUG_LEVEL > 0 + +#if _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_RANGES empty(_Self), "front() called on empty ranges::view_interface"); #endif + return *_RANGES begin(_Self); } @@ -3843,9 +3847,11 @@ namespace ranges { requires bidirectional_range<_Derived> && common_range<_Derived> { auto& _Self = _Cast(); -#if _CONTAINER_DEBUG_LEVEL > 0 + +#if _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_RANGES empty(_Self), "back() called on empty ranges::view_interface"); #endif + auto _Last = _RANGES end(_Self); return *--_Last; } @@ -3854,9 +3860,11 @@ namespace ranges { requires bidirectional_range && common_range { auto& _Self = _Cast(); -#if _CONTAINER_DEBUG_LEVEL > 0 + +#if _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE || _ITERATOR_DEBUG_LEVEL != 0 _STL_VERIFY(!_RANGES empty(_Self), "back() called on empty ranges::view_interface"); #endif + auto _Last = _RANGES end(_Self); return *--_Last; } @@ -3864,26 +3872,30 @@ namespace ranges { template _NODISCARD constexpr decltype(auto) operator[](const range_difference_t<_Rng> _Idx) { auto& _Self = _Cast(); -#if _CONTAINER_DEBUG_LEVEL > 0 + +#if _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE || _ITERATOR_DEBUG_LEVEL != 0 if constexpr (sized_range<_Derived>) { using _U_diff = _Make_unsigned_like_t>; _STL_VERIFY(static_cast<_U_diff>(_Idx) < static_cast<_U_diff>(_RANGES size(_Self)), "ranges::view_interface subscript out of range"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE || _ITERATOR_DEBUG_LEVEL != 0 + return _RANGES begin(_Self)[_Idx]; } template _NODISCARD constexpr decltype(auto) operator[](const range_difference_t<_Rng> _Idx) const { auto& _Self = _Cast(); -#if _CONTAINER_DEBUG_LEVEL > 0 + +#if _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE || _ITERATOR_DEBUG_LEVEL != 0 if constexpr (sized_range<_Derived>) { using _U_diff = _Make_unsigned_like_t>; _STL_VERIFY(static_cast<_U_diff>(_Idx) < static_cast<_U_diff>(_RANGES size(_Self)), "ranges::view_interface subscript out of range"); } -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE || _ITERATOR_DEBUG_LEVEL != 0 + return _RANGES begin(_Self)[_Idx]; } }; diff --git a/stl/inc/yvals.h b/stl/inc/yvals.h index 5922af50231..bae84f1e6b1 100644 --- a/stl/inc/yvals.h +++ b/stl/inc/yvals.h @@ -157,33 +157,102 @@ _STL_DISABLE_CLANG_WARNINGS #endif // defined(_DLL) etc. #endif // !defined(_ALLOW_RUNTIME_LIBRARY_MISMATCH) -#ifndef _CONTAINER_DEBUG_LEVEL -#if _ITERATOR_DEBUG_LEVEL == 0 -#define _CONTAINER_DEBUG_LEVEL 0 -#else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL != 0 vvv -#define _CONTAINER_DEBUG_LEVEL 1 -#endif // _ITERATOR_DEBUG_LEVEL == 0 -#endif // !defined(_CONTAINER_DEBUG_LEVEL) - -#if _ITERATOR_DEBUG_LEVEL != 0 && _CONTAINER_DEBUG_LEVEL == 0 -#error _ITERATOR_DEBUG_LEVEL != 0 must imply _CONTAINER_DEBUG_LEVEL == 1. -#endif // _ITERATOR_DEBUG_LEVEL != 0 && _CONTAINER_DEBUG_LEVEL == 0 - -#ifndef _STL_CRT_SECURE_INVALID_PARAMETER +#ifdef _CONTAINER_DEBUG_LEVEL +_EMIT_STL_ERROR(STL1006, "_CONTAINER_DEBUG_LEVEL has been removed. It was superseded by _MSVC_STL_HARDENING."); +#endif + +#ifndef _MSVC_STL_HARDENING +#define _MSVC_STL_HARDENING 0 +#endif + +#ifndef _MSVC_STL_HARDENING_ARRAY +#define _MSVC_STL_HARDENING_ARRAY _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_BASIC_STRING +#define _MSVC_STL_HARDENING_BASIC_STRING _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_BASIC_STRING_VIEW +#define _MSVC_STL_HARDENING_BASIC_STRING_VIEW _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_BITSET +#define _MSVC_STL_HARDENING_BITSET _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_DEQUE +#define _MSVC_STL_HARDENING_DEQUE _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_EXPECTED +#define _MSVC_STL_HARDENING_EXPECTED _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_FORWARD_LIST +#define _MSVC_STL_HARDENING_FORWARD_LIST _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_LIST +#define _MSVC_STL_HARDENING_LIST _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_MDSPAN +#define _MSVC_STL_HARDENING_MDSPAN _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_OPTIONAL +#define _MSVC_STL_HARDENING_OPTIONAL _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE +#define _MSVC_STL_HARDENING_RANGES_VIEW_INTERFACE _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_SPAN +#define _MSVC_STL_HARDENING_SPAN _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_VALARRAY +#define _MSVC_STL_HARDENING_VALARRAY _MSVC_STL_HARDENING +#endif + +#ifndef _MSVC_STL_HARDENING_VECTOR +#define _MSVC_STL_HARDENING_VECTOR _MSVC_STL_HARDENING +#endif + +#ifdef _STL_CRT_SECURE_INVALID_PARAMETER +_EMIT_STL_ERROR(STL1007, "_STL_CRT_SECURE_INVALID_PARAMETER has been removed. " + "It was superseded by _MSVC_STL_DOOM_FUNCTION."); +#endif + #ifdef _STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER -#define _STL_CRT_SECURE_INVALID_PARAMETER(expr) _CSTD abort() -#elif defined(_DEBUG) // Avoid emitting unused long strings for function names; see GH-1956. -// static_cast(__LINE__) avoids warning C4365 (signed/unsigned mismatch) with the /ZI compiler option. -#define _STL_CRT_SECURE_INVALID_PARAMETER(expr) \ - ::_invalid_parameter(_CRT_WIDE(#expr), L"", __FILEW__, static_cast(__LINE__), 0) -#else // ^^^ defined(_DEBUG) / !defined(_DEBUG) vvv -#define _STL_CRT_SECURE_INVALID_PARAMETER(expr) _CRT_SECURE_INVALID_PARAMETER(expr) -#endif // ^^^ !defined(_DEBUG) ^^^ -#endif // !defined(_STL_CRT_SECURE_INVALID_PARAMETER) +_EMIT_STL_ERROR(STL1008, "_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER has been removed. " + "It was superseded by _MSVC_STL_USE_ABORT_AS_DOOM_FUNCTION."); +#endif + +// The STL's "doom function" can be replaced. Notes: +// * It must not throw. (Attempting to throw would slam into noexcept.) +// * Common case: If it doesn't return, it should be marked as `[[noreturn]]`. +// * Uncommon case: If it returns, the STL will attempt to "continue on error", behaving as if no checking was done. +// + For example, a legacy codebase with a long startup time might want to log errors for investigation later. +// + WARNING: If you replace the STL's "doom function" to "continue on error", you do so at your own risk! +// After the STL has detected a precondition violation, undefined behavior is imminent. The STL will support +// "continue on error" by proceeding to do what it would have done anyways (instead of falling off the end of +// a non-void function, etc.), but it will not attempt to replace undefined behavior with implementation-defined +// behavior. (For example, we will not transform `pop_back()` of an empty `vector` to be a no-op.) +#ifndef _MSVC_STL_DOOM_FUNCTION +#ifdef _MSVC_STL_USE_ABORT_AS_DOOM_FUNCTION +#define _MSVC_STL_DOOM_FUNCTION(mesg) _CSTD abort() +#else // ^^^ defined(_MSVC_STL_USE_ABORT_AS_DOOM_FUNCTION) / !defined(_MSVC_STL_USE_ABORT_AS_DOOM_FUNCTION) vvv +// TRANSITION, GH-4858: after dropping Win7 support, we can directly call __fastfail(FAST_FAIL_INVALID_ARG). +#define _MSVC_STL_DOOM_FUNCTION(mesg) ::_invoke_watson(nullptr, nullptr, nullptr, 0, 0) +#endif // ^^^ !defined(_MSVC_STL_USE_ABORT_AS_DOOM_FUNCTION) ^^^ +#endif // ^^^ !defined(_MSVC_STL_DOOM_FUNCTION) ^^^ #define _STL_REPORT_ERROR(mesg) \ _RPTF0(_CRT_ASSERT, mesg); \ - _STL_CRT_SECURE_INVALID_PARAMETER(mesg) + _MSVC_STL_DOOM_FUNCTION(mesg) #define _STL_VERIFY(cond, mesg) \ if (!(cond)) { \ @@ -417,7 +486,7 @@ class _CRTIMP2_PURE_IMPORT _EmptyLockit { // empty lock class used for bin compa } \ } -#define _RAISE(x) _invoke_watson(nullptr, nullptr, nullptr, 0, 0) +#define _RAISE(x) ::_invoke_watson(nullptr, nullptr, nullptr, 0, 0) #define _RERAISE #define _THROW(...) (__VA_ARGS__)._Raise() diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 9be20813bdd..1abaf85d260 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1523,7 +1523,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect // next warning number: STL4049 -// next error number: STL1006 +// next error number: STL1009 // P0619R4 Removing C++17-Deprecated Features #ifndef _HAS_FEATURES_REMOVED_IN_CXX20 diff --git a/tests/libcxx/usual_matrix.lst b/tests/libcxx/usual_matrix.lst index a6642320f3a..72969ef33cc 100644 --- a/tests/libcxx/usual_matrix.lst +++ b/tests/libcxx/usual_matrix.lst @@ -3,7 +3,7 @@ RUNALL_INCLUDE ..\universal_prefix.lst RUNALL_CROSSLIST -* PM_CL="/EHsc /MTd /std:c++latest /permissive- /utf-8 /FImsvc_stdlib_force_include.h /wd4643 /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER" +* PM_CL="/EHsc /MTd /std:c++latest /permissive- /utf-8 /FImsvc_stdlib_force_include.h /wd4643" RUNALL_CROSSLIST PM_CL="/analyze:autolog- /Zc:preprocessor /wd6262" ASAN PM_CL="-fsanitize=address /Zi" PM_LINK="/debug" diff --git a/tests/std/test.lst b/tests/std/test.lst index 7093936102a..e188823bfcf 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -253,6 +253,7 @@ tests\GH_004657_expected_constraints_permissive tests\GH_004845_logical_operator_traits_with_non_bool_constant tests\GH_004929_internal_tag_constructors tests\GH_004930_char_traits_user_specialization +tests\GH_005090_stl_hardening tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function diff --git a/tests/std/tests/GH_005090_stl_hardening/env.lst b/tests/std/tests/GH_005090_stl_hardening/env.lst new file mode 100644 index 00000000000..606d5f84175 --- /dev/null +++ b/tests/std/tests/GH_005090_stl_hardening/env.lst @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst +RUNALL_CROSSLIST +* PM_CL="/D_MSVC_STL_HARDENING=1" diff --git a/tests/std/tests/GH_005090_stl_hardening/test.cpp b/tests/std/tests/GH_005090_stl_hardening/test.cpp new file mode 100644 index 00000000000..9fc8b475a9c --- /dev/null +++ b/tests/std/tests/GH_005090_stl_hardening/test.cpp @@ -0,0 +1,711 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// env.lst defines _MSVC_STL_HARDENING to 1. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if _HAS_CXX17 +#include +#include +#endif // _HAS_CXX17 + +#if _HAS_CXX20 +#include +#include +#endif // _HAS_CXX20 + +#if _HAS_CXX23 +#include +#include +#endif // _HAS_CXX23 + +#include + +using namespace std; + +// +void test_array_subscript() { + array a{}; +#pragma warning(push) +#pragma warning(disable : 28020) // /analyze correctly warns: The expression '_Param_(1)<3' is not true at this call. + (void) a[3]; +#pragma warning(pop) +} + +void test_array_subscript_const() { + const array a{}; +#pragma warning(push) +#pragma warning(disable : 28020) // /analyze correctly warns: The expression '_Param_(1)<3' is not true at this call. + (void) a[3]; +#pragma warning(pop) +} + +void test_array_zero_subscript() { + array az{}; + (void) az[0]; +} + +void test_array_zero_subscript_const() { + const array az{}; + (void) az[0]; +} + +void test_array_zero_front() { + array az{}; + (void) az.front(); +} + +void test_array_zero_front_const() { + const array az{}; + (void) az.front(); +} + +void test_array_zero_back() { + array az{}; + (void) az.back(); +} + +void test_array_zero_back_const() { + const array az{}; + (void) az.back(); +} + +// +void test_bitset_subscript() { + bitset<100> b{}; + (void) b[100]; +} + +void test_bitset_subscript_const() { + const bitset<100> b{}; + (void) b[100]; +} + +// +void test_deque_subscript() { + deque d(3); + (void) d[3]; +} + +void test_deque_subscript_const() { + const deque d(3); + (void) d[3]; +} + +void test_deque_front() { + deque d{}; + (void) d.front(); +} + +void test_deque_front_const() { + const deque d{}; + (void) d.front(); +} + +void test_deque_back() { + deque d{}; + (void) d.back(); +} + +void test_deque_back_const() { + const deque d{}; + (void) d.back(); +} + +void test_deque_pop_front() { + deque d{}; + d.pop_front(); +} + +void test_deque_pop_back() { + deque d{}; + d.pop_back(); +} + +// +void test_forward_list_front() { + forward_list fl{}; + (void) fl.front(); +} + +void test_forward_list_front_const() { + const forward_list fl{}; + (void) fl.front(); +} + +void test_forward_list_pop_front() { + forward_list fl{}; + fl.pop_front(); +} + +// +void test_list_front() { + list l{}; + (void) l.front(); +} + +void test_list_front_const() { + const list l{}; + (void) l.front(); +} + +void test_list_back() { + list l{}; + (void) l.back(); +} + +void test_list_back_const() { + const list l{}; + (void) l.back(); +} + +void test_list_pop_front() { + list l{}; + l.pop_front(); +} + +void test_list_pop_back() { + list l{}; + l.pop_back(); +} + +// +void test_string_subscript() { + string s(3, '*'); + (void) s[4]; // beyond null terminator +} + +void test_string_subscript_const() { + const string s(3, '*'); + (void) s[4]; // beyond null terminator +} + +void test_string_front() { + string s{}; + (void) s.front(); +} + +void test_string_front_const() { + const string s{}; + (void) s.front(); +} + +void test_string_back() { + string s{}; + (void) s.back(); +} + +void test_string_back_const() { + const string s{}; + (void) s.back(); +} + +void test_string_pop_back() { + string s{}; + s.pop_back(); +} + +// +void test_valarray_subscript() { + valarray va(3); + (void) va[3]; +} + +void test_valarray_subscript_const() { + const valarray va(3); + (void) va[3]; +} + +// +void test_vector_subscript() { + vector v(3); + (void) v[3]; +} + +void test_vector_subscript_const() { + const vector v(3); + (void) v[3]; +} + +void test_vector_front() { + vector v{}; + (void) v.front(); +} + +void test_vector_front_const() { + const vector v{}; + (void) v.front(); +} + +void test_vector_back() { + vector v{}; + (void) v.back(); +} + +void test_vector_back_const() { + const vector v{}; + (void) v.back(); +} + +void test_vector_pop_back() { + vector v{}; + v.pop_back(); +} + +void test_vector_bool_subscript() { + vector vb(3); + (void) vb[3]; +} + +void test_vector_bool_subscript_const() { + const vector vb(3); + (void) vb[3]; +} + +void test_vector_bool_front() { + vector vb{}; + (void) vb.front(); +} + +void test_vector_bool_front_const() { + const vector vb{}; + (void) vb.front(); +} + +void test_vector_bool_back() { + vector vb{}; + (void) vb.back(); +} + +void test_vector_bool_back_const() { + const vector vb{}; + (void) vb.back(); +} + +void test_vector_bool_pop_back() { + vector vb{}; + vb.pop_back(); +} + +#if _HAS_CXX17 +// +void test_optional_deref_lvalue() { + optional o{}; + (void) *o; +} + +void test_optional_deref_lvalue_const() { + const optional o{}; + (void) *o; +} + +void test_optional_deref_rvalue() { + optional o{}; + (void) *move(o); +} + +void test_optional_deref_rvalue_const() { + const optional o{}; + (void) *move(o); +} + +void test_optional_arrow() { + optional o{}; + (void) o.operator->(); +} + +void test_optional_arrow_const() { + const optional o{}; + (void) o.operator->(); +} + +// +void test_string_view_subscript() { + const string_view sv{"Toki"}; + (void) sv[4]; +} + +void test_string_view_front() { + const string_view sv{}; + (void) sv.front(); +} + +void test_string_view_back() { + const string_view sv{}; + (void) sv.back(); +} + +void test_string_view_remove_prefix() { + string_view sv{"Cosmos"}; + sv.remove_prefix(7); +} + +void test_string_view_remove_suffix() { + string_view sv{"Meadow"}; + sv.remove_suffix(7); +} +#endif // _HAS_CXX17 + +#if _HAS_CXX20 +// +// ranges::subrange derives from ranges::view_interface, which is hardened. +void test_ranges_view_interface_subscript() { + int arr[10]{}; + ranges::subrange sr{arr + 5, arr + 8}; + (void) sr[3]; +} + +void test_ranges_view_interface_subscript_const() { + int arr[10]{}; + const ranges::subrange sr{arr + 5, arr + 8}; + (void) sr[3]; +} + +void test_ranges_view_interface_front() { + int arr[10]{}; + ranges::subrange sr{arr + 5, arr + 5}; + (void) sr.front(); +} + +void test_ranges_view_interface_front_const() { + int arr[10]{}; + const ranges::subrange sr{arr + 5, arr + 5}; + (void) sr.front(); +} + +void test_ranges_view_interface_back() { + int arr[10]{}; + ranges::subrange sr{arr + 5, arr + 5}; + (void) sr.back(); +} + +void test_ranges_view_interface_back_const() { + int arr[10]{}; + const ranges::subrange sr{arr + 5, arr + 5}; + (void) sr.back(); +} + +// +void test_span_ctor_first_count() { + int arr[10]{}; + span sp_static{arr, 10}; +} + +void test_span_ctor_first_last() { + int arr[10]{}; + span sp_static{arr, arr + 10}; +} + +void test_span_ctor_range() { + vector v(10); + span sp_static{v}; +} + +void test_span_ctor_other() { + int arr[10]{}; + span other{arr}; + span sp_static{other}; +} + +void test_span_first_compiletime() { + int arr[10]{}; + const span sp{arr}; + (void) sp.first<11>(); +} + +void test_span_first_runtime() { + int arr[10]{}; + const span sp{arr}; + (void) sp.first(11); +} + +void test_span_last_compiletime() { + int arr[10]{}; + const span sp{arr}; + (void) sp.last<11>(); +} + +void test_span_last_runtime() { + int arr[10]{}; + const span sp{arr}; + (void) sp.last(11); +} + +void test_span_subspan_compiletime_bad_offset() { + int arr[10]{}; + const span sp{arr}; + (void) sp.subspan<11>(); +} + +void test_span_subspan_compiletime_bad_count() { + int arr[10]{}; + const span sp{arr}; + (void) sp.subspan<3, 8>(); +} + +void test_span_subspan_runtime_bad_offset() { + int arr[10]{}; + const span sp{arr}; + (void) sp.subspan(11); +} + +void test_span_subspan_runtime_bad_count() { + int arr[10]{}; + const span sp{arr}; + (void) sp.subspan(3, 8); +} + +void test_span_subscript() { + int arr[10]{}; + const span sp{arr}; + (void) sp[10]; +} + +void test_span_front() { + const span sp{}; + (void) sp.front(); +} + +void test_span_back() { + const span sp{}; + (void) sp.back(); +} +#endif // _HAS_CXX20 + +#if _HAS_CXX23 +// +void test_expected_arrow() { + expected e{unexpect, "woof"}; + (void) e.operator->(); +} + +void test_expected_arrow_const() { + const expected e{unexpect, "woof"}; + (void) e.operator->(); +} + +void test_expected_deref_lvalue() { + expected e{unexpect, "woof"}; + (void) *e; +} + +void test_expected_deref_lvalue_const() { + const expected e{unexpect, "woof"}; + (void) *e; +} + +void test_expected_deref_rvalue() { + expected e{unexpect, "woof"}; + (void) *move(e); +} + +void test_expected_deref_rvalue_const() { + const expected e{unexpect, "woof"}; + (void) *move(e); +} + +void test_expected_error_lvalue() { + expected e{1729}; + (void) e.error(); +} + +void test_expected_error_lvalue_const() { + const expected e{1729}; + (void) e.error(); +} + +void test_expected_error_rvalue() { + expected e{1729}; + (void) move(e).error(); +} + +void test_expected_error_rvalue_const() { + const expected e{1729}; + (void) move(e).error(); +} + +void test_expected_void_deref() { + const expected ev{unexpect, "woof"}; + (void) *ev; +} + +void test_expected_void_error_lvalue() { + expected ev{}; + (void) ev.error(); +} + +void test_expected_void_error_lvalue_const() { + const expected ev{}; + (void) ev.error(); +} + +void test_expected_void_error_rvalue() { + expected ev{}; + (void) move(ev).error(); +} + +void test_expected_void_error_rvalue_const() { + const expected ev{}; + (void) move(ev).error(); +} + +// +void test_mdspan_ctor_other() { + char arr[12]{}; + mdspan> other{arr, 4, 3}; + mdspan> md{other}; +} + +#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 +void test_mdspan_subscript_multidim() { + const auto str{"HissMeowPurr"}; + const mdspan> md{str, 3, 4}; + (void) md[1, 4]; +} +#endif // ^^^ defined(__cpp_multidimensional_subscript) ^^^ + +void test_mdspan_subscript_array() { + const auto str{"HissMeowPurr"}; + const mdspan> md{str, 3, 4}; + const array a_idx{1, 4}; + (void) md[a_idx]; +} + +void test_mdspan_subscript_span() { + const auto str{"HissMeowPurr"}; + const mdspan> md{str, 3, 4}; + const array a_idx{1, 4}; + const span sp_idx{a_idx}; + (void) md[sp_idx]; +} +#endif // _HAS_CXX23 + +int main(int argc, char* argv[]) { + std_testing::death_test_executive exec; + + exec.add_death_tests({ + test_array_subscript, + test_array_subscript_const, + test_array_zero_subscript, + test_array_zero_subscript_const, + test_array_zero_front, + test_array_zero_front_const, + test_array_zero_back, + test_array_zero_back_const, + test_bitset_subscript, + test_bitset_subscript_const, + test_deque_subscript, + test_deque_subscript_const, + test_deque_front, + test_deque_front_const, + test_deque_back, + test_deque_back_const, + test_deque_pop_front, + test_deque_pop_back, + test_forward_list_front, + test_forward_list_front_const, + test_forward_list_pop_front, + test_list_front, + test_list_front_const, + test_list_back, + test_list_back_const, + test_list_pop_front, + test_list_pop_back, + test_string_subscript, + test_string_subscript_const, + test_string_front, + test_string_front_const, + test_string_back, + test_string_back_const, + test_string_pop_back, + test_valarray_subscript, + test_valarray_subscript_const, + test_vector_subscript, + test_vector_subscript_const, + test_vector_front, + test_vector_front_const, + test_vector_back, + test_vector_back_const, + test_vector_pop_back, + test_vector_bool_subscript, + test_vector_bool_subscript_const, + test_vector_bool_front, + test_vector_bool_front_const, + test_vector_bool_back, + test_vector_bool_back_const, + test_vector_bool_pop_back, + +#if _HAS_CXX17 + test_optional_deref_lvalue, + test_optional_deref_lvalue_const, + test_optional_deref_rvalue, + test_optional_deref_rvalue_const, + test_optional_arrow, + test_optional_arrow_const, + test_string_view_subscript, + test_string_view_front, + test_string_view_back, + test_string_view_remove_prefix, + test_string_view_remove_suffix, +#endif // _HAS_CXX17 + +#if _HAS_CXX20 + test_ranges_view_interface_subscript, + test_ranges_view_interface_subscript_const, + test_ranges_view_interface_front, + test_ranges_view_interface_front_const, + test_ranges_view_interface_back, + test_ranges_view_interface_back_const, + test_span_ctor_first_count, + test_span_ctor_first_last, + test_span_ctor_range, + test_span_ctor_other, + test_span_first_compiletime, + test_span_first_runtime, + test_span_last_compiletime, + test_span_last_runtime, + test_span_subspan_compiletime_bad_offset, + test_span_subspan_compiletime_bad_count, + test_span_subspan_runtime_bad_offset, + test_span_subspan_runtime_bad_count, + test_span_subscript, + test_span_front, + test_span_back, +#endif // _HAS_CXX20 + +#if _HAS_CXX23 + test_expected_arrow, + test_expected_arrow_const, + test_expected_deref_lvalue, + test_expected_deref_lvalue_const, + test_expected_deref_rvalue, + test_expected_deref_rvalue_const, + test_expected_error_lvalue, + test_expected_error_lvalue_const, + test_expected_error_rvalue, + test_expected_error_rvalue_const, + test_expected_void_deref, + test_expected_void_error_lvalue, + test_expected_void_error_lvalue_const, + test_expected_void_error_rvalue, + test_expected_void_error_rvalue_const, + test_mdspan_ctor_other, +#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 + test_mdspan_subscript_multidim, +#endif // ^^^ defined(__cpp_multidimensional_subscript) ^^^ + test_mdspan_subscript_array, + test_mdspan_subscript_span, +#endif // _HAS_CXX23 + }); + + return exec.run(argc, argv); +} diff --git a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp index bdb9279c6af..2ef5d3fc05e 100644 --- a/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -97,6 +95,8 @@ void test_construction_from_array_with_unrepresentable_as_index_type_values() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; + +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_static_extent_function_with_invalid_index, test_extent_function_with_invalid_index, @@ -111,5 +111,7 @@ int main(int argc, char* argv[]) { test_construction_from_array_with_invalid_values, test_construction_from_array_with_unrepresentable_as_index_type_values, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + return exec.run(argc, argv); } diff --git a/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp index b0b5f031e7d..ce0fb911717 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -41,7 +39,7 @@ void test_construction_from_other_stride_mapping_1() { layout_stride::mapping m1{Ext{}, array{4, 1}}; // For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to // extents().fwd-prod-of-extents(r) - layout_left::mapping m2{m1}; + [[maybe_unused]] layout_left::mapping m2{m1}; } void test_construction_from_other_stride_mapping_2() { @@ -67,6 +65,8 @@ void test_stride_function() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; + +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_construction_from_extents_type_with_signed_index_type, test_construction_from_extents_type_with_unsigned_index_type, @@ -77,5 +77,7 @@ int main(int argc, char* argv[]) { test_call_operator, test_stride_function, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + return exec.run(argc, argv); } diff --git a/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp index ef72ed7be34..4de267099f8 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -41,7 +39,7 @@ void test_construction_from_other_stride_mapping_1() { layout_stride::mapping m1{Ext{}, array{1, 2}}; // For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to // extents().rev-prod-of-extents(r) - layout_right::mapping m2{m1}; + [[maybe_unused]] layout_right::mapping m2{m1}; } void test_construction_from_other_stride_mapping_2() { @@ -67,6 +65,8 @@ void test_stride_function() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; + +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_construction_from_extents_type_with_signed_index_type, test_construction_from_extents_type_with_unsigned_index_type, @@ -77,5 +77,7 @@ int main(int argc, char* argv[]) { test_call_operator, test_stride_function, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + return exec.run(argc, argv); } diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp index 4668facbd22..2c1cb19e7df 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -69,6 +67,8 @@ void test_stride_with_empty_extents() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; + +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_default_construction, test_construction_from_extents_and_array_1, @@ -79,5 +79,7 @@ int main(int argc, char* argv[]) { test_call_operator, test_stride_with_empty_extents, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + return exec.run(argc, argv); } diff --git a/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp index e1c3bba1a91..2e225ae4fa2 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -57,6 +55,8 @@ void test_size_when_index_type_is_unsigned() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; + +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_construction_from_other_mdspan, #ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 @@ -68,5 +68,7 @@ int main(int argc, char* argv[]) { test_size_when_index_type_is_signed, test_size_when_index_type_is_unsigned, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + return exec.run(argc, argv); } diff --git a/tests/std/tests/P0122R7_span_death/test.cpp b/tests/std/tests/P0122R7_span_death/test.cpp index 545b6729dec..48baa31a2f7 100644 --- a/tests/std/tests/P0122R7_span_death/test.cpp +++ b/tests/std/tests/P0122R7_span_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -261,7 +259,7 @@ void test_case_subspan_excessive_runtime_count_static_extent() { } void test_case_size_bytes_overflow() { - span sp(begin(globalArray), static_cast(-2)); // undefined behavior, not detected here + span sp(begin(globalArray), static_cast(-2)); // undefined behavior is detected here (void) sp.size_bytes(); // size of span in bytes exceeds std::numeric_limits::max() } @@ -330,11 +328,6 @@ int main(int argc, char* argv[]) { test_case_algorithm_incompatible_different_size, test_case_algorithm_incompatible_value_initialized, test_case_algorithm_incompatible_transposed, - }); -#endif // _ITERATOR_DEBUG_LEVEL != 0 - - // _CONTAINER_DEBUG_LEVEL tests - exec.add_death_tests({ test_case_constructor_first_count_incompatible_extent, test_case_constructor_first_last_incompatible_extent, test_case_constructor_range_incompatible_extent, @@ -359,6 +352,7 @@ int main(int argc, char* argv[]) { test_case_front_empty_static_extent, test_case_back_empty_static_extent, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P0220R1_optional_death/test.cpp b/tests/std/tests/P0220R1_optional_death/test.cpp index bdc284f0028..b55a59b2928 100644 --- a/tests/std/tests/P0220R1_optional_death/test.cpp +++ b/tests/std/tests/P0220R1_optional_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -47,6 +45,7 @@ void test_nullopt_operator_star_const_rvalue() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_nullopt_operator_arrow, test_nullopt_operator_arrow_const, @@ -55,6 +54,7 @@ int main(int argc, char* argv[]) { test_nullopt_operator_star_rvalue, test_nullopt_operator_star_const_rvalue, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index 37476de98b0..ce2eccd161b 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include diff --git a/tests/std/tests/P0896R4_views_counted_death/test.cpp b/tests/std/tests/P0896R4_views_counted_death/test.cpp index 1ec2d648cd4..8bb5fdba4b7 100644 --- a/tests/std/tests/P0896R4_views_counted_death/test.cpp +++ b/tests/std/tests/P0896R4_views_counted_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -17,11 +15,11 @@ void test_constructor_negative_size() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; -#ifdef _DEBUG +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_constructor_negative_size, }); -#endif // _DEBUG +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P0896R4_views_drop_death/test.cpp b/tests/std/tests/P0896R4_views_drop_death/test.cpp index 9205b10aa75..5d3996e6f7c 100644 --- a/tests/std/tests/P0896R4_views_drop_death/test.cpp +++ b/tests/std/tests/P0896R4_views_drop_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -17,11 +15,11 @@ void test_constructor_negative_size() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; -#ifdef _DEBUG +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_constructor_negative_size, }); -#endif // _DEBUG +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P0896R4_views_drop_while_death/test.cpp b/tests/std/tests/P0896R4_views_drop_while_death/test.cpp index 9cce078838d..e145c6e017e 100644 --- a/tests/std/tests/P0896R4_views_drop_while_death/test.cpp +++ b/tests/std/tests/P0896R4_views_drop_while_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -48,10 +46,12 @@ void test_view_begin() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_view_predicate, test_view_begin, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P0896R4_views_filter_death/test.cpp b/tests/std/tests/P0896R4_views_filter_death/test.cpp index 6a79aa699af..d6f119b6ea2 100644 --- a/tests/std/tests/P0896R4_views_filter_death/test.cpp +++ b/tests/std/tests/P0896R4_views_filter_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -180,11 +178,6 @@ int main(int argc, char* argv[]) { test_iter_swap_value_initialized_iterator_left, test_iter_swap_value_initialized_iterator_right, }); -#else // ^^^ test everything / test only _CONTAINER_DEBUG_LEVEL cases vvv - exec.add_death_tests({ - test_view_predicate, - test_view_begin, - }); #endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); diff --git a/tests/std/tests/P0896R4_views_iota_death/test.cpp b/tests/std/tests/P0896R4_views_iota_death/test.cpp index d38a5ad9a73..43ea1041ed4 100644 --- a/tests/std/tests/P0896R4_views_iota_death/test.cpp +++ b/tests/std/tests/P0896R4_views_iota_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -54,7 +52,7 @@ void test_misordered_iterator_sentinel_vector_iter() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; -#ifdef _DEBUG +#if _ITERATOR_DEBUG_LEVEL != 0 struct S {}; exec.add_death_tests({ @@ -124,7 +122,7 @@ int main(int argc, char* argv[]) { test_misordered_iterator_sentinel_vector_iter, test_misordered_iterator_sentinel_vector_iter, }); -#endif // _DEBUG +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P0896R4_views_take_death/test.cpp b/tests/std/tests/P0896R4_views_take_death/test.cpp index 54c26053f52..325100b5477 100644 --- a/tests/std/tests/P0896R4_views_take_death/test.cpp +++ b/tests/std/tests/P0896R4_views_take_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -17,11 +15,11 @@ void test_constructor_negative_size() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; -#ifdef _DEBUG +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_constructor_negative_size, }); -#endif // _DEBUG +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P0896R4_views_take_while_death/test.cpp b/tests/std/tests/P0896R4_views_take_while_death/test.cpp index 3ebc5d93dd9..34e3da9769a 100644 --- a/tests/std/tests/P0896R4_views_take_while_death/test.cpp +++ b/tests/std/tests/P0896R4_views_take_while_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -51,11 +49,13 @@ void test_view_const_end() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_view_predicate, test_view_end, test_view_const_end, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P1502R1_standard_library_header_units/env.lst b/tests/std/tests/P1502R1_standard_library_header_units/env.lst index 90f83ac9b67..3fc0a727c79 100644 --- a/tests/std/tests/P1502R1_standard_library_header_units/env.lst +++ b/tests/std/tests/P1502R1_standard_library_header_units/env.lst @@ -3,7 +3,7 @@ RUNALL_INCLUDE ..\..\..\universal_prefix.lst RUNALL_CROSSLIST -* PM_CL="/w14365 /D_ENFORCE_FACET_SPECIALIZATIONS=1 /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER /Zc:preprocessor" +* PM_CL="/w14365 /D_ENFORCE_FACET_SPECIALIZATIONS=1 /Zc:preprocessor" RUNALL_CROSSLIST * PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /DTEST_STANDARD=20 /std:c++20" * PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /DTEST_STANDARD=23 /std:c++latest" diff --git a/tests/std/tests/P1899R3_views_stride_death/test.cpp b/tests/std/tests/P1899R3_views_stride_death/test.cpp index ffe1afd65e6..0cebca9f4b1 100644 --- a/tests/std/tests/P1899R3_views_stride_death/test.cpp +++ b/tests/std/tests/P1899R3_views_stride_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -66,10 +64,6 @@ int main(int argc, char* argv[]) { test_iterator_advance_past_end_with_integer_overflow, test_iterator_advance_negative_min, }); -#else // ^^^ test everything / test only _CONTAINER_DEBUG_LEVEL case vvv - exec.add_death_tests({ - test_view_negative_stride, - }); #endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); diff --git a/tests/std/tests/P2374R4_views_cartesian_product_death/test.cpp b/tests/std/tests/P2374R4_views_cartesian_product_death/test.cpp index 65b850caafb..9becd5d078b 100644 --- a/tests/std/tests/P2374R4_views_cartesian_product_death/test.cpp +++ b/tests/std/tests/P2374R4_views_cartesian_product_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -79,11 +77,6 @@ int main(int argc, char* argv[]) { test_iterator_differencing, test_iterator_and_default_sentinel_differencing, }); -#else // ^^^ test everything / test only _CONTAINER_DEBUG_LEVEL cases vvv - exec.add_death_tests({ - test_view_size, - test_view_const_size, - }); #endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); diff --git a/tests/std/tests/P2442R1_views_chunk_death/test.cpp b/tests/std/tests/P2442R1_views_chunk_death/test.cpp index a62cfdfac64..026e1661311 100644 --- a/tests/std/tests/P2442R1_views_chunk_death/test.cpp +++ b/tests/std/tests/P2442R1_views_chunk_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -110,11 +108,6 @@ int main(int argc, char* argv[]) { test_fwd_iterator_advance_past_end_with_integer_overflow, test_fwd_iterator_advance_negative_min, }); -#else // ^^^ test everything / test only _CONTAINER_DEBUG_LEVEL cases vvv - exec.add_death_tests({ - test_view_negative_size_forward_range, - test_view_negative_size_input_range, - }); #endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); diff --git a/tests/std/tests/P2442R1_views_slide_death/test.cpp b/tests/std/tests/P2442R1_views_slide_death/test.cpp index 794f1e69076..fc2b1dc11bd 100644 --- a/tests/std/tests/P2442R1_views_slide_death/test.cpp +++ b/tests/std/tests/P2442R1_views_slide_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -23,10 +21,12 @@ void test_view_zero_window_size() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_view_negative_window_size, test_view_zero_window_size, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/P2443R1_views_chunk_by_death/test.cpp b/tests/std/tests/P2443R1_views_chunk_by_death/test.cpp index 07965975201..f414c1ac072 100644 --- a/tests/std/tests/P2443R1_views_chunk_by_death/test.cpp +++ b/tests/std/tests/P2443R1_views_chunk_by_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -106,11 +104,6 @@ int main(int argc, char* argv[]) { test_operator_postdecrement_value_initialized_iterator, test_operator_postdecrement_before_begin, }); -#else // ^^^ test everything / test only _CONTAINER_DEBUG_LEVEL cases vvv - exec.add_death_tests({ - test_view_predicate, - test_view_begin, - }); #endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); diff --git a/tests/std/tests/P2474R2_views_repeat_death/test.cpp b/tests/std/tests/P2474R2_views_repeat_death/test.cpp index 77ea4d02909..920a926135c 100644 --- a/tests/std/tests/P2474R2_views_repeat_death/test.cpp +++ b/tests/std/tests/P2474R2_views_repeat_death/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -129,6 +127,7 @@ void test_iter_sub_neg_huge() { int main(int argc, char* argv[]) { std_testing::death_test_executive exec; +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_view_lvalue_negative, test_view_rvalue_negative, @@ -155,5 +154,7 @@ int main(int argc, char* argv[]) { test_iter_sub_neg_huge, test_iter_sub_neg_huge, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 + return exec.run(argc, argv); } diff --git a/tests/std/tests/P2502R2_generator_death/test.cpp b/tests/std/tests/P2502R2_generator_death/test.cpp index edf602a32c4..990f5639e7f 100644 --- a/tests/std/tests/P2502R2_generator_death/test.cpp +++ b/tests/std/tests/P2502R2_generator_death/test.cpp @@ -5,8 +5,6 @@ int main() {} #else // ^^^ workaround / no workaround vvv -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -43,12 +41,14 @@ void test_end_iterator_incrementation() { int main(int argc, char** argv) { std_testing::death_test_executive exec; +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_begin_after_initial_suspend_point, test_begin_after_moving_from, test_end_iterator_dereference, test_end_iterator_incrementation, }); +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/VSO_0000000_list_iterator_debugging/test.cpp b/tests/std/tests/VSO_0000000_list_iterator_debugging/test.cpp index fae346f53c5..cd9730af067 100644 --- a/tests/std/tests/VSO_0000000_list_iterator_debugging/test.cpp +++ b/tests/std/tests/VSO_0000000_list_iterator_debugging/test.cpp @@ -532,7 +532,7 @@ int main(int argc, char* argv[]) { }); #endif // _ITERATOR_DEBUG_LEVEL == 2 -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_case_empty_front_bad, test_case_empty_cfront_bad, @@ -541,7 +541,7 @@ int main(int argc, char* argv[]) { test_case_pop_front_bad, test_case_pop_back_bad, }); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/VSO_0000000_string_view_idl/test.cpp b/tests/std/tests/VSO_0000000_string_view_idl/test.cpp index 7b52fcb5c17..d96ce9cf42e 100644 --- a/tests/std/tests/VSO_0000000_string_view_idl/test.cpp +++ b/tests/std/tests/VSO_0000000_string_view_idl/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include @@ -237,21 +235,21 @@ int main(int argc, char* argv[]) { test_case_operator_equal_incompatible_value_initialized, test_case_operator_less_incompatible_different_views, test_case_operator_less_incompatible_value_initialized, + test_case_operator_subscript_out_of_range, + test_case_front_empty, + test_case_back_empty, + test_case_remove_prefix_too_large, + test_case_remove_suffix_too_large, test_case_remove_prefix_incompatible, test_case_remove_suffix_incompatible, + test_case_null_constructor, }); #endif // _ITERATOR_DEBUG_LEVEL != 0 + // basic_string_view::_Copy_s() is a non-Standard extension that's unconditionally checked. + // See: https://learn.microsoft.com/en-us/cpp/standard-library/basic-string-view-class?view=msvc-170#_copy_s exec.add_death_tests({ - // These tests are turned on for _ITERATOR_DEBUG_LEVEL == 0 as part of - // VSO-830211 "Macro to enable runtime bounds checking for subscript operator for STL containers" - test_case_operator_subscript_out_of_range, - test_case_front_empty, - test_case_back_empty, - test_case_remove_prefix_too_large, - test_case_remove_suffix_too_large, test_case_Copy_s, - test_case_null_constructor, }); return exec.run(argc, argv); diff --git a/tests/std/tests/VSO_0677157_flist_merge_edge_cases/test.cpp b/tests/std/tests/VSO_0677157_flist_merge_edge_cases/test.cpp index 70a508eb942..dbc4cfbfac1 100644 --- a/tests/std/tests/VSO_0677157_flist_merge_edge_cases/test.cpp +++ b/tests/std/tests/VSO_0677157_flist_merge_edge_cases/test.cpp @@ -267,18 +267,16 @@ int main(int argc, char* argv[]) { test_case_empty_source_bad>, test_case_empty_target_bad, test_case_empty_target_bad>, - test_case_front_bad, - test_case_cfront_bad, }); #endif // _ITERATOR_DEBUG_LEVEL == 2 -#if _CONTAINER_DEBUG_LEVEL > 0 +#if _ITERATOR_DEBUG_LEVEL != 0 exec.add_death_tests({ test_case_front_bad, test_case_cfront_bad, test_case_pop_front_bad, }); -#endif // _CONTAINER_DEBUG_LEVEL > 0 +#endif // _ITERATOR_DEBUG_LEVEL != 0 return exec.run(argc, argv); } diff --git a/tests/std/tests/VSO_0830211_container_debugging_range_checks/test.cpp b/tests/std/tests/VSO_0830211_container_debugging_range_checks/test.cpp index 29b47050c76..9b9643b198b 100644 --- a/tests/std/tests/VSO_0830211_container_debugging_range_checks/test.cpp +++ b/tests/std/tests/VSO_0830211_container_debugging_range_checks/test.cpp @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#define _CONTAINER_DEBUG_LEVEL 1 - #include #include #include @@ -203,6 +201,10 @@ struct TestCases { test_case_operator_equal_incompatible_value_initialized, test_case_operator_less_incompatible_different_views, test_case_operator_less_incompatible_value_initialized, + test_case_operator_subscript_out_of_range_empty, + test_case_operator_subscript_out_of_range, + test_case_front_empty, + test_case_back_empty, }); if constexpr (Traits::has_arrow) { @@ -211,14 +213,9 @@ struct TestCases { test_case_operator_arrow_end_iterator, }); } -#endif // _ITERATOR_DEBUG_LEVEL != 0 - - exec.add_death_tests({ - test_case_operator_subscript_out_of_range_empty, - test_case_operator_subscript_out_of_range, - test_case_front_empty, - test_case_back_empty, - }); +#else // ^^^ _ITERATOR_DEBUG_LEVEL != 0 / _ITERATOR_DEBUG_LEVEL == 0 vvv + (void) exec; +#endif // ^^^ _ITERATOR_DEBUG_LEVEL == 0 ^^^ } }; diff --git a/tests/std/tests/modules_20_matrix.lst b/tests/std/tests/modules_20_matrix.lst index 22a3a5ea9d4..6ccb872fd81 100644 --- a/tests/std/tests/modules_20_matrix.lst +++ b/tests/std/tests/modules_20_matrix.lst @@ -3,7 +3,7 @@ RUNALL_INCLUDE ..\..\universal_prefix.lst RUNALL_CROSSLIST -* PM_CL="/w14365 /D_ENFORCE_FACET_SPECIALIZATIONS=1 /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER /Zc:preprocessor" +* PM_CL="/w14365 /D_ENFORCE_FACET_SPECIALIZATIONS=1 /Zc:preprocessor" RUNALL_CROSSLIST * PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /DTEST_STANDARD=20 /std:c++20" * PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /DTEST_STANDARD=23 /std:c++latest" diff --git a/tests/std/tests/prefix.lst b/tests/std/tests/prefix.lst index ca509bbe8fc..167a64e537d 100644 --- a/tests/std/tests/prefix.lst +++ b/tests/std/tests/prefix.lst @@ -3,4 +3,4 @@ RUNALL_INCLUDE ..\..\universal_prefix.lst RUNALL_CROSSLIST -* PM_CL="/FIforce_include.hpp /w14365 /w14668 /w15267 /D_ENFORCE_FACET_SPECIALIZATIONS=1 /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER" +* PM_CL="/FIforce_include.hpp /w14365 /w14668 /w15267 /D_ENFORCE_FACET_SPECIALIZATIONS=1" diff --git a/tests/tr1/prefix.lst b/tests/tr1/prefix.lst index 5d1ecb45c88..09eacd9984d 100644 --- a/tests/tr1/prefix.lst +++ b/tests/tr1/prefix.lst @@ -3,4 +3,4 @@ RUNALL_INCLUDE ..\universal_prefix.lst RUNALL_CROSSLIST -* PM_CL="/FIforce_include.hpp /w14668 /w15267 /D_ENFORCE_FACET_SPECIALIZATIONS=1 /D_CRT_SECURE_NO_WARNINGS /D_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER" +* PM_CL="/FIforce_include.hpp /w14668 /w15267 /D_ENFORCE_FACET_SPECIALIZATIONS=1 /D_CRT_SECURE_NO_WARNINGS" From 25cfafbb896c7a9b1ecfa8fcfe56b69b13eb9216 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 25 Feb 2025 08:08:31 +0800 Subject: [PATCH 02/13] ``: Fix ambiguity among constructors of `basic_ispanstream` (#5309) --- stl/inc/spanstream | 13 +++++++----- tests/std/tests/P0448R4_spanstream/test.cpp | 22 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/stl/inc/spanstream b/stl/inc/spanstream index 77a3bc478d9..bf189b063a5 100644 --- a/stl/inc/spanstream +++ b/stl/inc/spanstream @@ -190,6 +190,11 @@ void swap(basic_spanbuf<_Elem, _Traits>& _Left, basic_spanbuf<_Elem, _Traits>& _ _Left.swap(_Right); } +template +span<_Elem, _Extent> _As_nonconst_span(const span _Span) noexcept { + return span<_Elem, _Extent>{const_cast<_Elem*>(_Span.data()), _Span.size()}; +} + _EXPORT_STD template class basic_ispanstream : public basic_istream<_Elem, _Traits> { private: @@ -207,9 +212,6 @@ public: explicit basic_ispanstream(_STD span<_Elem> _Span, ios_base::openmode _Which = ios_base::in) : _Mybase(_STD addressof(_Buf)), _Buf(_Span, _Which | ios_base::in) {} - explicit basic_ispanstream(_STD span _Span) - : basic_ispanstream(_STD span<_Elem>{const_cast<_Elem*>(_Span.data()), _Span.size()}) {} - basic_ispanstream(const basic_ispanstream&) = delete; basic_ispanstream(basic_ispanstream&& _Right) : _Mybase(_STD move(_Right)), _Buf(_STD move(_Right._Buf)) { @@ -220,7 +222,8 @@ public: requires ( !convertible_to<_ReadOnlyRange, _STD span<_Elem>> && convertible_to<_ReadOnlyRange, _STD span>) explicit basic_ispanstream(_ReadOnlyRange&& _Range) - : basic_ispanstream(static_cast<_STD span>(_STD forward<_ReadOnlyRange>(_Range))) {} + : basic_ispanstream( + _STD _As_nonconst_span(static_cast<_STD span>(_STD forward<_ReadOnlyRange>(_Range)))) {} basic_ispanstream& operator=(const basic_ispanstream&) = delete; @@ -254,7 +257,7 @@ public: !convertible_to<_ReadOnlyRange, _STD span<_Elem>> && convertible_to<_ReadOnlyRange, _STD span>) void span(_ReadOnlyRange&& _Range) noexcept { const auto _Sp = static_cast<_STD span>(_STD forward<_ReadOnlyRange>(_Range)); - this->span(_STD span<_Elem>{const_cast<_Elem*>(_Sp.data()), _Sp.size()}); + rdbuf()->span(_STD _As_nonconst_span(_Sp)); } private: diff --git a/tests/std/tests/P0448R4_spanstream/test.cpp b/tests/std/tests/P0448R4_spanstream/test.cpp index 77f69db28d8..64e91731b63 100644 --- a/tests/std/tests/P0448R4_spanstream/test.cpp +++ b/tests/std/tests/P0448R4_spanstream/test.cpp @@ -674,6 +674,28 @@ void test_ispanstream() { assert(static_cast(special_range_constructed.rdbuf())->epptr() == nullptr); } + { // GH-5308: : Constructing ispanstream from string no longer compiles since VS 17.13 + basic_string str(42, static_cast('*')); + basic_ispanstream from_string_constructed{str}; + assert(from_string_constructed.span().data() == str.data()); + assert(static_cast(from_string_constructed.rdbuf())->eback() == str.data()); + assert(static_cast(from_string_constructed.rdbuf())->gptr() == str.data()); + assert(static_cast(from_string_constructed.rdbuf())->egptr() == str.data() + str.size()); + assert(static_cast(from_string_constructed.rdbuf())->pbase() == nullptr); + assert(static_cast(from_string_constructed.rdbuf())->pptr() == nullptr); + assert(static_cast(from_string_constructed.rdbuf())->epptr() == nullptr); + + basic_ispanstream from_string_reset{span{}}; + from_string_reset.span(str); + assert(from_string_reset.span().data() == str.data()); + assert(static_cast(from_string_reset.rdbuf())->eback() == str.data()); + assert(static_cast(from_string_reset.rdbuf())->gptr() == str.data()); + assert(static_cast(from_string_reset.rdbuf())->egptr() == str.data() + str.size()); + assert(static_cast(from_string_reset.rdbuf())->pbase() == nullptr); + assert(static_cast(from_string_reset.rdbuf())->pptr() == nullptr); + assert(static_cast(from_string_reset.rdbuf())->epptr() == nullptr); + } + { // span CharT buffer[10]; basic_ispanstream is{span{buffer}}; From 3b2a52e0940dd1b8e13734487daa5f8b56ea01ef Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 24 Feb 2025 16:14:37 -0800 Subject: [PATCH 03/13] Unblock RWC by extending the static call operator workaround (#5312) Co-authored-by: David Justo --- stl/inc/yvals_core.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 1abaf85d260..3525693fa21 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -2014,7 +2014,9 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #define _STL_INTERNAL_STATIC_ASSERT(...) #endif // ^^^ !defined(_ENABLE_STL_INTERNAL_CHECK) ^^^ -#ifdef __CUDACC__ // TRANSITION, CUDA 12.4 doesn't have downlevel support for static call operators +#if defined(__CUDACC__) || (defined(__clang__) && __clang_major__ < 16) +// TRANSITION, CUDA 12.4 doesn't have downlevel support for static call operators. +// TRANSITION, VSO-2397560, temporary workaround for Real World Code relying on ancient Clang versions. #define _STATIC_CALL_OPERATOR #define _CONST_CALL_OPERATOR const #define _STATIC_LAMBDA From 0d8f517ae3828284fed594741b847db940167a59 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Mon, 3 Mar 2025 10:05:38 -0800 Subject: [PATCH 04/13] Destructor Tombstones (#5318) --- stl/inc/any | 14 ++ stl/inc/deque | 12 ++ stl/inc/exception | 6 + stl/inc/forward_list | 9 + stl/inc/functional | 10 + stl/inc/list | 10 + stl/inc/memory | 26 +++ stl/inc/optional | 10 + stl/inc/regex | 5 + stl/inc/valarray | 8 + stl/inc/variant | 11 + stl/inc/vector | 19 ++ stl/inc/xhash | 10 + stl/inc/xpolymorphic_allocator.h | 7 + stl/inc/xstring | 19 ++ stl/inc/xtree | 10 + stl/inc/yvals.h | 8 + tests/std/test.lst | 1 + .../GH_005315_destructor_tombstones/env.lst | 6 + .../GH_005315_destructor_tombstones/test.cpp | 188 ++++++++++++++++++ .../test.cpp | 22 +- 21 files changed, 401 insertions(+), 10 deletions(-) create mode 100644 tests/std/tests/GH_005315_destructor_tombstones/env.lst create mode 100644 tests/std/tests/GH_005315_destructor_tombstones/test.cpp diff --git a/stl/inc/any b/stl/inc/any index 9f776996ac0..2f33cb0545d 100644 --- a/stl/inc/any +++ b/stl/inc/any @@ -158,6 +158,20 @@ public: ~any() noexcept { reset(); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + // The two least significant bits (LSBs) of _Storage._TypeData encode whether we're in _Small, _Big, + // or _Trivial mode; see _Rep(). The rest of the bits encode the type_info pointer that's used + // to remember what type of object we're storing; see _TypeInfo(). So, we'll take the tombstone value, + // clear out the two LSBs with the _Rep_mask, then set the bits for _Small mode. + // _Small mode will prevent the most misuse, as the pseudo-vtable will be used for _Destroy, _Copy, and _Move. + // _Big mode wouldn't use the pseudo-vtable for _Move, and _Trivial mode doesn't have a pseudo-vtable at all. + const uintptr_t _Tombstone_value{_MSVC_STL_UINTPTR_TOMBSTONE_VALUE}; + // Set the pseudo-vtable pointer: + _Storage._SmallStorage._RTTI = reinterpret_cast(_Tombstone_value); + // Set the combined type_info pointer and representation mode bits: + _Storage._TypeData = (_Tombstone_value & ~_Rep_mask) | static_cast(_Any_representation::_Small); +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES } // Assignment [any.assign] diff --git a/stl/inc/deque b/stl/inc/deque index b6fcee81c38..05793b8ac41 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -555,6 +555,18 @@ public: _Deque_val() noexcept : _Map(), _Mapsize(0), _Myoff(0), _Mysize(0) {} +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + ~_Deque_val() noexcept { + if constexpr (is_pointer_v<_Mapptr>) { + const auto _Tombstone{reinterpret_cast<_Mapptr>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Map = _Tombstone; + _Mapsize = 0; + _Myoff = 0; + _Mysize = 0; + } + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + _Map_difference_type _Getblock(size_type _Off) const noexcept { // NB: _Mapsize and _Block_size are guaranteed to be powers of 2 return static_cast<_Map_difference_type>((_Off / _Block_size) & (_Mapsize - 1)); diff --git a/stl/inc/exception b/stl/inc/exception index 3d07bb824c6..9cf770faff2 100644 --- a/stl/inc/exception +++ b/stl/inc/exception @@ -234,6 +234,12 @@ public: ~exception_ptr() noexcept { __ExceptionPtrDestroy(this); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Data1 = _Tombstone; + _Data2 = _Tombstone; +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES } exception_ptr(const exception_ptr& _Rhs) noexcept { diff --git a/stl/inc/forward_list b/stl/inc/forward_list index f0fb5398ef5..7d7dfb8db11 100644 --- a/stl/inc/forward_list +++ b/stl/inc/forward_list @@ -277,6 +277,15 @@ public: _Flist_val() noexcept : _Myhead() {} // initialize data +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + ~_Flist_val() noexcept { + if constexpr (is_pointer_v<_Nodeptr>) { + const auto _Tombstone{reinterpret_cast<_Nodeptr>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Myhead = _Tombstone; + } + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + _Nodeptr _Before_head() const noexcept { // return pointer to the "before begin" pseudo node return pointer_traits<_Nodeptr>::pointer_to(reinterpret_cast<_Node&>(const_cast<_Nodeptr&>(_Myhead))); } diff --git a/stl/inc/functional b/stl/inc/functional index 33d51be9a3b..e386dc35c1f 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -928,6 +928,11 @@ public: ~_Func_class() noexcept { _Tidy(); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + const auto _Tombstone{reinterpret_cast<_Ptrt*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Set(_Tombstone); +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES } protected: @@ -1934,6 +1939,11 @@ public: // Do cleanup in this class destructor rather than base, // so that if object construction throws, the unnecessary cleanup isn't called. this->_Checked_destroy(this->_Data); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + this->_Data._Impl = _Tombstone; +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES } move_only_function& operator=(nullptr_t) noexcept { diff --git a/stl/inc/list b/stl/inc/list index 1d67c2e4810..446649dcef4 100644 --- a/stl/inc/list +++ b/stl/inc/list @@ -352,6 +352,16 @@ public: _List_val() noexcept : _Myhead(), _Mysize(0) {} // initialize data +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + ~_List_val() noexcept { + if constexpr (is_pointer_v<_Nodeptr>) { + const auto _Tombstone{reinterpret_cast<_Nodeptr>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Myhead = _Tombstone; + _Mysize = 0; + } + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + void _Orphan_ptr2(_Nodeptr _Ptr) noexcept { // orphan iterators with specified node pointers #if _ITERATOR_DEBUG_LEVEL == 2 _Lockit _Lock(_LOCK_DEBUG); diff --git a/stl/inc/memory b/stl/inc/memory index 3770d48706d..883a16076f7 100644 --- a/stl/inc/memory +++ b/stl/inc/memory @@ -1311,7 +1311,15 @@ protected: constexpr _Ptr_base() noexcept = default; +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + ~_Ptr_base() noexcept { + const uintptr_t _Tombstone_value{_MSVC_STL_UINTPTR_TOMBSTONE_VALUE}; + _Ptr = reinterpret_cast(_Tombstone_value); + _Rep = reinterpret_cast<_Ref_count_base*>(_Tombstone_value); + } +#else // ^^^ _MSVC_STL_DESTRUCTOR_TOMBSTONES / !_MSVC_STL_DESTRUCTOR_TOMBSTONES vvv ~_Ptr_base() = default; +#endif // ^^^ !_MSVC_STL_DESTRUCTOR_TOMBSTONES ^^^ template void _Move_construct_from(_Ptr_base<_Ty2>&& _Right) noexcept { @@ -3418,6 +3426,15 @@ public: if (_Mypair._Myval2) { _Mypair._Get_first()(_Mypair._Myval2); } + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + if constexpr (is_pointer_v) { + if (!_STD _Is_constant_evaluated()) { + const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Mypair._Myval2 = _Tombstone; + } + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES } _NODISCARD _CONSTEXPR23 _Dx& get_deleter() noexcept { @@ -3555,6 +3572,15 @@ public: if (_Mypair._Myval2) { _Mypair._Get_first()(_Mypair._Myval2); } + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + if constexpr (is_pointer_v) { + if (!_STD _Is_constant_evaluated()) { + const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Mypair._Myval2 = _Tombstone; + } + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES } _NODISCARD _CONSTEXPR23 _Dx& get_deleter() noexcept { diff --git a/stl/inc/optional b/stl/inc/optional index 196374892eb..14cf3f65127 100644 --- a/stl/inc/optional +++ b/stl/inc/optional @@ -88,6 +88,9 @@ struct _Optional_destruct_base { // either contains a value of _Ty or is empty ( : _Value(_STD invoke(_STD forward<_Fn>(_Func), _STD forward<_Ux>(_Arg))), _Has_value{true} {} #endif // _HAS_CXX23 + // For the trivially destructible case, we can't add a destructor for _MSVC_STL_DESTRUCTOR_TOMBSTONES, due to + // N5001 [optional.dtor]/2: "Remarks: If is_trivially_destructible_v is true, then this destructor is trivial." + _CONSTEXPR20 void reset() noexcept { _Has_value = false; } @@ -104,6 +107,13 @@ struct _Optional_destruct_base<_Ty, false> { // either contains a value of _Ty o _CONSTEXPR20 ~_Optional_destruct_base() noexcept { if (_Has_value) { _Value.~_Ty(); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + // For the non-trivially destructible case, we can set the optional to be empty. + // We don't attempt to scribble over the bytes of the object's storage because that could be expensive + // and we don't know whether the object has an invalid representation, much less what it could be. + _Has_value = false; +#endif } } diff --git a/stl/inc/regex b/stl/inc/regex index d4988266506..27b63c11e2d 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -1923,6 +1923,11 @@ public: ~basic_regex() noexcept { _Tidy(); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + const auto _Tombstone{reinterpret_cast<_Root_node*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Rep = _Tombstone; +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES } basic_regex& operator=(const basic_regex& _Right) { diff --git a/stl/inc/valarray b/stl/inc/valarray index bb30c016487..a6a0909d9a8 100644 --- a/stl/inc/valarray +++ b/stl/inc/valarray @@ -137,6 +137,14 @@ public: ~valarray() noexcept { _Tidy_deallocate(); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + const auto _Tombstone{reinterpret_cast<_Ty*>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Myptr = _Tombstone; + + // _Tidy_deallocate() sets _Mysize to 0, so we don't need to set it here. + _STL_INTERNAL_CHECK(_Mysize == 0); +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES } valarray& operator=(const valarray& _Right) { diff --git a/stl/inc/variant b/stl/inc/variant index 8d472e9ca24..0679d94022d 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -756,6 +756,10 @@ public: _Which{static_cast<_Index_t>(_Idx)} { // initialize alternative _Idx from _Args... } + // For the trivially destructible case, we can't add a destructor for _MSVC_STL_DESTRUCTOR_TOMBSTONES, due to + // N5001 [variant.dtor]/2: "Remarks: If is_trivially_destructible_v is true for all Ti, + // then this destructor is trivial." + _NODISCARD constexpr bool valueless_by_exception() const noexcept { // does this variant NOT hold a value? return _Which < 0; } @@ -839,6 +843,13 @@ struct _Variant_destroy_layer_ : _Variant_base<_Types...> { // destruction behav _CONSTEXPR20 ~_Variant_destroy_layer_() noexcept { // Destroy contained value, if any this->_Destroy(); + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + // For the non-trivially destructible case, we can set the variant to be valueless. + // We don't attempt to scribble over the bytes of the object's storage because that could be expensive + // and we don't know whether the object has an invalid representation, much less what it could be. + this->_Set_index(variant_npos); +#endif } _Variant_destroy_layer_() = default; diff --git a/stl/inc/vector b/stl/inc/vector index 1450120f061..a4dcee2cfbe 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -402,6 +402,19 @@ public: _CONSTEXPR20 _Vector_val(pointer _First, pointer _Last, pointer _End) noexcept : _Myfirst(_First), _Mylast(_Last), _Myend(_End) {} +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + _CONSTEXPR20 ~_Vector_val() noexcept { + if constexpr (is_pointer_v) { + if (!_STD _Is_constant_evaluated()) { + const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Myfirst = _Tombstone; + _Mylast = _Tombstone; + _Myend = _Tombstone; + } + } + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + _CONSTEXPR20 void _Swap_val(_Vector_val& _Right) noexcept { this->_Swap_proxy_and_iterators(_Right); swap(_Myfirst, _Right._Myfirst); // intentional ADL @@ -2851,6 +2864,12 @@ public: auto&& _Alproxy = _GET_PROXY_ALLOCATOR(_Alvbase, this->_Getal()); _Delete_plain_internal(_Alproxy, _STD exchange(this->_Myproxy, nullptr)); #endif // _ITERATOR_DEBUG_LEVEL != 0 + +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + // Destroying _Myvec will store tombstones in its pointers, setting its apparent size to 0. + // We should also set our _Mysize to 0 for consistency, allowing precondition hardening to detect UB earlier. + _Mysize = 0; +#endif } _CONSTEXPR20 _Alvbase& _Getal() noexcept { diff --git a/stl/inc/xhash b/stl/inc/xhash index 0df519a86ff..beb31a12d26 100644 --- a/stl/inc/xhash +++ b/stl/inc/xhash @@ -436,6 +436,16 @@ public: #endif // _ENABLE_STL_INTERNAL_CHECK } +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + ~_Hash() noexcept { + // Destroying _List and _Vec will store tombstones in their pointers. + // We'll also set _Mask and _Maxidx back to the values used by _Hash's default constructor. Although this + // doesn't provide the same benefit as zeroing out size fields, it's consistent with the pattern elsewhere. + _Mask = _Min_buckets - 1; + _Maxidx = _Min_buckets; + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + private: void _Swap_val(_Hash& _Right) noexcept { // swap contents with equal allocator _Hash _Right _List._Swap_val(_Right._List); diff --git a/stl/inc/xpolymorphic_allocator.h b/stl/inc/xpolymorphic_allocator.h index ea0825c7c9f..53fe25e7942 100644 --- a/stl/inc/xpolymorphic_allocator.h +++ b/stl/inc/xpolymorphic_allocator.h @@ -221,6 +221,13 @@ namespace pmr { polymorphic_allocator& operator=(const polymorphic_allocator&) = delete; +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + ~polymorphic_allocator() noexcept { + const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Resource = _Tombstone; + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + _NODISCARD_RAW_PTR_ALLOC __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count) { // get space for _Count objects of type _Ty from _Resource void* const _Vp = _Resource->allocate(_Get_size_of_n(_Count), alignof(_Ty)); diff --git a/stl/inc/xstring b/stl/inc/xstring index 52926040086..85f7f8a89fe 100644 --- a/stl/inc/xstring +++ b/stl/inc/xstring @@ -401,6 +401,25 @@ public: _CONSTEXPR20 _String_val() noexcept : _Bx() {} +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + _CONSTEXPR20 ~_String_val() noexcept { + if constexpr (is_pointer_v) { + if (!_STD _Is_constant_evaluated()) { + const auto _Tombstone{reinterpret_cast(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Bx._Ptr = _Tombstone; + _Mysize = 0; + _Myres = (_Small_string_capacity + 1) | _Alloc_mask; // first capacity when entering large mode + + // The capacity indicates whether we're in small mode or large mode; see _Large_mode_engaged(). + // The string would be usable in small mode, so we need large mode for the tombstone to be effective. + // `_Small_string_capacity + 1` would be sufficient to make _Large_mode_engaged() return true. However, + // basic_string uses a "roundup mask" when allocating; see _Calculate_growth(). So to avoid confusing + // the SSO logic, we use the first capacity that would normally be used when entering large mode. + } + } + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + // length of internal buffer, [1, 16] (NB: used by the debugger visualizer) static constexpr size_type _BUF_SIZE = 16 / sizeof(value_type) < 1 ? 1 : 16 / sizeof(value_type); // roundup mask for allocated buffers, [0, 15] diff --git a/stl/inc/xtree b/stl/inc/xtree index 9738b831130..d0237880371 100644 --- a/stl/inc/xtree +++ b/stl/inc/xtree @@ -449,6 +449,16 @@ public: _Tree_val() noexcept : _Myhead(), _Mysize(0) {} +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES + ~_Tree_val() noexcept { + if constexpr (is_pointer_v<_Nodeptr>) { + const auto _Tombstone{reinterpret_cast<_Nodeptr>(_MSVC_STL_UINTPTR_TOMBSTONE_VALUE)}; + _Myhead = _Tombstone; + _Mysize = 0; + } + } +#endif // _MSVC_STL_DESTRUCTOR_TOMBSTONES + enum _Redbl { // colors for link to parent _Red, _Black diff --git a/stl/inc/yvals.h b/stl/inc/yvals.h index bae84f1e6b1..c8cfa973615 100644 --- a/stl/inc/yvals.h +++ b/stl/inc/yvals.h @@ -272,6 +272,14 @@ _EMIT_STL_ERROR(STL1008, "_STL_CALL_ABORT_INSTEAD_OF_INVALID_PARAMETER has been #define _STL_INTERNAL_CHECK(...) _Analysis_assume_(__VA_ARGS__) #endif // ^^^ !defined(_ENABLE_STL_INTERNAL_CHECK) ^^^ +#ifndef _MSVC_STL_DESTRUCTOR_TOMBSTONES +#define _MSVC_STL_DESTRUCTOR_TOMBSTONES 0 +#endif + +#ifndef _MSVC_STL_UINTPTR_TOMBSTONE_VALUE +#define _MSVC_STL_UINTPTR_TOMBSTONE_VALUE uintptr_t{19937} +#endif + #include #ifdef _STATIC_CPPLIB diff --git a/tests/std/test.lst b/tests/std/test.lst index e188823bfcf..1c40a3294d8 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -254,6 +254,7 @@ tests\GH_004845_logical_operator_traits_with_non_bool_constant tests\GH_004929_internal_tag_constructors tests\GH_004930_char_traits_user_specialization tests\GH_005090_stl_hardening +tests\GH_005315_destructor_tombstones tests\LWG2381_num_get_floating_point tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function diff --git a/tests/std/tests/GH_005315_destructor_tombstones/env.lst b/tests/std/tests/GH_005315_destructor_tombstones/env.lst new file mode 100644 index 00000000000..2afe136720a --- /dev/null +++ b/tests/std/tests/GH_005315_destructor_tombstones/env.lst @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst +RUNALL_CROSSLIST +* PM_CL="/D_MSVC_STL_DESTRUCTOR_TOMBSTONES=1" diff --git a/tests/std/tests/GH_005315_destructor_tombstones/test.cpp b/tests/std/tests/GH_005315_destructor_tombstones/test.cpp new file mode 100644 index 00000000000..7e9a0bb290b --- /dev/null +++ b/tests/std/tests/GH_005315_destructor_tombstones/test.cpp @@ -0,0 +1,188 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// env.lst defines _MSVC_STL_DESTRUCTOR_TOMBSTONES to 1. + +#ifdef _M_CEE // work around a sporadic hang in /clr configurations +int main() {} +#else // ^^^ workaround / no workaround vvv + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if _HAS_CXX17 +#include +#include +#include +#include +#endif + +#include + +using namespace std; + +// A good test is one that consistently gets away with UB when destructor tombstones are disabled, +// but reliably terminates when destructor tombstones are enabled. +// A great test is when not even ASan can detect the UB when destructor tombstones are disabled. +// (Note that it may not always be possible to write a great test. For example, when +// dynamically allocated sentinel nodes are involved, ASan is extremely good at detecting UB.) + +template +void call_on_destroyed_object(Func func, Args&&... args) { + alignas(T) unsigned char storage[sizeof(T)]{}; + T& t = *::new (static_cast(storage)) T(forward(args)...); + t.~T(); + func(t); // obviously undefined behavior +} + +void test_vector() { + call_on_destroyed_object>([](auto& v) { v.push_back(17.29); }); +} +void test_vector_bool() { + call_on_destroyed_object>([](auto& vb) { vb.push_back(true); }); +} +void test_deque() { + call_on_destroyed_object>([](auto& d) { d.shrink_to_fit(); }); +} +void test_list() { + call_on_destroyed_object>([](auto& l) { (void) (l.begin() == l.end()); }); +} +void test_forward_list() { + call_on_destroyed_object>([](auto& fl) { (void) distance(fl.begin(), fl.end()); }); +} +void test_set() { + call_on_destroyed_object>([](auto& s) { (void) (s.begin() == s.end()); }); +} +void test_unordered_set() { + call_on_destroyed_object>([](auto& us) { (void) (us.begin() == us.end()); }); +} +void test_string() { + call_on_destroyed_object([](auto& str) { str[0] = '\0'; }); // 1-byte characters +} +void test_wstring() { + call_on_destroyed_object([](auto& wstr) { wstr[0] = L'\0'; }); // 2-byte characters +} +void test_u32string() { + call_on_destroyed_object([](auto& u32str) { u32str[0] = U'\0'; }); // 4-byte characters +} +void test_unique_ptr() { + call_on_destroyed_object>([](auto& up) { up.reset(); }); +} +void test_unique_ptr_array() { + call_on_destroyed_object>([](auto& upa) { upa.reset(); }); +} +void test_shared_ptr() { + call_on_destroyed_object>([](auto& sp) { sp.reset(); }); +} +void test_weak_ptr() { + call_on_destroyed_object>([](auto& wp) { (void) wp.expired(); }); +} +void test_exception_ptr() { + call_on_destroyed_object([](auto& ep) { ep = nullptr; }); +} +void test_function() { + call_on_destroyed_object>([](auto& f) { f = nullptr; }); +} +void test_regex() { + call_on_destroyed_object([](auto& r) { (void) r.mark_count(); }); +} +void test_valarray() { + call_on_destroyed_object>([](auto& va) { va.resize(10); }); +} + +#if _HAS_CXX17 +void test_any() { + call_on_destroyed_object([](auto& a) { any other{move(a)}; }); +} +void test_optional() { + call_on_destroyed_object>([](auto& o) { o.value() = "woof"; }, "meow"); +} +void test_variant() { + call_on_destroyed_object>([](auto& var) { get(var) = "woof"; }, "meow"); +} +void test_polymorphic_allocator() { + call_on_destroyed_object>([](auto& pa) { (void) pa.allocate(1); }); +} +#endif // _HAS_CXX17 + +#if _HAS_CXX23 +void test_move_only_function() { + call_on_destroyed_object>([](auto& mof) { mof = nullptr; }); +} +#endif // _HAS_CXX23 + +int main(int argc, char* argv[]) { + std_testing::death_test_executive exec; + + exec.add_death_tests({ + test_vector, + test_vector_bool, + test_deque, + test_list, + test_forward_list, + test_set, + test_unordered_set, + test_string, + test_wstring, + test_u32string, + test_unique_ptr, + test_unique_ptr_array, + test_shared_ptr, + test_weak_ptr, + test_exception_ptr, + test_function, + test_regex, + test_valarray, + +#if _HAS_CXX17 + test_any, + test_optional, + test_variant, + test_polymorphic_allocator, +#endif // _HAS_CXX17 + +#if _HAS_CXX23 + test_move_only_function, +#endif // _HAS_CXX23 + }); + + return exec.run(argc, argv); +} + +#if _HAS_CXX20 +// Verify that destructor tombstones don't interfere with constexpr. +constexpr bool test_constexpr() { // COMPILE-ONLY + vector v(10, 3.14); + vector vb(10, true); + string str{"cats"}; + wstring wstr{L"meow"}; + u32string u32str{U"purr"}; + optional o{"hiss"}; + +#if _HAS_CXX23 + unique_ptr up{new double{3.14}}; + unique_ptr upa{new double[10]{}}; +#endif // _HAS_CXX23 + + return true; +} + +static_assert(test_constexpr()); +#endif // _HAS_CXX20 + +#endif // ^^^ no workaround ^^^ diff --git a/tests/std/tests/VSO_0000000_wcfb01_idempotent_container_destructors/test.cpp b/tests/std/tests/VSO_0000000_wcfb01_idempotent_container_destructors/test.cpp index 7f320239cd1..ca6d179e981 100644 --- a/tests/std/tests/VSO_0000000_wcfb01_idempotent_container_destructors/test.cpp +++ b/tests/std/tests/VSO_0000000_wcfb01_idempotent_container_destructors/test.cpp @@ -7,23 +7,25 @@ using namespace std; +#if _MSVC_STL_DESTRUCTOR_TOMBSTONES +#error This test is fundamentally incompatible with destructor tombstones. +#endif + int main() { - // this is nonstandard behavior, but historically our containers - // have allowed it so we want to preserve it in the current ABI - // - // TRANSITION, ABI - // in the next ABI breaking release we will change this behavior to terminate programs that do nonstandard things - // like this + // Idempotent destruction is an abomination that our `string` and `vector` have historically allowed. + // We're preserving it for the time being, except when destructor tombstones are enabled. + + // TRANSITION, ABI: In the next ABI-breaking release, we'll stop supporting this nonstandard usage. { // small string - char buff[sizeof(string)]; + alignas(string) char buff[sizeof(string)]; string& s = *::new (buff) string; s.~string(); s.~string(); } { // big string - char buff[sizeof(string)]; + alignas(string) char buff[sizeof(string)]; string& s = *::new (buff) string("a really long string that is going to trigger separate allocation"); s.~string(); s.~string(); @@ -32,14 +34,14 @@ int main() { using vecT = vector; { // empty vector - char buff[sizeof(vecT)]; + alignas(vecT) char buff[sizeof(vecT)]; vecT& v = *::new (buff) vecT; v.~vecT(); v.~vecT(); } { // data vector - char buff[sizeof(vecT)]; + alignas(vecT) char buff[sizeof(vecT)]; vecT& v = *::new (buff) vecT; v.push_back(42); v.~vecT(); From 38040787550a644afeac8e7e76b417aa07b11ce6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 13 Mar 2025 11:00:16 -0700 Subject: [PATCH 05/13] Toolset update: VS 2022 17.14 Preview 2, Clang 19.1.5 (#5335) --- .github/workflows/update-status-chart.yml | 2 +- README.md | 4 +- azure-devops/checkout-self.yml | 1 + azure-devops/config.yml | 2 +- azure-devops/create-1es-hosted-pool.ps1 | 92 ++++++++++++++++--- azure-devops/provision-image.ps1 | 10 +- stl/inc/__msvc_bit_utils.hpp | 7 +- stl/inc/__msvc_int128.hpp | 3 +- stl/inc/__msvc_iter_core.hpp | 2 +- stl/inc/__msvc_ranges_tuple_formatter.hpp | 3 +- stl/inc/array | 14 +-- stl/inc/cmath | 3 +- stl/inc/string | 40 ++++---- stl/inc/utility | 4 +- stl/inc/xmemory | 4 +- stl/inc/yvals_core.h | 33 ++----- tests/libcxx/expected_results.txt | 1 + .../test.cpp | 3 - .../test.compile.pass.cpp | 9 ++ tests/std/tests/P0019R8_atomic_ref/test.cpp | 4 - .../test.cpp | 4 +- tests/std/tests/P0896R4_views_take/test.cpp | 23 ++--- tools/format/CMakeLists.txt | 2 +- 23 files changed, 148 insertions(+), 122 deletions(-) diff --git a/.github/workflows/update-status-chart.yml b/.github/workflows/update-status-chart.yml index 7379faf7c48..12ae8109d65 100644 --- a/.github/workflows/update-status-chart.yml +++ b/.github/workflows/update-status-chart.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: ">=22.2.0" + node-version: ">=23.9.0" - name: Install Packages run: | npm ci diff --git a/README.md b/README.md index 2600f98cee3..4e306f137e4 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.14 Preview 1 or later. +1. Install Visual Studio 2022 17.14 Preview 2 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. @@ -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.14 Preview 1 or later. +1. Install Visual Studio 2022 17.14 Preview 2 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. diff --git a/azure-devops/checkout-self.yml b/azure-devops/checkout-self.yml index 7fac477f5b8..69fbb011639 100644 --- a/azure-devops/checkout-self.yml +++ b/azure-devops/checkout-self.yml @@ -11,6 +11,7 @@ steps: submodules: false fetchDepth: 1 fetchTags: false + retryCountOnTaskFailure: 4 - script: | git clean --quiet -x -d -f -f displayName: 'Clean after checkout' diff --git a/azure-devops/config.yml b/azure-devops/config.yml index 732fe64fe9f..60d59b5502a 100644 --- a/azure-devops/config.yml +++ b/azure-devops/config.yml @@ -5,7 +5,7 @@ variables: - name: poolName - value: 'StlBuild-2025-02-15T0137-Pool' + value: 'StlBuild-2025-03-11T1203-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 aa99a024346..7dce5e9bca5 100644 --- a/azure-devops/create-1es-hosted-pool.ps1 +++ b/azure-devops/create-1es-hosted-pool.ps1 @@ -22,7 +22,7 @@ $ImageSku = '2025-datacenter-azure-edition' $LogFile = '1es-hosted-pool.log' $ProgressActivity = 'Preparing STL CI pool' -$TotalProgress = 26 +$TotalProgress = 38 $CurrentProgress = 1 <# @@ -103,7 +103,30 @@ $AdminPWSecure = New-Password $Credential = New-Object System.Management.Automation.PSCredential ('AdminUser', $AdminPWSecure) #################################################################################################### -Display-ProgressBar -Status 'Creating virtual network' +Display-ProgressBar -Status 'Creating public IP address' + +$PublicIpAddressName = $ResourceGroupName + '-PublicIpAddress' +$PublicIpAddress = New-AzPublicIpAddress ` + -Name $PublicIpAddressName ` + -ResourceGroupName $ResourceGroupName ` + -Location $Location ` + -Sku 'Standard' ` + -AllocationMethod 'Static' + +#################################################################################################### +Display-ProgressBar -Status 'Creating NAT gateway' + +$NatGatewayName = $ResourceGroupName + '-NatGateway' +$NatGateway = New-AzNatGateway ` + -Name $NatGatewayName ` + -ResourceGroupName $ResourceGroupName ` + -Location $Location ` + -IdleTimeoutInMinutes 10 ` + -Sku 'Standard' ` + -PublicIpAddress $PublicIpAddress + +#################################################################################################### +Display-ProgressBar -Status 'Creating network security group' $NetworkSecurityGroupName = $ResourceGroupName + '-NetworkSecurity' $NetworkSecurityGroup = New-AzNetworkSecurityGroup ` @@ -111,12 +134,23 @@ $NetworkSecurityGroup = New-AzNetworkSecurityGroup ` -ResourceGroupName $ResourceGroupName ` -Location $Location +#################################################################################################### +Display-ProgressBar -Status 'Creating virtual network subnet config' + +# TRANSITION, 2025-09-30: "On September 30, 2025, default outbound access for new deployments will be retired." +# https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/default-outbound-access +# We're using `-DefaultOutboundAccess $false` to opt-in early. $SubnetName = $ResourceGroupName + '-Subnet' $Subnet = New-AzVirtualNetworkSubnetConfig ` -Name $SubnetName ` -AddressPrefix '10.0.0.0/16' ` + -DefaultOutboundAccess $false ` + -NatGateway $NatGateway ` -NetworkSecurityGroup $NetworkSecurityGroup +#################################################################################################### +Display-ProgressBar -Status 'Creating virtual network' + $VirtualNetworkName = $ResourceGroupName + '-Network' $VirtualNetwork = New-AzVirtualNetwork ` -Name $VirtualNetworkName ` @@ -136,7 +170,7 @@ $Nic = New-AzNetworkInterface ` -Subnet $VirtualNetwork.Subnets[0] #################################################################################################### -Display-ProgressBar -Status 'Creating prototype VM' +Display-ProgressBar -Status 'Creating prototype VM config' # Previously: -Priority 'Spot' $VM = New-AzVMConfig ` @@ -145,6 +179,9 @@ $VM = New-AzVMConfig ` -DiskControllerType 'NVMe' ` -Priority 'Regular' +#################################################################################################### +Display-ProgressBar -Status 'Setting prototype VM OS' + $VM = Set-AzVMOperatingSystem ` -VM $VM ` -Windows ` @@ -152,10 +189,16 @@ $VM = Set-AzVMOperatingSystem ` -Credential $Credential ` -ProvisionVMAgent +#################################################################################################### +Display-ProgressBar -Status 'Adding prototype VM network interface' + $VM = Add-AzVMNetworkInterface ` -VM $VM ` -Id $Nic.Id +#################################################################################################### +Display-ProgressBar -Status 'Setting prototype VM source image' + $VM = Set-AzVMSourceImage ` -VM $VM ` -PublisherName $ImagePublisher ` @@ -163,15 +206,24 @@ $VM = Set-AzVMSourceImage ` -Skus $ImageSku ` -Version 'latest' +#################################################################################################### +Display-ProgressBar -Status 'Setting prototype VM boot diagnostic' + $VM = Set-AzVMBootDiagnostic ` -VM $VM ` -Disable +#################################################################################################### +Display-ProgressBar -Status 'Creating prototype VM' + New-AzVm ` -ResourceGroupName $ResourceGroupName ` -Location $Location ` -VM $VM >> $LogFile +#################################################################################################### +Display-ProgressBar -Status 'Getting prototype VM OS disk name' + $VM = Get-AzVM ` -ResourceGroupName $ResourceGroupName ` -Name $ProtoVMName @@ -350,25 +402,41 @@ Remove-AzDisk ` Display-ProgressBar -Status 'Deleting unused network interface' Remove-AzNetworkInterface ` --ResourceGroupName $ResourceGroupName ` --Name $NicName ` --Force >> $LogFile + -ResourceGroupName $ResourceGroupName ` + -Name $NicName ` + -Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Deleting unused virtual network' Remove-AzVirtualNetwork ` --ResourceGroupName $ResourceGroupName ` --Name $VirtualNetworkName ` --Force >> $LogFile + -ResourceGroupName $ResourceGroupName ` + -Name $VirtualNetworkName ` + -Force >> $LogFile #################################################################################################### Display-ProgressBar -Status 'Deleting unused network security group' Remove-AzNetworkSecurityGroup ` --ResourceGroupName $ResourceGroupName ` --Name $NetworkSecurityGroupName ` --Force >> $LogFile + -ResourceGroupName $ResourceGroupName ` + -Name $NetworkSecurityGroupName ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused NAT gateway' + +Remove-AzNatGateway ` + -ResourceGroupName $ResourceGroupName ` + -Name $NatGatewayName ` + -Force >> $LogFile + +#################################################################################################### +Display-ProgressBar -Status 'Deleting unused public IP address' + +Remove-AzPublicIpAddress ` + -ResourceGroupName $ResourceGroupName ` + -Name $PublicIpAddressName ` + -Force >> $LogFile #################################################################################################### Write-Progress -Activity $ProgressActivity -Completed diff --git a/azure-devops/provision-image.ps1 b/azure-devops/provision-image.ps1 index ea42153a8d5..67357c4a121 100644 --- a/azure-devops/provision-image.ps1 +++ b/azure-devops/provision-image.ps1 @@ -46,10 +46,8 @@ $PowerShellArgs = @('/quiet', '/norestart') $PythonUrl = 'https://www.python.org/ftp/python/3.13.2/python-3.13.2-amd64.exe' $PythonArgs = @('/quiet', 'InstallAllUsers=1', 'PrependPath=1', 'CompileAll=1', 'Include_doc=0') -# TRANSITION, GH-5282: Install only nvcc and cudart, then manually add CUDA to the PATH (see below). $CudaUrl = 'https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda_12.4.0_551.61_windows.exe' -$CudaArgs = @('-s', '-n', 'nvcc_12.4', 'cudart_12.4') -$CudaPath = 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\bin' +$CudaArgs = @('-s', '-n') <# .SYNOPSIS @@ -114,12 +112,6 @@ DownloadAndInstall -Name 'CUDA' -Url $CudaUrl -Args $CudaArgs Write-Host 'Setting environment variables...' -# TRANSITION, GH-5282: Manually add CUDA to the PATH. -# Don't use $Env:PATH here - that's the local path for this running script, captured before we installed anything. -# The machine path was just updated by the installers above. -$machinePath = [Environment]::GetEnvironmentVariable('Path', 'Machine') -[Environment]::SetEnvironmentVariable('Path', "$machinePath;$CudaPath", 'Machine') - # The STL's PR/CI builds are totally unrepresentative of customer usage. [Environment]::SetEnvironmentVariable('VSCMD_SKIP_SENDTELEMETRY', '1', 'Machine') diff --git a/stl/inc/__msvc_bit_utils.hpp b/stl/inc/__msvc_bit_utils.hpp index a89221adec0..4217cb208a3 100644 --- a/stl/inc/__msvc_bit_utils.hpp +++ b/stl/inc/__msvc_bit_utils.hpp @@ -51,7 +51,7 @@ _NODISCARD constexpr int _Countl_zero_fallback(_Ty _Val) noexcept { return static_cast(_Nx) - static_cast(_Val); } -#if !defined(_M_CEE_PURE) && !defined(__CUDACC__) && !defined(__INTEL_COMPILER) +#if !defined(_M_CEE_PURE) && !defined(__CUDACC__) #define _HAS_COUNTL_ZERO_INTRINSICS 1 #else // ^^^ intrinsics available / intrinsics unavailable vvv #define _HAS_COUNTL_ZERO_INTRINSICS 0 @@ -179,7 +179,7 @@ _NODISCARD constexpr int _Popcount_fallback(_Ty _Val) noexcept { } #if ((defined(_M_IX86) && !defined(_M_HYBRID_X86_ARM64)) || (defined(_M_X64) && !defined(_M_ARM64EC))) \ - && !defined(_M_CEE_PURE) && !defined(__CUDACC__) && !defined(__INTEL_COMPILER) + && !defined(_M_CEE_PURE) && !defined(__CUDACC__) #define _HAS_TZCNT_BSF_INTRINSICS 1 #else // ^^^ intrinsics available / intrinsics unavailable vvv #define _HAS_TZCNT_BSF_INTRINSICS 0 @@ -273,8 +273,7 @@ _NODISCARD int _Checked_x86_x64_countr_zero(const _Ty _Val) noexcept { #endif // _HAS_TZCNT_BSF_INTRINSICS -#if (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64)) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \ - && !defined(__INTEL_COMPILER) +#if (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64)) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) #define _HAS_POPCNT_INTRINSICS 1 #if defined(__AVX__) || defined(_M_ARM64) || defined(_M_ARM64EC) #define _POPCNT_INTRINSICS_ALWAYS_AVAILABLE 1 diff --git a/stl/inc/__msvc_int128.hpp b/stl/inc/__msvc_int128.hpp index 7933e595820..e0a0dd34ddb 100644 --- a/stl/inc/__msvc_int128.hpp +++ b/stl/inc/__msvc_int128.hpp @@ -36,8 +36,7 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN -#if defined(_M_X64) && !defined(_M_ARM64EC) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) \ - && !defined(__INTEL_COMPILER) +#if defined(_M_X64) && !defined(_M_ARM64EC) && !defined(_M_CEE_PURE) && !defined(__CUDACC__) #define _STL_128_INTRINSICS 1 #ifdef __clang__ // clang doesn't have _udiv128 / _div128 #define _STL_128_DIV_INTRINSICS 0 diff --git a/stl/inc/__msvc_iter_core.hpp b/stl/inc/__msvc_iter_core.hpp index d549bf06ce7..e77903479a1 100644 --- a/stl/inc/__msvc_iter_core.hpp +++ b/stl/inc/__msvc_iter_core.hpp @@ -283,7 +283,7 @@ struct _Iter_traits_category4 { template concept _Cpp17_random_delta = -#if defined(__CUDACC__) && !defined(__clang__) // TRANSITION, CUDA 12.5 +#if defined(__CUDACC__) && !defined(__clang__) // TRANSITION, fixed in CUDA 12.5 totally_ordered<_It> && requires(_It __i, typename incrementable_traits<_It>::difference_type __n) { #else // ^^^ workaround / no workaround vvv totally_ordered<_It> && requires(_It __i, incrementable_traits<_It>::difference_type __n) { diff --git a/stl/inc/__msvc_ranges_tuple_formatter.hpp b/stl/inc/__msvc_ranges_tuple_formatter.hpp index eeb768995f6..677997e3abb 100644 --- a/stl/inc/__msvc_ranges_tuple_formatter.hpp +++ b/stl/inc/__msvc_ranges_tuple_formatter.hpp @@ -264,7 +264,8 @@ class basic_format_arg { } }; -#if defined(__clang__) || defined(__EDG__) // TRANSITION, LLVM-81774 (Clang), VSO-1956558 (EDG) +#if defined(__clang__) || defined(__EDG__) \ + || defined(__CUDACC__) // TRANSITION, LLVM-81774 (Clang), VSO-1956558 (EDG), VSO-2411436 (needed by CUDA 12.8.1) basic_format_arg() noexcept : _Active_state(_Basic_format_arg_type::_None), _No_state() {} #else // ^^^ workaround / no workaround vvv basic_format_arg() noexcept = default; diff --git a/stl/inc/array b/stl/inc/array index 5be4b29622d..09bf8820073 100644 --- a/stl/inc/array +++ b/stl/inc/array @@ -230,6 +230,11 @@ private: _STL_VERIFY(*this <= _Last, "array iterator range transposed"); } + friend constexpr void _Verify_range( + const _Array_const_iterator& _First, const _Array_const_iterator& _Last) noexcept { + _First._Verify_with(_Last); + } + constexpr void _Seek_to(pointer _It) noexcept { _Idx = static_cast(_It - _Ptr); } @@ -277,15 +282,6 @@ public: #endif // !_HAS_CXX20 }; -#if _ITERATOR_DEBUG_LEVEL != 0 -template -constexpr void _Verify_range( - const _Array_const_iterator<_Ty, _Size>& _First, const _Array_const_iterator<_Ty, _Size>& _Last) noexcept { - // TRANSITION, CUDA - _First._Verify_with(_Last); -} -#endif // _ITERATOR_DEBUG_LEVEL != 0 - #if _HAS_CXX20 template struct pointer_traits<_Array_const_iterator<_Ty, _Size>> { diff --git a/stl/inc/cmath b/stl/inc/cmath index 8b6b938ff66..7190d446064 100644 --- a/stl/inc/cmath +++ b/stl/inc/cmath @@ -11,8 +11,7 @@ #include #include -#if !defined(__clang__) && !defined(__CUDACC__) && !defined(__INTEL_COMPILER) \ - && !defined(_M_CEE) // TRANSITION, VSO-1663104 +#if !defined(__clang__) && !defined(__CUDACC__) && !defined(_M_CEE) // TRANSITION, VSO-1663104 #define _HAS_CMATH_INTRINSICS 1 #else // ^^^ intrinsics available / intrinsics unavailable vvv #define _HAS_CMATH_INTRINSICS 0 diff --git a/stl/inc/string b/stl/inc/string index 2ba574013fc..51661e2ad8f 100644 --- a/stl/inc/string +++ b/stl/inc/string @@ -441,39 +441,31 @@ template _NODISCARD basic_string<_Elem> _Integral_to_string(const _Ty _Val) { // convert _Val to string static_assert(is_integral_v<_Ty>, "_Ty must be integral"); - using _UTy = make_unsigned_t<_Ty>; _Elem _Buff[21]; // can hold -2^63 and 2^64 - 1, plus NUL _Elem* const _Buff_end = _STD end(_Buff); _Elem* _RNext = _Buff_end; - const auto _UVal = static_cast<_UTy>(_Val); - if (_Val < 0) { - _RNext = _UIntegral_to_buff(_RNext, 0 - _UVal); - *--_RNext = '-'; + + if constexpr (is_signed_v<_Ty>) { + const auto _UVal = static_cast>(_Val); + if (_Val < 0) { + _RNext = _UIntegral_to_buff(_RNext, 0 - _UVal); + *--_RNext = '-'; + } else { + _RNext = _UIntegral_to_buff(_RNext, _UVal); + } } else { - _RNext = _UIntegral_to_buff(_RNext, _UVal); + _RNext = _UIntegral_to_buff(_RNext, _Val); } return basic_string<_Elem>(_RNext, _Buff_end); } -// TRANSITION, CUDA - warning: pointless comparison of unsigned integer with zero -template -_NODISCARD basic_string<_Elem> _UIntegral_to_string(const _Ty _Val) { - // convert _Val to string - static_assert(is_integral_v<_Ty>, "_Ty must be integral"); - static_assert(is_unsigned_v<_Ty>, "_Ty must be unsigned"); - _Elem _Buff[21]; // can hold 2^64 - 1, plus NUL - _Elem* const _Buff_end = _STD end(_Buff); - _Elem* const _RNext = _UIntegral_to_buff(_Buff_end, _Val); - return basic_string<_Elem>(_RNext, _Buff_end); -} - _EXPORT_STD _NODISCARD inline string to_string(int _Val) { return _Integral_to_string(_Val); } _EXPORT_STD _NODISCARD inline string to_string(unsigned int _Val) { - return _UIntegral_to_string(_Val); + return _Integral_to_string(_Val); } _EXPORT_STD _NODISCARD inline string to_string(long _Val) { @@ -481,7 +473,7 @@ _EXPORT_STD _NODISCARD inline string to_string(long _Val) { } _EXPORT_STD _NODISCARD inline string to_string(unsigned long _Val) { - return _UIntegral_to_string(_Val); + return _Integral_to_string(_Val); } _EXPORT_STD _NODISCARD inline string to_string(long long _Val) { @@ -489,7 +481,7 @@ _EXPORT_STD _NODISCARD inline string to_string(long long _Val) { } _EXPORT_STD _NODISCARD inline string to_string(unsigned long long _Val) { - return _UIntegral_to_string(_Val); + return _Integral_to_string(_Val); } _EXPORT_STD _NODISCARD inline string to_string(double _Val) { @@ -512,7 +504,7 @@ _EXPORT_STD _NODISCARD inline wstring to_wstring(int _Val) { } _EXPORT_STD _NODISCARD inline wstring to_wstring(unsigned int _Val) { - return _UIntegral_to_string(_Val); + return _Integral_to_string(_Val); } _EXPORT_STD _NODISCARD inline wstring to_wstring(long _Val) { @@ -520,7 +512,7 @@ _EXPORT_STD _NODISCARD inline wstring to_wstring(long _Val) { } _EXPORT_STD _NODISCARD inline wstring to_wstring(unsigned long _Val) { - return _UIntegral_to_string(_Val); + return _Integral_to_string(_Val); } _EXPORT_STD _NODISCARD inline wstring to_wstring(long long _Val) { @@ -528,7 +520,7 @@ _EXPORT_STD _NODISCARD inline wstring to_wstring(long long _Val) { } _EXPORT_STD _NODISCARD inline wstring to_wstring(unsigned long long _Val) { - return _UIntegral_to_string(_Val); + return _Integral_to_string(_Val); } _EXPORT_STD _NODISCARD inline wstring to_wstring(double _Val) { diff --git a/stl/inc/utility b/stl/inc/utility index ae7f4094f14..999de93c950 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -951,8 +951,8 @@ _NODISCARD constexpr bool in_range(const _Ty _Value) noexcept { #endif // _HAS_CXX20 #if _HAS_CXX23 -_EXPORT_STD template -_NODISCARD _MSVC_INTRINSIC constexpr underlying_type_t<_Ty> to_underlying(_Ty _Value) noexcept { +_EXPORT_STD template // TRANSITION, VSO-2253317: should be _MSVC_INTRINSIC +_NODISCARD constexpr underlying_type_t<_Ty> to_underlying(_Ty _Value) noexcept { return static_cast>(_Value); } diff --git a/stl/inc/xmemory b/stl/inc/xmemory index acac82131e1..f65246466cc 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1500,8 +1500,8 @@ struct _Container_proxy_ptr12 : _Basic_container_proxy_ptr12 { }; #if _ITERATOR_DEBUG_LEVEL == 0 -_INLINE_VAR constexpr _Fake_allocator _Fake_alloc{}; -#define _GET_PROXY_ALLOCATOR(_Alty, _Al) _Fake_alloc // TRANSITION, VSO-1284799, should be _Fake_allocator{} +#define _GET_PROXY_ALLOCATOR(_Alty, _Al) \ + _Fake_allocator {} template using _Container_proxy_ptr = _Fake_proxy_ptr_impl; #else // ^^^ _ITERATOR_DEBUG_LEVEL == 0 / _ITERATOR_DEBUG_LEVEL > 0 vvv diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 3525693fa21..3b482db985b 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -526,14 +526,7 @@ #define _STL_STRINGIZE_(S) #S #define _STL_STRINGIZE(S) _STL_STRINGIZE_(S) -// Note that _STL_PRAGMA is load-bearing; -// it still needs to exist even once CUDA and ICC support _Pragma. -#if defined(__CUDACC__) || defined(__INTEL_COMPILER) -#define _STL_PRAGMA(PRAGMA) __pragma(PRAGMA) -#else -#define _STL_PRAGMA(PRAGMA) _Pragma(#PRAGMA) -#endif - +#define _STL_PRAGMA(PRAGMA) _Pragma(#PRAGMA) #define _STL_PRAGMA_MESSAGE(MESSAGE) _STL_PRAGMA(message(MESSAGE)) #define _EMIT_STL_MESSAGE(MESSAGE) _STL_PRAGMA_MESSAGE(__FILE__ "(" _STL_STRINGIZE(__LINE__) "): " MESSAGE) @@ -698,8 +691,6 @@ #ifndef __has_cpp_attribute #define _HAS_MSVC_ATTRIBUTE(x) 0 -#elif defined(__CUDACC__) // TRANSITION, CUDA - warning: attribute namespace "msvc" is unrecognized -#define _HAS_MSVC_ATTRIBUTE(x) 0 #else #define _HAS_MSVC_ATTRIBUTE(x) __has_cpp_attribute(msvc::x) #endif @@ -885,26 +876,20 @@ #define _STL_DISABLE_DEPRECATED_WARNING \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#elif defined(__CUDACC__) || defined(__INTEL_COMPILER) -#define _STL_DISABLE_DEPRECATED_WARNING \ - __pragma(warning(push)) \ - __pragma(warning(disable : 4996)) // was declared deprecated -#else // vvv MSVC vvv +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv #define _STL_DISABLE_DEPRECATED_WARNING \ _Pragma("warning(push)") \ _Pragma("warning(disable : 4996)") // was declared deprecated -#endif // ^^^ MSVC ^^^ +#endif // ^^^ !defined(__clang__) ^^^ #endif // _STL_DISABLE_DEPRECATED_WARNING // clang-format on #ifndef _STL_RESTORE_DEPRECATED_WARNING #ifdef __clang__ #define _STL_RESTORE_DEPRECATED_WARNING _Pragma("clang diagnostic pop") -#elif defined(__CUDACC__) || defined(__INTEL_COMPILER) -#define _STL_RESTORE_DEPRECATED_WARNING __pragma(warning(pop)) -#else // vvv MSVC vvv +#else // ^^^ defined(__clang__) / !defined(__clang__) vvv #define _STL_RESTORE_DEPRECATED_WARNING _Pragma("warning(pop)") -#endif // ^^^ MSVC ^^^ +#endif // ^^^ !defined(__clang__) ^^^ #endif // !defined(_STL_RESTORE_DEPRECATED_WARNING) #define _CPPLIB_VER 650 @@ -923,8 +908,8 @@ _EMIT_STL_ERROR(STL1002, "Unexpected compiler version, expected CUDA 12.4 or new _EMIT_STL_ERROR(STL1000, "Unexpected compiler version, expected Clang 19.0.0 or newer."); #endif // ^^^ old Clang ^^^ #elif defined(_MSC_VER) -#if _MSC_VER < 1942 // Coarse-grained, not inspecting _MSC_FULL_VER -_EMIT_STL_ERROR(STL1001, "Unexpected compiler version, expected MSVC 19.42 or newer."); +#if _MSC_VER < 1944 // Coarse-grained, not inspecting _MSC_FULL_VER +_EMIT_STL_ERROR(STL1001, "Unexpected compiler version, expected MSVC 19.44 or newer."); #endif // ^^^ old MSVC ^^^ #else // vvv other compilers vvv // not attempting to detect other compilers @@ -2024,10 +2009,6 @@ compiler option, or define _ALLOW_RTCc_IN_STL to suppress this error. #define _STATIC_CALL_OPERATOR static #define _CONST_CALL_OPERATOR #define _STATIC_LAMBDA static -#elif _MSC_VER < 1944 // TRANSITION, internal toolset needs to be updated to VS 2022 17.14 Preview 1 -#define _STATIC_CALL_OPERATOR -#define _CONST_CALL_OPERATOR const -#define _STATIC_LAMBDA #else // TRANSITION, VSO-2383148, fixed in VS 2022 17.14 Preview 3 #define _STATIC_CALL_OPERATOR static #define _CONST_CALL_OPERATOR diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index d3359a1b79c..bf8daabd5c6 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -602,6 +602,7 @@ std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/m std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex_time_point.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/mutex.pass.cpp SKIPPED std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.locking/lock.pass.cpp SKIPPED +std/thread/thread.threads/thread.thread.class/thread.thread.destr/dtor.pass.cpp SKIPPED std/thread/thread.threads/thread.thread.this/sleep_until.pass.cpp SKIPPED # Not analyzed, likely bogus tests. Various assertions, probably POSIX assumptions. diff --git a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp index cc2fabe66af..0f79623e2df 100644 --- a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp +++ b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp @@ -1370,8 +1370,6 @@ _CONSTEXPR20 bool test_mem_fn() { const int&& r2 = mf_pmd(move(cw)); assert(&r2 == &cw.m_i); - -#ifndef _M_CEE // TRANSITION, VSO-1664293 w.m_i = 1000; assert(mem_fn(&Widget::nullary)(w) == 1001); @@ -1395,7 +1393,6 @@ _CONSTEXPR20 bool test_mem_fn() { assert(mem_fn(&Widget::unary_lv)(&w, 6) == 1061); assert(mem_fn(&Widget::unary_rv)(move(w), 7) == 1404); -#endif // ^^^ no workaround ^^^ return true; } diff --git a/tests/std/tests/GH_000639_nvcc_include_all/test.compile.pass.cpp b/tests/std/tests/GH_000639_nvcc_include_all/test.compile.pass.cpp index 3141bc208ce..dc49c8ff92f 100644 --- a/tests/std/tests/GH_000639_nvcc_include_all/test.compile.pass.cpp +++ b/tests/std/tests/GH_000639_nvcc_include_all/test.compile.pass.cpp @@ -4,3 +4,12 @@ #define _MSVC_TESTING_NVCC #include <__msvc_all_public_headers.hpp> + +using namespace std; + +#if _HAS_CXX20 +// Test VSO-2411436 "[Feedback] CUDA (12.8) host code compilation fails with std::format and VS2022" +void test_VSO_2411436() { + (void) format("{}", 1729); +} +#endif // _HAS_CXX20 diff --git a/tests/std/tests/P0019R8_atomic_ref/test.cpp b/tests/std/tests/P0019R8_atomic_ref/test.cpp index 47f42a78be0..ad351d42b23 100644 --- a/tests/std/tests/P0019R8_atomic_ref/test.cpp +++ b/tests/std/tests/P0019R8_atomic_ref/test.cpp @@ -53,11 +53,7 @@ void test_atomic_ref_constraints_single() { // COMPILE-ONLY }); { [[maybe_unused]] auto instantiator = [](const AR& r, TD v, std::memory_order ord) { -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-2343282 (void) r.operator TD(); -#else // ^^^ no workaround / workaround vvv - [[maybe_unused]] TD td = r; -#endif // ^^^ workaround ^^^ (void) r.load(); (void) r.load(ord); r.wait(v); diff --git a/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp index 55333fccfcd..1500983e015 100644 --- a/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp +++ b/tests/std/tests/P0466R5_layout_compatibility_and_pointer_interconvertibility_traits/test.cpp @@ -199,7 +199,7 @@ constexpr bool test() { ASSERT(!is_corresponding_member(&S5::v1, &S6::v2)); ASSERT(!is_corresponding_member(&S5::v2, &S6::v1)); ASSERT(!is_corresponding_member(&S5::v3, &S6::v3)); -#ifndef _M_CEE // TRANSITION, VSO-1664293 +#ifndef _M_CEE // TRANSITION, VSO-2417635 ASSERT(!is_corresponding_member(&NS::v1, &NS::w1)); #endif // ^^^ no workaround ^^^ ASSERT(!is_corresponding_member(&S7::f1, &S7::f1)); @@ -236,7 +236,7 @@ constexpr bool test() { ASSERT(is_pointer_interconvertible_with_class(&U::v2)); ASSERT(!is_pointer_interconvertible_with_class(&NS::a)); -#ifndef _M_CEE // TRANSITION, VSO-1664293 +#ifndef _M_CEE // TRANSITION, VSO-2417635 ASSERT(!is_pointer_interconvertible_with_class(&NS::b)); #endif // ^^^ no workaround ^^^ ASSERT(!is_pointer_interconvertible_with_class(&C::f1)); diff --git a/tests/std/tests/P0896R4_views_take/test.cpp b/tests/std/tests/P0896R4_views_take/test.cpp index d14de052e7b..a512435f971 100644 --- a/tests/std/tests/P0896R4_views_take/test.cpp +++ b/tests/std/tests/P0896R4_views_take/test.cpp @@ -561,22 +561,17 @@ constexpr void move_only_test() { } constexpr void output_range_test() { -#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1132704 - if (!is_constant_evaluated()) -#endif // ^^^ workaround ^^^ - { - using R = test::range; - int some_writable_ints[] = {0, 1, 2, 3}; - static_assert(same_as>); + using R = test::range; + int some_writable_ints[] = {0, 1, 2, 3}; + static_assert(same_as>); - // How do I implement "Fill up to n elements in {output range} with {value}"? - ranges::fill(R{some_writable_ints} | views::take(99999), 42); - assert(ranges::equal(some_writable_ints, initializer_list{42, 42, 42, 42})); + // How do I implement "Fill up to n elements in {output range} with {value}"? + ranges::fill(R{some_writable_ints} | views::take(99999), 42); + assert(ranges::equal(some_writable_ints, initializer_list{42, 42, 42, 42})); - ranges::fill(R{some_writable_ints} | views::take(3), 13); - assert(ranges::equal(some_writable_ints, initializer_list{13, 13, 13, 42})); - } + ranges::fill(R{some_writable_ints} | views::take(3), 13); + assert(ranges::equal(some_writable_ints, initializer_list{13, 13, 13, 42})); } void test_DevCom_1397309() { diff --git a/tools/format/CMakeLists.txt b/tools/format/CMakeLists.txt index 7b0a9adffdd..dbd31237141 100644 --- a/tools/format/CMakeLists.txt +++ b/tools/format/CMakeLists.txt @@ -18,7 +18,7 @@ execute_process( ) if(clang_format_version MATCHES "clang-format version ([0-9]+\.[0-9]+\.[0-9]+)") - set(expected_version "19.1.1") + set(expected_version "19.1.5") if(CMAKE_MATCH_1 VERSION_LESS expected_version) message(FATAL_ERROR "Found clang-format: ${CLANG_FORMAT} (\"${CMAKE_MATCH_1}\", older than expected version \"${expected_version}\")") elseif(CMAKE_MATCH_1 VERSION_EQUAL expected_version) From 1cbf31618de8117d57046a83773ae99ac7f8e145 Mon Sep 17 00:00:00 2001 From: mirounga Date: Thu, 13 Mar 2025 11:25:34 -0700 Subject: [PATCH 06/13] ``: Optimized divisionless implementation of `minstd_rand`, `minstd_rand0` (#5256) Co-authored-by: Stephan T. Lavavej --- stl/inc/random | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/stl/inc/random b/stl/inc/random index 09b7418d93e..77726564f94 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -490,6 +490,13 @@ _NODISCARD _Uint _Next_linear_congruential_value(_Uint _Prev) noexcept { // numeric_limits::max() plus 1." That is: Just do the multiply // and let normal unsigned modulo take care of it return static_cast<_Uint>(static_cast<_Uint>(_Ax * _Prev) + _Cx); + } else if constexpr (_Cx == 0 && _Mx == 2147483647) { + // for minstd_rand and minstd_rand0 we can improve performance by avoiding constant divisions + auto _Mul = static_cast(_Prev) * _Ax; + _Mul = (_Mul >> 31) + (_Mul & _Mx); + _Mul = _Mul < _Mx ? _Mul : _Mul - _Mx; + + return static_cast<_Uint>(_Mul); } else if constexpr (_Cx <= UINT_MAX && static_cast<_Uint>(_Mx - 1) <= (UINT_MAX - _Cx) / _Ax) { // unsigned int is sufficient to store intermediate calculation const auto _Mul = From 18cdebdcbb070e7011b3dad5e1c9d1c296825fce Mon Sep 17 00:00:00 2001 From: runzh <1206904210@qq.com> Date: Fri, 14 Mar 2025 02:31:36 +0800 Subject: [PATCH 07/13] Update _MSVC_STL_UPDATE to March 2025 (#5323) --- 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 3b482db985b..c3ff774f67c 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -894,7 +894,7 @@ #define _CPPLIB_VER 650 #define _MSVC_STL_VERSION 143 -#define _MSVC_STL_UPDATE 202502L +#define _MSVC_STL_UPDATE 202503L #ifndef _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH #if defined(__CUDACC__) && defined(__CUDACC_VER_MAJOR__) From 48db4facbe28da03036514ffc7620089bf963c22 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 14 Mar 2025 02:49:39 +0800 Subject: [PATCH 08/13] ``: Fix conversion between `basic_const_iterator`s (#5325) --- stl/inc/xutility | 3 +++ .../P2278R4_basic_const_iterator/test.cpp | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/stl/inc/xutility b/stl/inc/xutility index 966a1d66036..4abd43c637c 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -2211,6 +2211,9 @@ struct _Basic_const_iterator_category<_Iter> { _EXPORT_STD template class basic_const_iterator : public _Basic_const_iterator_category<_Iter> { private: + template + friend class basic_const_iterator; + /* [[no_unique_address]] */ _Iter _Current{}; using _Reference = iter_const_reference_t<_Iter>; diff --git a/tests/std/tests/P2278R4_basic_const_iterator/test.cpp b/tests/std/tests/P2278R4_basic_const_iterator/test.cpp index e9cc8502dd2..028631d7ddd 100644 --- a/tests/std/tests/P2278R4_basic_const_iterator/test.cpp +++ b/tests/std/tests/P2278R4_basic_const_iterator/test.cpp @@ -374,9 +374,35 @@ constexpr void test_p2836r1() { } } +// GH-5321 ": basic_const_iterator Cannot Convert to basic_const_iterator" +constexpr void test_conversion_instantiation() { + struct Base {}; + struct Derived : Base {}; + + { + basic_const_iterator cit = basic_const_iterator{}; + assert(cit.base() == nullptr); + } + { + int n{}; + basic_const_iterator cit = basic_const_iterator{&n}; + assert(cit.base() == &n); + } + { + basic_const_iterator cit = basic_const_iterator{}; + assert(cit.base() == nullptr); + } + { + Derived d{}; + basic_const_iterator cit = basic_const_iterator{&d}; + assert(cit.base() == static_cast(&d)); + } +} + constexpr bool all_tests() { instantiation_test(); test_p2836r1(); + test_conversion_instantiation(); return true; } From 5dcd9178b2561c8347d165d435a050cdd4c2cc8d Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 13 Mar 2025 12:04:19 -0700 Subject: [PATCH 09/13] ``: make `move_only_function` do less work (#5328) Co-authored-by: Stephan T. Lavavej --- benchmarks/CMakeLists.txt | 1 + benchmarks/src/move_only_function.cpp | 47 +++++++++++++++++++++++++++ stl/inc/functional | 11 ++----- 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 benchmarks/src/move_only_function.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 4e4f47894ed..22503345a4a 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -117,6 +117,7 @@ add_benchmark(iota src/iota.cpp) add_benchmark(locale_classic src/locale_classic.cpp) add_benchmark(minmax_element src/minmax_element.cpp) add_benchmark(mismatch src/mismatch.cpp) +add_benchmark(move_only_function src/move_only_function.cpp) add_benchmark(path_lexically_normal src/path_lexically_normal.cpp) add_benchmark(priority_queue_push_range src/priority_queue_push_range.cpp) add_benchmark(random_integer_generation src/random_integer_generation.cpp) diff --git a/benchmarks/src/move_only_function.cpp b/benchmarks/src/move_only_function.cpp new file mode 100644 index 00000000000..9760a602b25 --- /dev/null +++ b/benchmarks/src/move_only_function.cpp @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +using namespace std; + +void mof_none(benchmark::State& state) { + move_only_function mof; + for (auto _ : state) { + benchmark::DoNotOptimize(mof); + } +} + +void mof_construct(benchmark::State& state) { + for (auto _ : state) { + move_only_function mof; + benchmark::DoNotOptimize(mof); + } +} + +void mof_move(benchmark::State& state) { + move_only_function mof; + for (auto _ : state) { + benchmark::DoNotOptimize(mof); + auto moved_mof = move(mof); + benchmark::DoNotOptimize(moved_mof); + } +} + +void mof_construct_and_move(benchmark::State& state) { + for (auto _ : state) { + move_only_function mof; + benchmark::DoNotOptimize(mof); + auto moved_mof = move(mof); + benchmark::DoNotOptimize(moved_mof); + } +} + +BENCHMARK(mof_none); +BENCHMARK(mof_construct); +BENCHMARK(mof_move); +BENCHMARK(mof_construct_and_move); + +BENCHMARK_MAIN(); diff --git a/stl/inc/functional b/stl/inc/functional index e386dc35c1f..1c474932f74 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1506,11 +1506,6 @@ public: _Other._Reset_to_null(); } - void _Construct_with_null() noexcept { - _Data._Impl = nullptr; - _Data._Set_large_fn_ptr(nullptr); // initialize, since we'll be copying it - } - void _Reset_to_null() noexcept { _Data._Impl = nullptr; } @@ -1888,11 +1883,11 @@ public: using typename _Call::result_type; move_only_function() noexcept { - this->_Construct_with_null(); + this->_Reset_to_null(); } move_only_function(nullptr_t) noexcept { - this->_Construct_with_null(); + this->_Reset_to_null(); } move_only_function(move_only_function&&) noexcept = default; @@ -1906,7 +1901,7 @@ public: if constexpr (is_member_pointer_v<_Vt> || is_pointer_v<_Vt> || _Is_specialization_v<_Vt, move_only_function>) { if (_Callable == nullptr) { - this->_Construct_with_null(); + this->_Reset_to_null(); return; } } From cc11d088cdaa6aec7930b6509abb6bb838189540 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 13 Mar 2025 12:08:35 -0700 Subject: [PATCH 10/13] `README.md`: consistent assumption about STL location (#5332) --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4e306f137e4..1b83c5cadf0 100644 --- a/README.md +++ b/README.md @@ -379,8 +379,8 @@ steps. Let's assume we want to debug a new feature with tests located in `tests\ As always, build the STL from your branch and run the tests: ``` -C:\STL\out\x64> ninja -C:\STL\out\x64> python tests\utils\stl-lit\stl-lit.py -v C:\STL\tests\std\tests\GH_XXXX_meow +C:\Dev\STL\out\x64> ninja +C:\Dev\STL\out\x64> python tests\utils\stl-lit\stl-lit.py -v C:\Dev\STL\tests\std\tests\GH_XXXX_meow ``` Let's assume one of the tests fails an assert and we want to debug that configuration. `stl-lit` will conveniently print @@ -390,15 +390,15 @@ provide debug symbols: `/Zi /Fdbark.pdb`. You can replace `bark` with any descriptive name you like. Add these before the `"-link"` option in the command line and recompile. Example: ``` -C:\STL\out\x64>cl "C:\STL\tests\std\tests\GH_XXXX_meow\test.cpp" [... more arguments ...] -"-FeC:\STL\out\x64\tests\std\tests\GH_XXXX_meow\Output\02\GH_XXXX_meow.exe" /Zi /Fdbark.pdb "-link" +C:\Dev\STL\out\x64>cl "C:\Dev\STL\tests\std\tests\GH_XXXX_meow\test.cpp" [... more arguments ...] +"-FeC:\Dev\STL\out\x64\tests\std\tests\GH_XXXX_meow\Output\02\GH_XXXX_meow.exe" /Zi /Fdbark.pdb "-link" [... more arguments ...] ``` You can now start debugging the test via: ``` -devenv "C:\STL\out\x64\tests\std\tests\GH_XXXX_meow\Output\02\GH_XXXX_meow.exe" - "C:\STL\tests\std\tests\GH_XXXX_meow\test.cpp" +devenv "C:\Dev\STL\out\x64\tests\std\tests\GH_XXXX_meow\Output\02\GH_XXXX_meow.exe" + "C:\Dev\STL\tests\std\tests\GH_XXXX_meow\test.cpp" ``` However, this might not work right away, as Visual Studio may complain about a missing `msvcp140_oss.dll`. The reason @@ -406,7 +406,7 @@ is that the STL builds those and other DLLs itself and we should under no circum If you are testing one of the configurations with dynamic linkage (`/MD` or `/MDd`) the easiest solution is to add the build folder to your path: ``` -set PATH=C:\STL\out\x64\out\bin\amd64;%PATH% +set PATH=C:\Dev\STL\out\x64\out\bin\amd64;%PATH% ``` ## Running Tests With Address Sanitizer (ASan) From 3030afbbe8fd6f94cec4ea97269d4458589e3657 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 14 Mar 2025 03:09:32 +0800 Subject: [PATCH 11/13] Implement LWG-3956 `chrono::parse` uses `from_stream` as a customization point (#5334) Co-authored-by: Stephan T. Lavavej --- stl/inc/chrono | 24 +++++++--- .../test.cpp | 45 +++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/stl/inc/chrono b/stl/inc/chrono index b71235f710d..8f0f6a6b0ee 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -4608,6 +4608,22 @@ namespace chrono { return _Istr; } + namespace _From_stream_adl_only { +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-1681199 + void from_stream() = delete; // Block unqualified name lookup +#else // ^^^ no workaround / workaround vvv + void from_stream(); +#endif // ^^^ workaround ^^^ + + template + concept _Can_from_stream = requires( + basic_istream<_CharT, _Traits>& __istr, const _CharT* __s, _Parsable& __parsed, _Rest&&... __rest_args) { + from_stream(__istr, +__s, __parsed, _STD forward<_Rest>(__rest_args)...); // intentional ADL + }; + } // namespace _From_stream_adl_only + + using _From_stream_adl_only::_Can_from_stream; + template struct _Time_parse_iomanip_c_str { _Time_parse_iomanip_c_str(const _CharT* _Fmt_, _Parsable& _Tp_, @@ -4618,6 +4634,7 @@ namespace chrono { friend basic_istream<_CharT, _Traits>& operator>>( basic_istream<_CharT, _Traits>& _Is, _Time_parse_iomanip_c_str&& _Tpi) { + using _From_stream_adl_only::from_stream; from_stream(_Is, _Tpi._Fmt, _Tpi._Tp, _Tpi._Abbrev, _Tpi._Offset); // intentional ADL return _Is; } @@ -4638,6 +4655,7 @@ namespace chrono { friend basic_istream<_CharT, _Traits>& operator>>( basic_istream<_CharT, _Traits>& _Is, _Time_parse_iomanip&& _Tpi) { + using _From_stream_adl_only::from_stream; from_stream(_Is, _Tpi._Fmt.c_str(), _Tpi._Tp, _Tpi._Abbrev, _Tpi._Offset); // intentional ADL return _Is; } @@ -4648,12 +4666,6 @@ namespace chrono { minutes* _Offset; }; - template - concept _Can_from_stream = requires( - basic_istream<_CharT, _Traits>& __istr, const _CharT* __s, _Parsable& __parsed, _Rest&&... __rest_args) { - from_stream(__istr, +__s, __parsed, _STD forward<_Rest>(__rest_args)...); // intentional ADL - }; - _EXPORT_STD template > _Parsable> _NODISCARD auto parse(const _CharT* _Fmt, _Parsable& _Tp) { return _Time_parse_iomanip_c_str<_CharT, char_traits<_CharT>, allocator<_CharT>, _Parsable>{_Fmt, _Tp}; diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp index 8b394ab63ce..a5683460375 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_io/test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -1247,8 +1248,52 @@ void test_io_manipulator() { fail_parse(WIDEN(CharT, "a b"), CStringOrStdString{WIDEN(CharT, "a%nb")}, time); } +namespace lwg_3956 { + struct has_adl_from_stream { + int value = 0; + + template + friend basic_istream& from_stream( + basic_istream& istr, const CharT*, has_adl_from_stream& parsed, ArgTypes&&...) { + parsed.value = 42; + return istr; + } + }; + + struct has_no_adl_from_stream { + operator year&() &; + }; + + template + concept can_parse = requires(ArgTypes&&... args) { parse(forward(args)...); }; + + static_assert(can_parse); + static_assert(can_parse); + static_assert(can_parse); + static_assert(can_parse); + + static_assert(!can_parse); + static_assert(!can_parse); + static_assert(!can_parse); + static_assert(!can_parse); +} // namespace lwg_3956 + +void test_lwg_3956() { + { + lwg_3956::has_adl_from_stream parsed{}; + test_parse("", "", parsed); + assert(parsed.value == 42); + } + { + lwg_3956::has_adl_from_stream parsed{}; + test_parse(L"", L"", parsed); + assert(parsed.value == 42); + } +} + void test_parse() { test_lwg_3536(); + test_lwg_3956(); parse_seconds(); parse_minutes(); parse_hours(); From 713dd95901f79aad7d51bb43435fa40727390d46 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 13 Mar 2025 12:12:11 -0700 Subject: [PATCH 12/13] Various cleanups (#5336) --- stl/inc/algorithm | 2 + stl/inc/atomic | 2 +- stl/inc/bitset | 2 +- stl/inc/chrono | 4 +- stl/inc/format | 2 +- stl/inc/functional | 4 +- stl/inc/future | 13 ++-- stl/inc/random | 63 +++++++++---------- stl/inc/regex | 2 +- stl/inc/variant | 2 +- stl/inc/xloctime | 6 +- stl/inc/xtree | 4 +- stl/inc/yvals_core.h | 2 +- stl/src/primitives.hpp | 2 +- stl/src/print.cpp | 2 +- tests/std/tests/P0088R3_variant_msvc/test.cpp | 2 +- .../tests/P0092R1_polishing_chrono/test.cpp | 2 +- tests/std/tests/P0220R1_sample/test.cpp | 2 +- .../test.cpp | 2 +- tests/std/tests/P2502R2_generator/test.cpp | 2 +- .../VSO_0000000_vector_algorithms/test.cpp | 4 +- tests/utils/stl/util.py | 12 ---- 22 files changed, 65 insertions(+), 73 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 0bfef44a07b..8109baf3a16 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -7477,11 +7477,13 @@ _NODISCARD constexpr auto _Idl_dist_add(_Diff1 _Lhs, _Diff2 _Rhs) { return ranges::_Distance_unbounded{}; } else #endif // _HAS_CXX20 + { if constexpr (is_same_v<_Diff1, _Distance_unknown> || is_same_v<_Diff2, _Distance_unknown>) { return _Distance_unknown{}; } else { return _Lhs + _Rhs; } + } } _EXPORT_STD template diff --git a/stl/inc/atomic b/stl/inc/atomic index 000559221f9..75e45dde4a0 100644 --- a/stl/inc/atomic +++ b/stl/inc/atomic @@ -203,7 +203,7 @@ extern "C" inline void _Atomic_thread_fence(const unsigned int _Order) noexcept if (_Order == _Atomic_memory_order_seq_cst) { volatile long _Guard; // Not initialized to avoid an unnecessary operation; the value does not matter - // _mm_mfence could have been used, but it is not supported on older x86 CPUs and is slower on some recent CPUs. + // _mm_mfence could have been used, but it is slower on some CPUs. // The memory fence provided by interlocked operations has some exceptions, but this is fine: // std::atomic_thread_fence works with respect to other atomics only; it may not be a full fence for all ops. (void) _InterlockedIncrement(&_Guard); diff --git a/stl/inc/bitset b/stl/inc/bitset index 7792605af47..30148f6579f 100644 --- a/stl/inc/bitset +++ b/stl/inc/bitset @@ -666,7 +666,7 @@ basic_istream<_Elem, _Tr>& operator>>(basic_istream<_Elem, _Tr>& _Istr, bitset<_ } _Istr.setstate(_State); - _Right = bitset<_Bits>(_Buf._Buf, _Count); // convert string and store + _Right = bitset<_Bits>{_Buf._Buf, _Count}; // convert string and store return _Istr; } diff --git a/stl/inc/chrono b/stl/inc/chrono index 8f0f6a6b0ee..2a86c9aded5 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -1849,7 +1849,7 @@ namespace chrono { // time zone name. In vNext, this should be a dedicated argument. const string _Tz_arg = _Name + static_cast(_Type); - const auto _Tz_len = _Name.length(); + const auto _Tz_len = _Name.size(); const auto _Info = _Make_unique_tzdb_info<__std_tzdb_get_sys_info>(_Tz_arg.c_str(), _Tz_len, _Internal_dur.count()); @@ -3493,7 +3493,7 @@ namespace chrono { return ratio_less_equal_v<_Period1, _Period2> && ratio_greater_equal_v, ratio_divide, _Period1>>; - } else if (is_floating_point_v<_Rep1>) { + } else if constexpr (is_floating_point_v<_Rep1>) { // With the smallest possible _Period1, ratio<1,INTMAX_MAX>, one day has a tick count of // 86,400*INTMAX_MAX ~= 7.97e23. This is representable by float and double, so they can always represent // at least one day. On the other hand, one second with the largest possible _Period1 needs a tick count diff --git a/stl/inc/format b/stl/inc/format index 034610661f1..2d81e60ce56 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -3545,7 +3545,7 @@ _NODISCARD _FormatContext::iterator _Tuple_formatter_format(const tuple(_Tmp_str); return _STD _Write_aligned( - _Fmt_ctx.out(), _Width, _Format_specs, _Fmt_align::_Left, [&](typename _FormatContext::iterator _Out) { + _Fmt_ctx.out(), _Width, _Format_specs, _Fmt_align::_Left, [&](_FormatContext::iterator _Out) { return _STD _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Tmp_str}); }); } diff --git a/stl/inc/functional b/stl/inc/functional index 1c474932f74..21c0e80ccc7 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -2132,7 +2132,7 @@ template {}, _IntSeq{}, _Fx, _Bound_tuple, _STD move(_Unbound_tuple)); }; -#else // ^^^ concept available / concept unavailable vvv +#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template constexpr bool _Can_call_binder = false; @@ -2140,7 +2140,7 @@ template {}, _IntSeq{}, _STD declval<_CvFD&>(), _STD declval<_CvBoundTuple&>(), _STD declval<_UnboundTuple>()))>> = true; -#endif // ^^^ concept unavailable ^^^ +#endif // ^^^ !_HAS_CXX20 ^^^ template struct _Forced_result_type { // used by bind() diff --git a/stl/inc/future b/stl/inc/future index 0eaef7372b2..1f691f52444 100644 --- a/stl/inc/future +++ b/stl/inc/future @@ -474,14 +474,17 @@ struct _P_arg_type { // type for functions returning void using type = int; }; +template +using _P_arg_type_t = typename _P_arg_type<_Ret>::type; + template class _Packaged_state; // class for managing associated asynchronous state for packaged_task template -class _Packaged_state<_Ret(_ArgTypes...)> : public _Associated_state::type> { +class _Packaged_state<_Ret(_ArgTypes...)> : public _Associated_state<_P_arg_type_t<_Ret>> { public: - using _Mybase = _Associated_state::type>; + using _Mybase = _Associated_state<_P_arg_type_t<_Ret>>; using _Mydel = typename _Mybase::_Mydel; using _Function_type = function<_Ret(_ArgTypes...)>; // TRANSITION, ABI, should not use std::function @@ -1197,7 +1200,7 @@ template class packaged_task<_Ret(_ArgTypes...)> { // class that defines an asynchronous provider that returns the result of a call to a function object private: - using _Ptype = typename _P_arg_type<_Ret>::type; + using _Ptype = _P_arg_type_t<_Ret>; using _MyPromiseType = _Promise<_Ptype>; using _MyStateManagerType = _State_manager<_Ptype>; using _MyStateType = _Packaged_state<_Ret(_ArgTypes...)>; @@ -1344,7 +1347,7 @@ private: }; template -_Associated_state::type>* _Get_associated_state(launch _Psync, _Fty&& _Fnarg) { +_Associated_state<_P_arg_type_t<_Ret>>* _Get_associated_state(launch _Psync, _Fty&& _Fnarg) { // construct associated asynchronous state object for the launch type switch (_Psync) { // select launch type case launch::deferred: @@ -1360,7 +1363,7 @@ _NODISCARD_ASYNC future<_Invoke_result_t, decay_t<_ArgTypes>...>> launch _Policy, _Fty&& _Fnarg, _ArgTypes&&... _Args) { // manages a callable object launched with supplied policy using _Ret = _Invoke_result_t, decay_t<_ArgTypes>...>; - using _Ptype = typename _P_arg_type<_Ret>::type; + using _Ptype = _P_arg_type_t<_Ret>; _Promise<_Ptype> _Pr( _Get_associated_state<_Ret>(_Policy, _Fake_no_copy_callable_adapter<_Fty, _ArgTypes...>( _STD forward<_Fty>(_Fnarg), _STD forward<_ArgTypes>(_Args)...))); diff --git a/stl/inc/random b/stl/inc/random index 77726564f94..fa401b630cd 100644 --- a/stl/inc/random +++ b/stl/inc/random @@ -402,7 +402,7 @@ bool _Nrand_for_tr1( } template -struct _Has_static_min_max : false_type {}; +struct _Has_static_min_max : false_type {}; // TRANSITION, VSO-2417491: Should be a variable template // This checks a requirement of N4981 [rand.req.urng] `concept uniform_random_bit_generator` but doesn't attempt // to implement the whole concept - we just need to distinguish Standard machinery from tr1 machinery. @@ -461,8 +461,6 @@ _NODISCARD _Real _Nrand_impl(_Gen& _Gx) { // build a floating-point value from r } } -#define _NRAND(eng, resty) (_Nrand_impl(eng)) - _INLINE_VAR constexpr int _MP_len = 5; using _MP_arr = uint64_t[_MP_len]; @@ -2546,7 +2544,7 @@ public: private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { - return _NRAND(_Eng, double) < _Par0._Px; + return _Nrand_impl(_Eng) < _Par0._Px; } param_type _Par; @@ -2713,7 +2711,7 @@ private: _Ty1 _Val; do { - _Val = _CSTD log(_NRAND(_Eng, _Ty1)) / _Par0._Log_1_p; + _Val = _CSTD log(_Nrand_impl<_Ty1>(_Eng)) / _Par0._Log_1_p; } while (_Val >= _Ty1_max); return static_cast<_Ty>(_Val); } @@ -2730,7 +2728,7 @@ public: _NODISCARD _Ty operator()(_Engine& _Eng) const { _Ty1 _Val = 1.0; for (_Ty _Res = 0;; ++_Res) { // count repetitions - _Val *= _NRAND(_Eng, _Ty1); + _Val *= _Nrand_impl<_Ty1>(_Eng); if (_Val <= _Gx0) { return _Res; } @@ -2882,7 +2880,7 @@ private: _Ty _Res; _Ty1 _Yx; for (;;) { // generate a tentative value - _Yx = static_cast<_Ty1>(_CSTD tan(_Pi_val * _NRAND(_Eng, _Ty1))); + _Yx = static_cast<_Ty1>(_CSTD tan(_Pi_val * _Nrand_impl<_Ty1>(_Eng))); const _Ty1 _Mx{_Par0._Sqrt * _Yx + _Par0._Mean}; if (0.0 <= _Mx && _Mx < _Ty1_max) { _Res = static_cast<_Ty>(_Mx); @@ -2890,7 +2888,7 @@ private: } } - if (_NRAND(_Eng, _Ty1) + if (_Nrand_impl<_Ty1>(_Eng) <= 0.9 * (1.0 + _Yx * _Yx) * _CSTD exp(_Res * _Par0._Logm - _XLgamma(_Res + 1.0) - _Par0._Gx1)) { return _Res; } @@ -3050,7 +3048,7 @@ private: if (_Par0._Tx < 25) { // generate directly _Res = 0; for (_Ty _Ix = 0; _Ix < _Par0._Tx; ++_Ix) { - if (_NRAND(_Eng, _Ty1) < _Par0._Px) { + if (_Nrand_impl<_Ty1>(_Eng) < _Par0._Px) { ++_Res; } } @@ -3058,7 +3056,7 @@ private: return _Res; } else if (_Par0._Mean < 1.0) { // Events are rare, use waiting time method (Luc Devroye, Non-Uniform Random Variate Generation, p. 525). - const _Ty1 _Rand = _NRAND(_Eng, _Ty1); + const _Ty1 _Rand = _Nrand_impl<_Ty1>(_Eng); // The exit condition is log(1 - _Rand)/t < log(1-p), which is equivalent to _Rand > 1 - (1-p)^t. If // we have a cheap upper bound for 1-(1-p)^t, we can exit early without having to call log. We use two @@ -3073,7 +3071,7 @@ private: _Ty _Denom = _Par0._Tx; _Ty1 _Sum = _CSTD log(_Ty1{1.0} - _Rand) / _Denom; while (_Sum >= _Par0._Logp1 && --_Denom != 0) { - _Sum += _CSTD log(_Ty1{1.0} - _NRAND(_Eng, _Ty1)) / _Denom; + _Sum += _CSTD log(_Ty1{1.0} - _Nrand_impl<_Ty1>(_Eng)) / _Denom; } _Res = static_cast<_Ty>(_Par0._Tx - _Denom); } @@ -3084,14 +3082,14 @@ private: for (;;) { // generate and reject _Ty1 _Yx; for (;;) { // generate a tentative value - _Yx = static_cast<_Ty1>(_CSTD tan(_Pi_val * _NRAND(_Eng, _Ty1))); + _Yx = static_cast<_Ty1>(_CSTD tan(_Pi_val * _Nrand_impl<_Ty1>(_Eng))); const _Ty1 _Mx{_Par0._Sqrt * _Yx + _Par0._Mean}; if (0.0 <= _Mx && _Mx < _Ty1_Tx) { _Res = static_cast<_Ty>(_Mx); break; } } - if (_NRAND(_Eng, _Ty1) + if (_Nrand_impl<_Ty1>(_Eng) <= 1.2 * _Par0._Sqrt * (1.0 + _Yx * _Yx) * _CSTD exp(_Par0._Gx1 - _XLgamma(_Res + 1.0) - _XLgamma(_Par0._Tx - _Res + 1.0) + _Res * _Par0._Logp + (_Par0._Tx - _Res) * _Par0._Logp1)) { @@ -3226,7 +3224,7 @@ public: private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { - return _NRAND(_Eng, _Ty) * (_Par0._Max - _Par0._Min) + _Par0._Min; + return _Nrand_impl<_Ty>(_Eng) * (_Par0._Max - _Par0._Min) + _Par0._Min; } param_type _Par; @@ -3439,7 +3437,7 @@ public: private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { - return -_CSTD log(_Ty{1} - _NRAND(_Eng, _Ty)) / _Par0._Lambda; + return -_CSTD log(_Ty{1} - _Nrand_impl<_Ty>(_Eng)) / _Par0._Lambda; } param_type _Par; @@ -3600,8 +3598,8 @@ private: _Ty _Vx2; _Ty _Sx; for (;;) { // reject bad values to avoid generating NaN/Inf on the next calculations - _Vx1 = 2 * _NRAND(_Eng, _Ty) - 1; - _Vx2 = 2 * _NRAND(_Eng, _Ty) - 1; + _Vx1 = 2 * _Nrand_impl<_Ty>(_Eng) - 1; + _Vx2 = 2 * _Nrand_impl<_Ty>(_Eng) - 1; _Sx = _Vx1 * _Vx1 + _Vx2 * _Vx2; if (_Sx < _Ty{1} && _Vx1 != _Ty{0} && _Vx2 != _Ty{0}) { // good values! @@ -3779,9 +3777,9 @@ private: if (_Par0._Alpha < 1) { // small values of alpha // from Knuth for (;;) { // generate and reject - _Ux = _NRAND(_Eng, _Ty); + _Ux = _Nrand_impl<_Ty>(_Eng); do { - _Vx = _NRAND(_Eng, _Ty); + _Vx = _Nrand_impl<_Ty>(_Eng); } while (_Vx == 0); if (_Ux < _Par0._Px) { // small _Ux @@ -3792,7 +3790,7 @@ private: _Qx = _CSTD pow(_Xx, _Par0._Alpha - 1); } - if (_NRAND(_Eng, _Ty) < _Qx) { + if (_Nrand_impl<_Ty>(_Eng) < _Qx) { return _Par0._Beta * _Xx; } } @@ -3804,10 +3802,10 @@ private: if (_Par0._Alpha < 20.0 && (_Count = static_cast(_Par0._Alpha)) == _Par0._Alpha) { // _Alpha is small integer, compute directly - _Yx = _NRAND(_Eng, _Ty); + _Yx = _Nrand_impl<_Ty>(_Eng); while (--_Count) { // adjust result do { - _Ux = _NRAND(_Eng, _Ty); + _Ux = _Nrand_impl<_Ty>(_Eng); } while (_Ux == 0); _Yx *= _Ux; @@ -3817,12 +3815,12 @@ private: // no shortcuts for (;;) { // generate and reject - _Yx = static_cast<_Ty>(_CSTD tan(_Pi_val * _NRAND(_Eng, _Ty))); + _Yx = static_cast<_Ty>(_CSTD tan(_Pi_val * _Nrand_impl<_Ty>(_Eng))); _Xx = _Par0._Sqrt * _Yx + _Par0._Alpha - 1; if (0 < _Xx - && _NRAND(_Eng, _Ty) <= (1 + _Yx * _Yx) - * _CSTD exp((_Par0._Alpha - 1) * _CSTD log(_Xx / (_Par0._Alpha - 1)) - - _Par0._Sqrt * _Yx)) { + && _Nrand_impl<_Ty>(_Eng) <= (1 + _Yx * _Yx) + * _CSTD exp((_Par0._Alpha - 1) * _CSTD log(_Xx / (_Par0._Alpha - 1)) + - _Par0._Sqrt * _Yx)) { return _Par0._Beta * _Xx; } } @@ -3959,7 +3957,7 @@ public: private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { // generate pseudo-random value - _Ty _Px = (_Ty{1} - _NRAND(_Eng, _Ty)); + _Ty _Px = (_Ty{1} - _Nrand_impl<_Ty>(_Eng)); return _Par0._Bx * _CSTD pow(-_CSTD log(_Px), _Ty{1} / _Par0._Ax); } @@ -4093,7 +4091,7 @@ public: private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { // generate pseudo-random value - _Ty _Px = _NRAND(_Eng, _Ty); + _Ty _Px = _Nrand_impl<_Ty>(_Eng); return _Par0._Ax - _Par0._Bx * _CSTD log(-_CSTD log(_Px)); } @@ -4481,7 +4479,7 @@ public: private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { // generate pseudo-random value - _Ty Px = _NRAND(_Eng, _Ty); + _Ty Px = _Nrand_impl<_Ty>(_Eng); return static_cast<_Ty>(_Par0._Ax + _Par0._Bx * _CSTD tan(_Pi_val * (Px - static_cast<_Ty>(0.5)))); } @@ -4504,8 +4502,8 @@ public: _Ty _Px1; _Ty _Px2; for (;;) { // reject large values - _Px1 = _NRAND(_Eng, _Ty); - _Px2 = _NRAND(_Eng, _Ty); + _Px1 = _Nrand_impl<_Ty>(_Eng); + _Px2 = _Nrand_impl<_Ty>(_Eng); _Px1 = _CSTD pow(_Px1, _Ty{1} / _Ax); _Px2 = _CSTD pow(_Px2, _Ty{1} / _Bx); _Wx = _Px1 + _Px2; @@ -5153,7 +5151,7 @@ public: private: template result_type _Eval(_Engine& _Eng, const param_type& _Par0) const { - double _Px = _NRAND(_Eng, double); + double _Px = _Nrand_impl(_Eng); const auto _First = _Par0._Pcdf.begin(); const auto _Position = _STD lower_bound(_First, _Prev_iter(_Par0._Pcdf.end()), _Px); return static_cast(_Position - _First); @@ -5706,7 +5704,6 @@ _STL_RESTORE_DEPRECATED_WARNING #endif // _HAS_TR1_NAMESPACE _STD_END -#undef _NRAND #undef _DISTRIBUTION_CONST // TRANSITION, GH-183 diff --git a/stl/inc/regex b/stl/inc/regex index 27b63c11e2d..8057d32946a 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -533,7 +533,7 @@ private: 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] = { - // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF + // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF /* 0X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/stl/inc/variant b/stl/inc/variant index 0679d94022d..e2a2e7581c6 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -899,7 +899,7 @@ struct _Variant_init_overload_set_, _Types...> template using _Variant_init_overload_set = _Variant_init_overload_set_, _Types...>; -template +template struct _Variant_init_helper {}; // failure case (has no member "type") template diff --git a/stl/inc/xloctime b/stl/inc/xloctime index 9534cdefddf..65de12ff9c8 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -800,7 +800,7 @@ public: _Elem _Percent = _Fmtfirst[-1]; if (_Specifier == 'E' || _Specifier == 'O' || _Specifier == 'Q' || _Specifier == '#') { - if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[E0Q#] as literal elements + if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[EOQ#] as literal elements *_Dest++ = _Percent; *_Dest++ = _Specifier; break; @@ -940,7 +940,7 @@ public: _Elem _Percent = _Fmtfirst[-1]; if (_Specifier == 'E' || _Specifier == 'O' || _Specifier == 'Q' || _Specifier == '#') { - if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[E0Q#] as literal elements + if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[EOQ#] as literal elements *_Dest++ = _Percent; *_Dest++ = _Raw; break; @@ -1089,7 +1089,7 @@ public: _Elem _Percent = _Fmtfirst[-1]; if (_Specifier == 'E' || _Specifier == 'O' || _Specifier == 'Q' || _Specifier == '#') { - if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[E0Q#] as literal elements + if (++_Fmtfirst == _Fmtlast) { // no specifier, copy %[EOQ#] as literal elements *_Dest++ = _Percent; *_Dest++ = _Raw; break; diff --git a/stl/inc/xtree b/stl/inc/xtree index d0237880371..783c05f15a9 100644 --- a/stl/inc/xtree +++ b/stl/inc/xtree @@ -433,10 +433,10 @@ public: using _Unchecked_const_iterator = _Tree_unchecked_const_iterator<_Tree_val>; using const_iterator = _Tree_const_iterator<_Tree_val>; - template + template struct _NODISCARD _Erase_tree_and_orphan_guard { _Tree_val* _Val_ptr; - _AllocNode& _Al; + _Alnode& _Al; _Nodeptr _New_root; _Erase_tree_and_orphan_guard& operator=(const _Erase_tree_and_orphan_guard&) = delete; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index c3ff774f67c..de4a5eb3957 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -986,7 +986,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect // P0298R3 std::byte #ifndef _HAS_STD_BYTE -#define _HAS_STD_BYTE _HAS_CXX17 +#define _HAS_STD_BYTE _HAS_CXX17 // TRANSITION, OS-14273702 #endif // !defined(_HAS_STD_BYTE) // P0302R1 Removing Allocator Support In std::function diff --git a/stl/src/primitives.hpp b/stl/src/primitives.hpp index d9572d4a00e..3cba95a9a74 100644 --- a/stl/src/primitives.hpp +++ b/stl/src/primitives.hpp @@ -8,7 +8,7 @@ #include -inline bool _Primitive_wait_for(const _Cnd_t cond, const _Mtx_t mtx, unsigned int timeout) noexcept { +inline bool _Primitive_wait_for(const _Cnd_t cond, const _Mtx_t mtx, const unsigned int timeout) noexcept { const auto pcv = reinterpret_cast(&cond->_Stl_cv._Win_cv); const auto psrw = reinterpret_cast(&mtx->_Critical_section._M_srw_lock); return SleepConditionVariableSRW(pcv, psrw, timeout, 0) != 0; diff --git a/stl/src/print.cpp b/stl/src/print.cpp index 89b4a8964e8..6fea3d36b26 100644 --- a/stl/src/print.cpp +++ b/stl/src/print.cpp @@ -273,7 +273,7 @@ extern "C" { _Allocated_string _Allocated_str{}; _Transcode_result _Transcoded_str{}; - while (true) { + for (;;) { _Curr_str_segment = _Get_next_utf8_string_segment(_Remaining_str, _Remaining_str_size); _Transcoded_str = _Transcode_utf8_string(_Allocated_str, _Curr_str_segment); diff --git a/tests/std/tests/P0088R3_variant_msvc/test.cpp b/tests/std/tests/P0088R3_variant_msvc/test.cpp index 81fadf0855d..32ac754222f 100644 --- a/tests/std/tests/P0088R3_variant_msvc/test.cpp +++ b/tests/std/tests/P0088R3_variant_msvc/test.cpp @@ -747,7 +747,7 @@ namespace msvc { #define CONSTEXPR20 constexpr #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv #define CONSTEXPR20 inline -#endif // ^^^ !_HAS_CXX20 ^^^ +#endif // ^^^ !_HAS_CXX20 ^^^ struct X { CONSTEXPR20 ~X() {} }; diff --git a/tests/std/tests/P0092R1_polishing_chrono/test.cpp b/tests/std/tests/P0092R1_polishing_chrono/test.cpp index 19b3b9abad0..6c912abfd50 100644 --- a/tests/std/tests/P0092R1_polishing_chrono/test.cpp +++ b/tests/std/tests/P0092R1_polishing_chrono/test.cpp @@ -166,7 +166,7 @@ namespace floating_point_conversions { // Make sure round() handles cases where taking half the divisor itself // truncates. using odd_divisor = duration>; -inline constexpr odd_divisor operator""_odd(unsigned long long val) { +constexpr odd_divisor operator""_odd(unsigned long long val) { return odd_divisor(val); } diff --git a/tests/std/tests/P0220R1_sample/test.cpp b/tests/std/tests/P0220R1_sample/test.cpp index 007b9d52800..137a16f824e 100644 --- a/tests/std/tests/P0220R1_sample/test.cpp +++ b/tests/std/tests/P0220R1_sample/test.cpp @@ -41,7 +41,7 @@ namespace { assert(sample(SI{cbegin(source)}, SI{cend(source)}, DI{begin(dest1)}, n, cpy).base() == cbegin(dest1) + result); assert(equal(cbegin(dest0), cbegin(dest0) + result, cbegin(dest1), cbegin(dest1) + result)); - if (is_base_of_v) { + if constexpr (is_base_of_v) { // Verify stability assert(is_sorted(cbegin(dest0), cbegin(dest0) + result)); } else { diff --git a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp index 745eb7b3315..39e42ff49a0 100644 --- a/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp +++ b/tests/std/tests/P0355R7_calendars_and_time_zones_dates/test.cpp @@ -880,7 +880,7 @@ constexpr void year_month_day_test() { assert(sys_days{ymd_max} == sys2 + days{254}); const year_month_day ymd_last = y / m / last; - sys2 += (ymd_last.day() - 1d); + sys2 += ymd_last.day() - 1d; assert(sys_days{ymd_last} == sys2); assert(year_month_day{sys2} == ymd_last); diff --git a/tests/std/tests/P2502R2_generator/test.cpp b/tests/std/tests/P2502R2_generator/test.cpp index a629f787c76..7c7b8f4b9d5 100644 --- a/tests/std/tests/P2502R2_generator/test.cpp +++ b/tests/std/tests/P2502R2_generator/test.cpp @@ -107,7 +107,7 @@ void test_one(generator g0, Ex&& expected) { // Some simple end-to-end tests, mostly from the Working Draft or P2502R2 generator ints(int start = 0) { - while (true) { + for (;;) { co_yield start++; } } diff --git a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp index 27ba7340b3f..293ee4520e9 100644 --- a/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp +++ b/tests/std/tests/VSO_0000000_vector_algorithms/test.cpp @@ -107,7 +107,9 @@ template ptrdiff_t last_known_good_count(FwdIt first, FwdIt last, T v) { ptrdiff_t result = 0; for (; first != last; ++first) { - result += (*first == v); + if (*first == v) { + ++result; + } } return result; } diff --git a/tests/utils/stl/util.py b/tests/utils/stl/util.py index b764ce494bd..74f0918a15c 100644 --- a/tests/utils/stl/util.py +++ b/tests/utils/stl/util.py @@ -177,15 +177,3 @@ def killProcessAndChildren(pid): psutilProc.kill() except psutil.NoSuchProcess: pass - - -def executeCommandVerbose(cmd, *args, **kwargs): - """ - Execute a command and print its output on failure. - """ - out, err, exitCode = executeCommand(cmd, *args, **kwargs) - if exitCode != 0: - report = makeReport(cmd, out, err, exitCode) - report += "\n\nFailed!" - sys.stderr.write('%s\n' % report) - return out, err, exitCode From 1f6e5b16ec02216665624c1e762f3732605cf2b4 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 13 Mar 2025 12:13:39 -0700 Subject: [PATCH 13/13] Make `unique_lock` and `shared_lock` use self-swap implementation of move assignment (#5337) Co-authored-by: Stephan T. Lavavej --- stl/inc/mutex | 13 +- stl/inc/shared_mutex | 9 +- tests/std/test.lst | 1 + .../env.lst | 4 + .../test.cpp | 111 ++++++++++++++++++ 5 files changed, 119 insertions(+), 19 deletions(-) create mode 100644 tests/std/tests/LWG4172_unique_lock_self_move_assignment/env.lst create mode 100644 tests/std/tests/LWG4172_unique_lock_self_move_assignment/test.cpp diff --git a/stl/inc/mutex b/stl/inc/mutex index 25cb1aed891..8cb450c59d7 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -170,17 +170,8 @@ public: _Other._Owns = false; } - unique_lock& operator=(unique_lock&& _Other) noexcept /* strengthened */ { - if (this != _STD addressof(_Other)) { - if (_Owns) { - _Pmtx->unlock(); - } - - _Pmtx = _Other._Pmtx; - _Owns = _Other._Owns; - _Other._Pmtx = nullptr; - _Other._Owns = false; - } + unique_lock& operator=(unique_lock&& _Other) noexcept { + unique_lock{_STD move(_Other)}.swap(*this); return *this; } diff --git a/stl/inc/shared_mutex b/stl/inc/shared_mutex index 3c67475e645..06ebb758e3f 100644 --- a/stl/inc/shared_mutex +++ b/stl/inc/shared_mutex @@ -251,14 +251,7 @@ public: } shared_lock& operator=(shared_lock&& _Right) noexcept { - if (_Owns) { - _Pmtx->unlock_shared(); - } - - _Pmtx = _Right._Pmtx; - _Owns = _Right._Owns; - _Right._Pmtx = nullptr; - _Right._Owns = false; + shared_lock{_STD move(_Right)}.swap(*this); return *this; } diff --git a/tests/std/test.lst b/tests/std/test.lst index 1c40a3294d8..484a11f3a14 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -269,6 +269,7 @@ tests\LWG3561_discard_block_engine_counter tests\LWG3610_iota_view_size_and_integer_class tests\LWG4084_iostream_uppercase_inf_nan tests\LWG4105_ranges_ends_with_and_integer_class +tests\LWG4172_unique_lock_self_move_assignment tests\P0009R18_mdspan_default_accessor tests\P0009R18_mdspan_extents tests\P0009R18_mdspan_extents_death diff --git a/tests/std/tests/LWG4172_unique_lock_self_move_assignment/env.lst b/tests/std/tests/LWG4172_unique_lock_self_move_assignment/env.lst new file mode 100644 index 00000000000..f141421b292 --- /dev/null +++ b/tests/std/tests/LWG4172_unique_lock_self_move_assignment/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\impure_matrix.lst diff --git a/tests/std/tests/LWG4172_unique_lock_self_move_assignment/test.cpp b/tests/std/tests/LWG4172_unique_lock_self_move_assignment/test.cpp new file mode 100644 index 00000000000..bf2aca86448 --- /dev/null +++ b/tests/std/tests/LWG4172_unique_lock_self_move_assignment/test.cpp @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +struct lockable_with_counters { + void lock() { + ++lock_count; + } + + void unlock() { + ++unlock_count; + } + + void lock_shared() { + ++shared_lock_count; + } + + void unlock_shared() { + ++shared_unlock_count; + } + + int lock_count = 0; + int unlock_count = 0; + int shared_lock_count = 0; + int shared_unlock_count = 0; +}; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wself-move" +#endif // __clang__ +#pragma warning(push) +#pragma warning(disable : 26800) // use a moved-from object +int main() { + lockable_with_counters lockable1; + lockable_with_counters lockable2; + + { + unique_lock lock_a(lockable1); + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 0); + + lock_a = move(lock_a); + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 0); + { + unique_lock lock_b(lockable2); + assert(lockable2.lock_count == 1); + assert(lockable2.unlock_count == 0); + + lock_a = move(lock_b); + + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 1); + assert(lockable2.lock_count == 1); + assert(lockable2.unlock_count == 0); + } + + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 1); + assert(lockable2.lock_count == 1); + assert(lockable2.unlock_count == 0); + } + + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 1); + assert(lockable2.lock_count == 1); + assert(lockable2.unlock_count == 1); + + { + shared_lock lock_a(lockable1); + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 0); + + lock_a = move(lock_a); + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 0); + { + shared_lock lock_b(lockable2); + assert(lockable2.shared_lock_count == 1); + assert(lockable2.shared_unlock_count == 0); + + lock_a = move(lock_b); + + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 1); + assert(lockable2.shared_lock_count == 1); + assert(lockable2.shared_unlock_count == 0); + } + + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 1); + assert(lockable2.shared_lock_count == 1); + assert(lockable2.shared_unlock_count == 0); + } + + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 1); + assert(lockable2.shared_lock_count == 1); + assert(lockable2.shared_unlock_count == 1); +} +#pragma warning(pop) +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__